From e8fca973ee1cf138624c9d7efb33d0cf4f0ed091 Mon Sep 17 00:00:00 2001 From: speckitor Date: Fri, 3 Jul 2026 23:27:22 +0700 Subject: [PATCH] initial commit --- raylib-6.0_linux_amd64/LICENSE | 16 + raylib-6.0_linux_amd64/include/raylib.h | 1743 +++++++ raylib-6.0_linux_amd64/include/raymath.h | 3139 +++++++++++++ raylib-6.0_linux_amd64/include/rlgl.h | 5421 ++++++++++++++++++++++ raylib-6.0_linux_amd64/lib/libraylib.a | Bin 0 -> 2869420 bytes 5 files changed, 10319 insertions(+) create mode 100644 raylib-6.0_linux_amd64/LICENSE create mode 100644 raylib-6.0_linux_amd64/include/raylib.h create mode 100644 raylib-6.0_linux_amd64/include/raymath.h create mode 100644 raylib-6.0_linux_amd64/include/rlgl.h create mode 100644 raylib-6.0_linux_amd64/lib/libraylib.a diff --git a/raylib-6.0_linux_amd64/LICENSE b/raylib-6.0_linux_amd64/LICENSE new file mode 100644 index 0000000..bc6f4b8 --- /dev/null +++ b/raylib-6.0_linux_amd64/LICENSE @@ -0,0 +1,16 @@ +Copyright (c) 2013-2026 Ramon Santamaria (@raysan5) + +This software is provided "as-is", without any express or implied warranty. In no event +will the authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, including commercial +applications, and to alter it and redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not claim that you + wrote the original software. If you use this software in a product, an acknowledgment + in the product documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be misrepresented + as being the original software. + + 3. This notice may not be removed or altered from any source distribution. diff --git a/raylib-6.0_linux_amd64/include/raylib.h b/raylib-6.0_linux_amd64/include/raylib.h new file mode 100644 index 0000000..bdca643 --- /dev/null +++ b/raylib-6.0_linux_amd64/include/raylib.h @@ -0,0 +1,1743 @@ +/********************************************************************************************** +* +* raylib v6.0 - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com) +* +* FEATURES: +* - NO external dependencies, all required libraries included with raylib +* - Multiplatform: Windows, Linux, macOS, FreeBSD, Web, Android, Raspberry Pi, DRM native... +* - Written in plain C code (C99) in PascalCase/camelCase notation +* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3, 4.3, ES2, ES3 - choose at compile) +* - Software renderer optional, for systems with no GPU: [rlsw] +* - Custom OpenGL abstraction layer (usable as standalone module): [rlgl] +* - Multiple Fonts formats supported (TTF, OTF, FNT, BDF, Sprite fonts) +* - Many texture formats supported, including compressed formats (DXT, ETC, ASTC) +* - Full 3d support for 3d Shapes, Models, Billboards, Heightmaps and more! +* - Flexible Materials system, supporting classic maps and PBR maps +* - Animated 3D models supported (skeletal bones animation) (IQM, M3D, GLTF) +* - Shaders support, including Model shaders and Postprocessing shaders +* - Powerful math module for Vector, Matrix and Quaternion operations: [raymath] +* - Audio loading and playing with streaming support (WAV, OGG, MP3, FLAC, QOA, XM, MOD) +* - VR stereo rendering with configurable HMD device parameters +* - Bindings to multiple programming languages available! +* +* NOTES: +* - One default Font is loaded on InitWindow()->LoadFontDefault() [core, text] +* - One default Texture2D is loaded on rlglInit(), 1x1 white pixel R8G8B8A8 [rlgl] (OpenGL 3.3 or ES2) +* - One default Shader is loaded on rlglInit()->rlLoadShaderDefault() [rlgl] (OpenGL 3.3 or ES2) +* - One default RenderBatch is loaded on rlglInit()->rlLoadRenderBatch() [rlgl] (OpenGL 3.3 or ES2) +* +* DEPENDENCIES: +* [rcore] Depends on the selected platform backend, check rcore.c header for details +* [rlgl] glad/glad_gles2 (David Herberth - github.com/Dav1dde/glad) for OpenGL extensions loading +* [raudio] miniaudio (David Reid - github.com/mackron/miniaudio) for audio device/context management +* +* OPTIONAL DEPENDENCIES (included): +* [rcore] sinfl (Micha Mettke) for DEFLATE decompression algorithm +* [rcore] sdefl (Micha Mettke) for DEFLATE compression algorithm +* [rcore] rprand (Ramon Santamaria) for pseudo-random numbers generation +* [rtextures] qoi (Dominic Szablewski - https://phoboslab.org) for QOI image management +* [rtextures] stb_image (Sean Barrett) for images loading (BMP, TGA, PNG, JPEG, HDR...) +* [rtextures] stb_image_write (Sean Barrett) for image writing (BMP, TGA, PNG, JPG) +* [rtextures] stb_image_resize2 (Sean Barrett) for image resizing algorithms +* [rtextures] stb_perlin (Sean Barrett) for Perlin Noise image generation +* [rtextures] rltexgpu (Ramon Santamaria) for GPU-compressed texture formats +* [rtext] stb_truetype (Sean Barrett) for ttf fonts loading +* [rtext] stb_rect_pack (Sean Barrett) for rectangles packing +* [rmodels] par_shapes (Philip Rideout) for parametric 3d shapes generation +* [rmodels] tinyobj_loader_c (Syoyo Fujita) for models loading (OBJ, MTL) +* [rmodels] cgltf (Johannes Kuhlmann) for models loading (glTF) +* [rmodels] m3d (bzt) for models loading (M3D, https://bztsrc.gitlab.io/model3d) +* [rmodels] vox_loader (Johann Nadalutti) for models loading (VOX) +* [raudio] dr_wav (David Reid) for WAV audio file loading +* [raudio] dr_flac (David Reid) for FLAC audio file loading +* [raudio] dr_mp3 (David Reid) for MP3 audio file loading +* [raudio] stb_vorbis (Sean Barrett) for OGG audio loading +* [raudio] jar_xm (Joshua Reisenauer) for XM audio module loading +* [raudio] jar_mod (Joshua Reisenauer) for MOD audio module loading +* [raudio] qoa (Dominic Szablewski - https://phoboslab.org) for QOA audio management +* +* +* LICENSE: zlib/libpng +* +* raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, +* BSD-like license that allows static linking with closed source software: +* +* Copyright (c) 2013-2026 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef RAYLIB_H +#define RAYLIB_H + +#include // Required for: va_list - Only used by TraceLogCallback + +#define RAYLIB_VERSION_MAJOR 6 +#define RAYLIB_VERSION_MINOR 0 +#define RAYLIB_VERSION_PATCH 0 +#define RAYLIB_VERSION "6.0" + +// Function specifiers in case library is build/used as a shared library +// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll +// NOTE: visibility("default") attribute makes symbols "visible" when compiled with -fvisibility=hidden +#if defined(_WIN32) + #if defined(__TINYC__) + #define __declspec(x) __attribute__((x)) + #endif + #if defined(BUILD_LIBTYPE_SHARED) + #define RLAPI __declspec(dllexport) // Building the library as a Win32 shared library (.dll) + #elif defined(USE_LIBTYPE_SHARED) + #define RLAPI __declspec(dllimport) // Using the library as a Win32 shared library (.dll) + #endif +#else + #if defined(BUILD_LIBTYPE_SHARED) + #define RLAPI __attribute__((visibility("default"))) // Building as a Unix shared library (.so/.dylib) + #endif +#endif + +#ifndef RLAPI + #define RLAPI // Functions defined as 'extern' by default (implicit specifiers) +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#ifndef PI + #define PI 3.14159265358979323846f +#endif +#ifndef DEG2RAD + #define DEG2RAD (PI/180.0f) +#endif +#ifndef RAD2DEG + #define RAD2DEG (180.0f/PI) +#endif + +// Allow custom memory allocators +// NOTE: Require recompiling raylib sources +#ifndef RL_MALLOC + #define RL_MALLOC(sz) malloc(sz) +#endif +#ifndef RL_CALLOC + #define RL_CALLOC(n,sz) calloc(n,sz) +#endif +#ifndef RL_REALLOC + #define RL_REALLOC(ptr,sz) realloc(ptr,sz) +#endif +#ifndef RL_FREE + #define RL_FREE(ptr) free(ptr) +#endif + +// NOTE: MSVC C++ compiler does not support compound literals (C99 feature) +// Plain structures in C++ (without constructors) can be initialized with { } +// This is called aggregate initialization (C++11 feature) +#if defined(__cplusplus) + #define CLITERAL(type) type +#else + #define CLITERAL(type) (type) +#endif + +// Some compilers (mostly macos clang) default to C++98, +// where aggregate initialization can't be used +// So, give a more clear error stating how to fix this +#if !defined(_MSC_VER) && (defined(__cplusplus) && __cplusplus < 201103L) + #error "C++11 or later is required. Add -std=c++11" +#endif + +// NOTE: Set some defines with some data types declared by raylib +// Other modules (raymath, rlgl) also require some of those types, so, +// to be able to use those other modules as standalone (not depending on raylib) +// this defines are useful for internal check and avoid type (re)definitions +#define RL_COLOR_TYPE +#define RL_RECTANGLE_TYPE +#define RL_VECTOR2_TYPE +#define RL_VECTOR3_TYPE +#define RL_VECTOR4_TYPE +#define RL_QUATERNION_TYPE +#define RL_MATRIX_TYPE + +// Some Basic Colors +// NOTE: Custom raylib color palette for amazing visuals on WHITE background +#define LIGHTGRAY CLITERAL(Color){ 200, 200, 200, 255 } // Light Gray +#define GRAY CLITERAL(Color){ 130, 130, 130, 255 } // Gray +#define DARKGRAY CLITERAL(Color){ 80, 80, 80, 255 } // Dark Gray +#define YELLOW CLITERAL(Color){ 253, 249, 0, 255 } // Yellow +#define GOLD CLITERAL(Color){ 255, 203, 0, 255 } // Gold +#define ORANGE CLITERAL(Color){ 255, 161, 0, 255 } // Orange +#define PINK CLITERAL(Color){ 255, 109, 194, 255 } // Pink +#define RED CLITERAL(Color){ 230, 41, 55, 255 } // Red +#define MAROON CLITERAL(Color){ 190, 33, 55, 255 } // Maroon +#define GREEN CLITERAL(Color){ 0, 228, 48, 255 } // Green +#define LIME CLITERAL(Color){ 0, 158, 47, 255 } // Lime +#define DARKGREEN CLITERAL(Color){ 0, 117, 44, 255 } // Dark Green +#define SKYBLUE CLITERAL(Color){ 102, 191, 255, 255 } // Sky Blue +#define BLUE CLITERAL(Color){ 0, 121, 241, 255 } // Blue +#define DARKBLUE CLITERAL(Color){ 0, 82, 172, 255 } // Dark Blue +#define PURPLE CLITERAL(Color){ 200, 122, 255, 255 } // Purple +#define VIOLET CLITERAL(Color){ 135, 60, 190, 255 } // Violet +#define DARKPURPLE CLITERAL(Color){ 112, 31, 126, 255 } // Dark Purple +#define BEIGE CLITERAL(Color){ 211, 176, 131, 255 } // Beige +#define BROWN CLITERAL(Color){ 127, 106, 79, 255 } // Brown +#define DARKBROWN CLITERAL(Color){ 76, 63, 47, 255 } // Dark Brown + +#define WHITE CLITERAL(Color){ 255, 255, 255, 255 } // White +#define BLACK CLITERAL(Color){ 0, 0, 0, 255 } // Black +#define BLANK CLITERAL(Color){ 0, 0, 0, 0 } // Blank (Transparent) +#define MAGENTA CLITERAL(Color){ 255, 0, 255, 255 } // Magenta +#define RAYWHITE CLITERAL(Color){ 245, 245, 245, 255 } // My own White (raylib logo) + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +// Boolean type +#if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800) + #include +#elif !defined(__cplusplus) && !defined(bool) + typedef enum bool { false = 0, true = !false } bool; + #define RL_BOOL_TYPE +#endif + +// Vector2, 2 components +typedef struct Vector2 { + float x; // Vector x component + float y; // Vector y component +} Vector2; + +// Vector3, 3 components +typedef struct Vector3 { + float x; // Vector x component + float y; // Vector y component + float z; // Vector z component +} Vector3; + +// Vector4, 4 components +typedef struct Vector4 { + float x; // Vector x component + float y; // Vector y component + float z; // Vector z component + float w; // Vector w component +} Vector4; + +// Quaternion, 4 components (Vector4 alias) +typedef Vector4 Quaternion; + +// Matrix, 4x4 components, column major, OpenGL style, right-handed +typedef struct Matrix { + float m0, m4, m8, m12; // Matrix first row (4 components) + float m1, m5, m9, m13; // Matrix second row (4 components) + float m2, m6, m10, m14; // Matrix third row (4 components) + float m3, m7, m11, m15; // Matrix fourth row (4 components) +} Matrix; + +// Color, 4 components, R8G8B8A8 (32bit) +typedef struct Color { + unsigned char r; // Color red value + unsigned char g; // Color green value + unsigned char b; // Color blue value + unsigned char a; // Color alpha value +} Color; + +// Rectangle, 4 components +typedef struct Rectangle { + float x; // Rectangle top-left corner position x + float y; // Rectangle top-left corner position y + float width; // Rectangle width + float height; // Rectangle height +} Rectangle; + +// Image, pixel data stored in CPU memory (RAM) +typedef struct Image { + void *data; // Image raw data + int width; // Image base width + int height; // Image base height + int mipmaps; // Mipmap levels, 1 by default + int format; // Data format (PixelFormat type) +} Image; + +// Texture, tex data stored in GPU memory (VRAM) +typedef struct Texture { + unsigned int id; // OpenGL texture id + int width; // Texture base width + int height; // Texture base height + int mipmaps; // Mipmap levels, 1 by default + int format; // Data format (PixelFormat type) +} Texture; + +// Texture2D, same as Texture +typedef Texture Texture2D; + +// TextureCubemap, same as Texture +typedef Texture TextureCubemap; + +// RenderTexture, fbo for texture rendering +typedef struct RenderTexture { + unsigned int id; // OpenGL framebuffer object id + Texture texture; // Color buffer attachment texture + Texture depth; // Depth buffer attachment texture +} RenderTexture; + +// RenderTexture2D, same as RenderTexture +typedef RenderTexture RenderTexture2D; + +// NPatchInfo, n-patch layout info +typedef struct NPatchInfo { + Rectangle source; // Texture source rectangle + int left; // Left border offset + int top; // Top border offset + int right; // Right border offset + int bottom; // Bottom border offset + int layout; // Layout of the n-patch: 3x3, 1x3 or 3x1 +} NPatchInfo; + +// GlyphInfo, font characters glyphs info +typedef struct GlyphInfo { + int value; // Character value (Unicode) + int offsetX; // Character offset X when drawing + int offsetY; // Character offset Y when drawing + int advanceX; // Character advance position X + Image image; // Character image data +} GlyphInfo; + +// Font, font texture and GlyphInfo array data +typedef struct Font { + int baseSize; // Base size (default chars height) + int glyphCount; // Number of glyph characters + int glyphPadding; // Padding around the glyph characters + Texture2D texture; // Texture atlas containing the glyphs + Rectangle *recs; // Rectangles in texture for the glyphs + GlyphInfo *glyphs; // Glyphs info data +} Font; + +// Camera, defines position/orientation in 3d space +typedef struct Camera3D { + Vector3 position; // Camera position + Vector3 target; // Camera target it looks-at + Vector3 up; // Camera up vector (rotation over its axis) + float fovy; // Camera field-of-view aperture in Y (degrees) in perspective, used as near plane height in world units in orthographic + int projection; // Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC +} Camera3D; + +typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D + +// Camera2D, defines position/orientation in 2d space +typedef struct Camera2D { + Vector2 offset; // Camera offset (screen space offset from window origin) + Vector2 target; // Camera target (world space target point that is mapped to screen space offset) + float rotation; // Camera rotation in degrees (pivots around target) + float zoom; // Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale +} Camera2D; + +// Mesh, vertex data and vao/vbo +typedef struct Mesh { + int vertexCount; // Number of vertices stored in arrays + int triangleCount; // Number of triangles stored (indexed or not) + + // Vertex attributes data + float *vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0) + float *texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) + float *texcoords2; // Vertex texture second coordinates (UV - 2 components per vertex) (shader-location = 5) + float *normals; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2) + float *tangents; // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4) + unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) + unsigned short *indices; // Vertex indices (in case vertex data comes indexed) + + // Skin data for animation + int boneCount; // Number of bones (MAX: 256 bones) + unsigned char *boneIndices; // Vertex bone indices, up to 4 bones influence by vertex (skinning) (shader-location = 6) + float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7) + + // Runtime animation vertex data (CPU skinning) + // NOTE: In case of GPU skinning, not used, pointers are NULL + float *animVertices; // Animated vertex positions (after bones transformations) + float *animNormals; // Animated normals (after bones transformations) + + // OpenGL identifiers + unsigned int vaoId; // OpenGL Vertex Array Object id + unsigned int *vboId; // OpenGL Vertex Buffer Objects id (default vertex data) +} Mesh; + +// Shader +typedef struct Shader { + unsigned int id; // Shader program id + int *locs; // Shader locations array (RL_MAX_SHADER_LOCATIONS) +} Shader; + +// MaterialMap +typedef struct MaterialMap { + Texture2D texture; // Material map texture + Color color; // Material map color + float value; // Material map value +} MaterialMap; + +// Material, includes shader and maps +typedef struct Material { + Shader shader; // Material shader + MaterialMap *maps; // Material maps array (MAX_MATERIAL_MAPS) + float params[4]; // Material generic parameters (if required) +} Material; + +// Transform, vertex transformation data +typedef struct Transform { + Vector3 translation; // Translation + Quaternion rotation; // Rotation + Vector3 scale; // Scale +} Transform; + +// Anim pose, an array of Transform[] +typedef Transform *ModelAnimPose; + +// Bone, skeletal animation bone +typedef struct BoneInfo { + char name[32]; // Bone name + int parent; // Bone parent +} BoneInfo; + +// Skeleton, animation bones hierarchy +typedef struct ModelSkeleton { + int boneCount; // Number of bones + BoneInfo *bones; // Bones information (skeleton) + ModelAnimPose bindPose; // Bones base transformation (Transform[]) +} ModelSkeleton; + +// Model, meshes, materials and animation data +typedef struct Model { + Matrix transform; // Local transform matrix + + int meshCount; // Number of meshes + int materialCount; // Number of materials + Mesh *meshes; // Meshes array + Material *materials; // Materials array + int *meshMaterial; // Mesh material number + + // Animation data + ModelSkeleton skeleton; // Skeleton for animation + + // Runtime animation data (CPU/GPU skinning) + ModelAnimPose currentPose; // Current animation pose (Transform[]) + Matrix *boneMatrices; // Bones animated transformation matrices +} Model; + +// ModelAnimation, contains a full animation sequence +typedef struct ModelAnimation { + char name[32]; // Animation name + + int boneCount; // Number of bones (per pose) + int keyframeCount; // Number of animation key frames + ModelAnimPose *keyframePoses; // Animation sequence keyframe poses [keyframe][pose] +} ModelAnimation; + +// Ray, ray for raycasting +typedef struct Ray { + Vector3 position; // Ray position (origin) + Vector3 direction; // Ray direction (normalized) +} Ray; + +// RayCollision, ray hit information +typedef struct RayCollision { + bool hit; // Did the ray hit something? + float distance; // Distance to the nearest hit + Vector3 point; // Point of the nearest hit + Vector3 normal; // Surface normal of hit +} RayCollision; + +// BoundingBox +typedef struct BoundingBox { + Vector3 min; // Minimum vertex box-corner + Vector3 max; // Maximum vertex box-corner +} BoundingBox; + +// Wave, audio wave data +typedef struct Wave { + unsigned int frameCount; // Total number of frames (considering channels) + unsigned int sampleRate; // Frequency (samples per second) + unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + unsigned int channels; // Number of channels (1-mono, 2-stereo, ...) + void *data; // Buffer data pointer +} Wave; + +// Opaque structs declaration +// NOTE: Actual structs are defined internally in raudio module +typedef struct rAudioBuffer rAudioBuffer; +typedef struct rAudioProcessor rAudioProcessor; + +// AudioStream, custom audio stream +typedef struct AudioStream { + rAudioBuffer *buffer; // Pointer to internal data used by the audio system + rAudioProcessor *processor; // Pointer to internal data processor, useful for audio effects + + unsigned int sampleRate; // Frequency (samples per second) + unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + unsigned int channels; // Number of channels (1-mono, 2-stereo, ...) +} AudioStream; + +// Sound +typedef struct Sound { + AudioStream stream; // Audio stream + unsigned int frameCount; // Total number of frames (considering channels) +} Sound; + +// Music, audio stream, anything longer than ~10 seconds should be streamed +typedef struct Music { + AudioStream stream; // Audio stream + unsigned int frameCount; // Total number of frames (considering channels) + bool looping; // Music looping enable + + int ctxType; // Type of music context (audio filetype) + void *ctxData; // Audio context data, depends on type +} Music; + +// VrDeviceInfo, Head-Mounted-Display device parameters +typedef struct VrDeviceInfo { + int hResolution; // Horizontal resolution in pixels + int vResolution; // Vertical resolution in pixels + float hScreenSize; // Horizontal size in meters + float vScreenSize; // Vertical size in meters + float eyeToScreenDistance; // Distance between eye and display in meters + float lensSeparationDistance; // Lens separation distance in meters + float interpupillaryDistance; // IPD (distance between pupils) in meters + float lensDistortionValues[4]; // Lens distortion constant parameters + float chromaAbCorrection[4]; // Chromatic aberration correction parameters +} VrDeviceInfo; + +// VrStereoConfig, VR stereo rendering configuration for simulator +typedef struct VrStereoConfig { + Matrix projection[2]; // VR projection matrices (per eye) + Matrix viewOffset[2]; // VR view offset matrices (per eye) + float leftLensCenter[2]; // VR left lens center + float rightLensCenter[2]; // VR right lens center + float leftScreenCenter[2]; // VR left screen center + float rightScreenCenter[2]; // VR right screen center + float scale[2]; // VR distortion scale + float scaleIn[2]; // VR distortion scale in +} VrStereoConfig; + +// File path list +typedef struct FilePathList { + unsigned int count; // Filepaths entries count + char **paths; // Filepaths entries +} FilePathList; + +// Automation event +typedef struct AutomationEvent { + unsigned int frame; // Event frame + unsigned int type; // Event type (AutomationEventType) + int params[4]; // Event parameters (if required) +} AutomationEvent; + +// Automation event list +typedef struct AutomationEventList { + unsigned int capacity; // Events max entries (MAX_AUTOMATION_EVENTS) + unsigned int count; // Events entries count + AutomationEvent *events; // Events entries +} AutomationEventList; + +//---------------------------------------------------------------------------------- +// 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 +typedef enum { + FLAG_VSYNC_HINT = 0x00000040, // Set to try enabling V-Sync on GPU + FLAG_FULLSCREEN_MODE = 0x00000002, // Set to run program in fullscreen + FLAG_WINDOW_RESIZABLE = 0x00000004, // Set to allow resizable window + FLAG_WINDOW_UNDECORATED = 0x00000008, // Set to disable window decoration (frame and buttons) + FLAG_WINDOW_HIDDEN = 0x00000080, // Set to hide window + FLAG_WINDOW_MINIMIZED = 0x00000200, // Set to minimize window (iconify) + FLAG_WINDOW_MAXIMIZED = 0x00000400, // Set to maximize window (expanded to monitor) + FLAG_WINDOW_UNFOCUSED = 0x00000800, // Set to window non focused + FLAG_WINDOW_TOPMOST = 0x00001000, // Set to window always on top + FLAG_WINDOW_ALWAYS_RUN = 0x00000100, // Set to allow windows running while minimized + FLAG_WINDOW_TRANSPARENT = 0x00000010, // Set to allow transparent framebuffer + FLAG_WINDOW_HIGHDPI = 0x00002000, // Set to support HighDPI + FLAG_WINDOW_MOUSE_PASSTHROUGH = 0x00004000, // Set to support mouse passthrough, only supported when FLAG_WINDOW_UNDECORATED + FLAG_BORDERLESS_WINDOWED_MODE = 0x00008000, // Set to run program in borderless windowed mode + FLAG_MSAA_4X_HINT = 0x00000020, // Set to try enabling MSAA 4X + FLAG_INTERLACED_HINT = 0x00010000 // Set to try enabling interlaced video format (for V3D) +} ConfigFlags; + +// Trace log level +// NOTE: Organized by priority level +typedef enum { + LOG_ALL = 0, // Display all logs + LOG_TRACE, // Trace logging, intended for internal use only + LOG_DEBUG, // Debug logging, used for internal debugging, it should be disabled on release builds + LOG_INFO, // Info logging, used for program execution info + LOG_WARNING, // Warning logging, used on recoverable failures + LOG_ERROR, // Error logging, used on unrecoverable failures + LOG_FATAL, // Fatal logging, used to abort program: exit(EXIT_FAILURE) + LOG_NONE // Disable logging +} TraceLogLevel; + +// Keyboard keys (US keyboard layout) +// NOTE: Use GetKeyPressed() to allow redefining required keys for alternative layouts +typedef enum { + KEY_NULL = 0, // Key: NULL, used for no key pressed + // Alphanumeric keys + KEY_APOSTROPHE = 39, // Key: ' + KEY_COMMA = 44, // Key: , + KEY_MINUS = 45, // Key: - + KEY_PERIOD = 46, // Key: . + KEY_SLASH = 47, // Key: / + KEY_ZERO = 48, // Key: 0 + KEY_ONE = 49, // Key: 1 + KEY_TWO = 50, // Key: 2 + KEY_THREE = 51, // Key: 3 + KEY_FOUR = 52, // Key: 4 + KEY_FIVE = 53, // Key: 5 + KEY_SIX = 54, // Key: 6 + KEY_SEVEN = 55, // Key: 7 + KEY_EIGHT = 56, // Key: 8 + KEY_NINE = 57, // Key: 9 + KEY_SEMICOLON = 59, // Key: ; + KEY_EQUAL = 61, // Key: = + KEY_A = 65, // Key: A | a + KEY_B = 66, // Key: B | b + KEY_C = 67, // Key: C | c + KEY_D = 68, // Key: D | d + KEY_E = 69, // Key: E | e + KEY_F = 70, // Key: F | f + KEY_G = 71, // Key: G | g + KEY_H = 72, // Key: H | h + KEY_I = 73, // Key: I | i + KEY_J = 74, // Key: J | j + KEY_K = 75, // Key: K | k + KEY_L = 76, // Key: L | l + KEY_M = 77, // Key: M | m + KEY_N = 78, // Key: N | n + KEY_O = 79, // Key: O | o + KEY_P = 80, // Key: P | p + KEY_Q = 81, // Key: Q | q + KEY_R = 82, // Key: R | r + KEY_S = 83, // Key: S | s + KEY_T = 84, // Key: T | t + KEY_U = 85, // Key: U | u + KEY_V = 86, // Key: V | v + KEY_W = 87, // Key: W | w + KEY_X = 88, // Key: X | x + KEY_Y = 89, // Key: Y | y + KEY_Z = 90, // Key: Z | z + KEY_LEFT_BRACKET = 91, // Key: [ + KEY_BACKSLASH = 92, // Key: '\' + KEY_RIGHT_BRACKET = 93, // Key: ] + KEY_GRAVE = 96, // Key: ` + // Function keys + KEY_SPACE = 32, // Key: Space + KEY_ESCAPE = 256, // Key: Esc + KEY_ENTER = 257, // Key: Enter + KEY_TAB = 258, // Key: Tab + KEY_BACKSPACE = 259, // Key: Backspace + KEY_INSERT = 260, // Key: Ins + KEY_DELETE = 261, // Key: Del + KEY_RIGHT = 262, // Key: Cursor right + KEY_LEFT = 263, // Key: Cursor left + KEY_DOWN = 264, // Key: Cursor down + KEY_UP = 265, // Key: Cursor up + KEY_PAGE_UP = 266, // Key: Page up + KEY_PAGE_DOWN = 267, // Key: Page down + KEY_HOME = 268, // Key: Home + KEY_END = 269, // Key: End + KEY_CAPS_LOCK = 280, // Key: Caps lock + KEY_SCROLL_LOCK = 281, // Key: Scroll down + KEY_NUM_LOCK = 282, // Key: Num lock + KEY_PRINT_SCREEN = 283, // Key: Print screen + KEY_PAUSE = 284, // Key: Pause + KEY_F1 = 290, // Key: F1 + KEY_F2 = 291, // Key: F2 + KEY_F3 = 292, // Key: F3 + KEY_F4 = 293, // Key: F4 + KEY_F5 = 294, // Key: F5 + KEY_F6 = 295, // Key: F6 + KEY_F7 = 296, // Key: F7 + KEY_F8 = 297, // Key: F8 + KEY_F9 = 298, // Key: F9 + KEY_F10 = 299, // Key: F10 + KEY_F11 = 300, // Key: F11 + KEY_F12 = 301, // Key: F12 + KEY_LEFT_SHIFT = 340, // Key: Shift left + KEY_LEFT_CONTROL = 341, // Key: Control left + KEY_LEFT_ALT = 342, // Key: Alt left + KEY_LEFT_SUPER = 343, // Key: Super left + KEY_RIGHT_SHIFT = 344, // Key: Shift right + KEY_RIGHT_CONTROL = 345, // Key: Control right + KEY_RIGHT_ALT = 346, // Key: Alt right + KEY_RIGHT_SUPER = 347, // Key: Super right + KEY_KB_MENU = 348, // Key: KB menu + // Keypad keys + KEY_KP_0 = 320, // Key: Keypad 0 + KEY_KP_1 = 321, // Key: Keypad 1 + KEY_KP_2 = 322, // Key: Keypad 2 + KEY_KP_3 = 323, // Key: Keypad 3 + KEY_KP_4 = 324, // Key: Keypad 4 + KEY_KP_5 = 325, // Key: Keypad 5 + KEY_KP_6 = 326, // Key: Keypad 6 + KEY_KP_7 = 327, // Key: Keypad 7 + KEY_KP_8 = 328, // Key: Keypad 8 + KEY_KP_9 = 329, // Key: Keypad 9 + KEY_KP_DECIMAL = 330, // Key: Keypad . + KEY_KP_DIVIDE = 331, // Key: Keypad / + KEY_KP_MULTIPLY = 332, // Key: Keypad * + KEY_KP_SUBTRACT = 333, // Key: Keypad - + KEY_KP_ADD = 334, // Key: Keypad + + KEY_KP_ENTER = 335, // Key: Keypad Enter + KEY_KP_EQUAL = 336, // Key: Keypad = + // Android key buttons + KEY_BACK = 4, // Key: Android back button + KEY_MENU = 5, // Key: Android menu button + KEY_VOLUME_UP = 24, // Key: Android volume up button + KEY_VOLUME_DOWN = 25 // Key: Android volume down button +} KeyboardKey; + +// Add backwards compatibility support for deprecated names +#define MOUSE_LEFT_BUTTON MOUSE_BUTTON_LEFT +#define MOUSE_RIGHT_BUTTON MOUSE_BUTTON_RIGHT +#define MOUSE_MIDDLE_BUTTON MOUSE_BUTTON_MIDDLE + +// Mouse buttons +typedef enum { + MOUSE_BUTTON_LEFT = 0, // Mouse button left + MOUSE_BUTTON_RIGHT = 1, // Mouse button right + MOUSE_BUTTON_MIDDLE = 2, // Mouse button middle (pressed wheel) + MOUSE_BUTTON_SIDE = 3, // Mouse button side (advanced mouse device) + MOUSE_BUTTON_EXTRA = 4, // Mouse button extra (advanced mouse device) + MOUSE_BUTTON_FORWARD = 5, // Mouse button forward (advanced mouse device) + MOUSE_BUTTON_BACK = 6, // Mouse button back (advanced mouse device) +} MouseButton; + +// Mouse cursor +typedef enum { + MOUSE_CURSOR_DEFAULT = 0, // Default pointer shape + MOUSE_CURSOR_ARROW = 1, // Arrow shape + MOUSE_CURSOR_IBEAM = 2, // Text writing cursor shape + MOUSE_CURSOR_CROSSHAIR = 3, // Cross shape + MOUSE_CURSOR_POINTING_HAND = 4, // Pointing hand cursor + MOUSE_CURSOR_RESIZE_EW = 5, // Horizontal resize/move arrow shape + MOUSE_CURSOR_RESIZE_NS = 6, // Vertical resize/move arrow shape + MOUSE_CURSOR_RESIZE_NWSE = 7, // Top-left to bottom-right diagonal resize/move arrow shape + MOUSE_CURSOR_RESIZE_NESW = 8, // The top-right to bottom-left diagonal resize/move arrow shape + MOUSE_CURSOR_RESIZE_ALL = 9, // The omnidirectional resize/move cursor shape + MOUSE_CURSOR_NOT_ALLOWED = 10 // The operation-not-allowed shape +} MouseCursor; + +// Gamepad buttons +typedef enum { + GAMEPAD_BUTTON_UNKNOWN = 0, // Unknown button, for error checking + GAMEPAD_BUTTON_LEFT_FACE_UP, // Gamepad left DPAD up button + GAMEPAD_BUTTON_LEFT_FACE_RIGHT, // Gamepad left DPAD right button + GAMEPAD_BUTTON_LEFT_FACE_DOWN, // Gamepad left DPAD down button + GAMEPAD_BUTTON_LEFT_FACE_LEFT, // Gamepad left DPAD left button + GAMEPAD_BUTTON_RIGHT_FACE_UP, // Gamepad right button up (i.e. PS3: Triangle, Xbox: Y) + GAMEPAD_BUTTON_RIGHT_FACE_RIGHT, // Gamepad right button right (i.e. PS3: Circle, Xbox: B) + GAMEPAD_BUTTON_RIGHT_FACE_DOWN, // Gamepad right button down (i.e. PS3: Cross, Xbox: A) + GAMEPAD_BUTTON_RIGHT_FACE_LEFT, // Gamepad right button left (i.e. PS3: Square, Xbox: X) + GAMEPAD_BUTTON_LEFT_TRIGGER_1, // Gamepad top/back trigger left (first), it could be a trailing button + GAMEPAD_BUTTON_LEFT_TRIGGER_2, // Gamepad top/back trigger left (second), it could be a trailing button + GAMEPAD_BUTTON_RIGHT_TRIGGER_1, // Gamepad top/back trigger right (first), it could be a trailing button + GAMEPAD_BUTTON_RIGHT_TRIGGER_2, // Gamepad top/back trigger right (second), it could be a trailing button + GAMEPAD_BUTTON_MIDDLE_LEFT, // Gamepad center buttons, left one (i.e. PS3: Select) + GAMEPAD_BUTTON_MIDDLE, // Gamepad center buttons, middle one (i.e. PS3: PS, Xbox: XBOX) + GAMEPAD_BUTTON_MIDDLE_RIGHT, // Gamepad center buttons, right one (i.e. PS3: Start) + GAMEPAD_BUTTON_LEFT_THUMB, // Gamepad joystick pressed button left + GAMEPAD_BUTTON_RIGHT_THUMB // Gamepad joystick pressed button right +} GamepadButton; + +// Gamepad axes +typedef enum { + GAMEPAD_AXIS_LEFT_X = 0, // Gamepad left stick X axis + GAMEPAD_AXIS_LEFT_Y = 1, // Gamepad left stick Y axis + GAMEPAD_AXIS_RIGHT_X = 2, // Gamepad right stick X axis + GAMEPAD_AXIS_RIGHT_Y = 3, // Gamepad right stick Y axis + GAMEPAD_AXIS_LEFT_TRIGGER = 4, // Gamepad back trigger left, pressure level: [1..-1] + GAMEPAD_AXIS_RIGHT_TRIGGER = 5 // Gamepad back trigger right, pressure level: [1..-1] +} GamepadAxis; + +// Material map index +typedef enum { + MATERIAL_MAP_ALBEDO = 0, // Albedo material (same as: MATERIAL_MAP_DIFFUSE) + MATERIAL_MAP_METALNESS, // Metalness material (same as: MATERIAL_MAP_SPECULAR) + MATERIAL_MAP_NORMAL, // Normal material + MATERIAL_MAP_ROUGHNESS, // Roughness material + MATERIAL_MAP_OCCLUSION, // Ambient occlusion material + MATERIAL_MAP_EMISSION, // Emission material + MATERIAL_MAP_HEIGHT, // Heightmap material + MATERIAL_MAP_CUBEMAP, // Cubemap material (NOTE: Uses GL_TEXTURE_CUBE_MAP) + MATERIAL_MAP_IRRADIANCE, // Irradiance material (NOTE: Uses GL_TEXTURE_CUBE_MAP) + MATERIAL_MAP_PREFILTER, // Prefilter material (NOTE: Uses GL_TEXTURE_CUBE_MAP) + MATERIAL_MAP_BRDF // Brdf material +} MaterialMapIndex; + +#define MATERIAL_MAP_DIFFUSE MATERIAL_MAP_ALBEDO +#define MATERIAL_MAP_SPECULAR MATERIAL_MAP_METALNESS + +// Shader location index +// NOTE: Some locations are tried to be set automatically on shader loading, +// but only if default attributes/uniforms names are found, check config.h for names +typedef enum { + SHADER_LOC_VERTEX_POSITION = 0, // Shader location: vertex attribute: position + SHADER_LOC_VERTEX_TEXCOORD01, // Shader location: vertex attribute: texcoord01 + SHADER_LOC_VERTEX_TEXCOORD02, // Shader location: vertex attribute: texcoord02 + SHADER_LOC_VERTEX_NORMAL, // Shader location: vertex attribute: normal + SHADER_LOC_VERTEX_TANGENT, // Shader location: vertex attribute: tangent + SHADER_LOC_VERTEX_COLOR, // Shader location: vertex attribute: color + SHADER_LOC_MATRIX_MVP, // Shader location: matrix uniform: model-view-projection + SHADER_LOC_MATRIX_VIEW, // Shader location: matrix uniform: view (camera transform) + SHADER_LOC_MATRIX_PROJECTION, // Shader location: matrix uniform: projection + SHADER_LOC_MATRIX_MODEL, // Shader location: matrix uniform: model (transform) + SHADER_LOC_MATRIX_NORMAL, // Shader location: matrix uniform: normal + SHADER_LOC_VECTOR_VIEW, // Shader location: vector uniform: view + SHADER_LOC_COLOR_DIFFUSE, // Shader location: vector uniform: diffuse color + SHADER_LOC_COLOR_SPECULAR, // Shader location: vector uniform: specular color + SHADER_LOC_COLOR_AMBIENT, // Shader location: vector uniform: ambient color + SHADER_LOC_MAP_ALBEDO, // Shader location: sampler2d texture: albedo (same as: SHADER_LOC_MAP_DIFFUSE) + SHADER_LOC_MAP_METALNESS, // Shader location: sampler2d texture: metalness (same as: SHADER_LOC_MAP_SPECULAR) + SHADER_LOC_MAP_NORMAL, // Shader location: sampler2d texture: normal + SHADER_LOC_MAP_ROUGHNESS, // Shader location: sampler2d texture: roughness + SHADER_LOC_MAP_OCCLUSION, // Shader location: sampler2d texture: occlusion + SHADER_LOC_MAP_EMISSION, // Shader location: sampler2d texture: emission + SHADER_LOC_MAP_HEIGHT, // Shader location: sampler2d texture: heightmap + SHADER_LOC_MAP_CUBEMAP, // Shader location: samplerCube texture: cubemap + SHADER_LOC_MAP_IRRADIANCE, // Shader location: samplerCube texture: irradiance + SHADER_LOC_MAP_PREFILTER, // Shader location: samplerCube texture: prefilter + SHADER_LOC_MAP_BRDF, // Shader location: sampler2d texture: brdf + SHADER_LOC_VERTEX_BONEIDS, // Shader location: vertex attribute: bone indices + SHADER_LOC_VERTEX_BONEWEIGHTS, // Shader location: vertex attribute: bone weights + SHADER_LOC_MATRIX_BONETRANSFORMS, // Shader location: matrix attribute: bone transforms (animation) + SHADER_LOC_VERTEX_INSTANCETRANSFORM // Shader location: vertex attribute: instance transforms +} ShaderLocationIndex; + +#define SHADER_LOC_MAP_DIFFUSE SHADER_LOC_MAP_ALBEDO +#define SHADER_LOC_MAP_SPECULAR SHADER_LOC_MAP_METALNESS + +// Shader uniform data type +typedef enum { + SHADER_UNIFORM_FLOAT = 0, // Shader uniform type: float + SHADER_UNIFORM_VEC2, // Shader uniform type: vec2 (2 float) + SHADER_UNIFORM_VEC3, // Shader uniform type: vec3 (3 float) + SHADER_UNIFORM_VEC4, // Shader uniform type: vec4 (4 float) + SHADER_UNIFORM_INT, // Shader uniform type: int + SHADER_UNIFORM_IVEC2, // Shader uniform type: ivec2 (2 int) + SHADER_UNIFORM_IVEC3, // Shader uniform type: ivec3 (3 int) + SHADER_UNIFORM_IVEC4, // Shader uniform type: ivec4 (4 int) + SHADER_UNIFORM_UINT, // Shader uniform type: unsigned int + SHADER_UNIFORM_UIVEC2, // Shader uniform type: uivec2 (2 unsigned int) + SHADER_UNIFORM_UIVEC3, // Shader uniform type: uivec3 (3 unsigned int) + SHADER_UNIFORM_UIVEC4, // Shader uniform type: uivec4 (4 unsigned int) + SHADER_UNIFORM_SAMPLER2D // Shader uniform type: sampler2d +} ShaderUniformDataType; + +// Shader attribute data types +typedef enum { + SHADER_ATTRIB_FLOAT = 0, // Shader attribute type: float + SHADER_ATTRIB_VEC2, // Shader attribute type: vec2 (2 float) + SHADER_ATTRIB_VEC3, // Shader attribute type: vec3 (3 float) + SHADER_ATTRIB_VEC4 // Shader attribute type: vec4 (4 float) +} ShaderAttributeDataType; + +// Pixel formats +// NOTE: Support depends on OpenGL version and platform +typedef enum { + PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) + PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) + PIXELFORMAT_UNCOMPRESSED_R5G6B5, // 16 bpp + PIXELFORMAT_UNCOMPRESSED_R8G8B8, // 24 bpp + PIXELFORMAT_UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) + PIXELFORMAT_UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) + PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, // 32 bpp + PIXELFORMAT_UNCOMPRESSED_R32, // 32 bpp (1 channel - float) + PIXELFORMAT_UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) + PIXELFORMAT_UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) + PIXELFORMAT_UNCOMPRESSED_R16, // 16 bpp (1 channel - half float) + PIXELFORMAT_UNCOMPRESSED_R16G16B16, // 16*3 bpp (3 channels - half float) + PIXELFORMAT_UNCOMPRESSED_R16G16B16A16, // 16*4 bpp (4 channels - half float) + PIXELFORMAT_COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) + PIXELFORMAT_COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) + PIXELFORMAT_COMPRESSED_DXT3_RGBA, // 8 bpp + PIXELFORMAT_COMPRESSED_DXT5_RGBA, // 8 bpp + PIXELFORMAT_COMPRESSED_ETC1_RGB, // 4 bpp + PIXELFORMAT_COMPRESSED_ETC2_RGB, // 4 bpp + PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA, // 8 bpp + PIXELFORMAT_COMPRESSED_PVRT_RGB, // 4 bpp + PIXELFORMAT_COMPRESSED_PVRT_RGBA, // 4 bpp + PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA, // 8 bpp + PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA // 2 bpp +} PixelFormat; + +// Texture parameters: filter mode +// NOTE 1: Filtering considers mipmaps if available in the texture +// NOTE 2: Filter is accordingly set for minification and magnification +typedef enum { + TEXTURE_FILTER_POINT = 0, // No filter, pixel approximation + TEXTURE_FILTER_BILINEAR, // Linear filtering + TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) + TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x + TEXTURE_FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x + TEXTURE_FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x +} TextureFilter; + +// Texture parameters: wrap mode +typedef enum { + TEXTURE_WRAP_REPEAT = 0, // Repeats texture in tiled mode + TEXTURE_WRAP_CLAMP, // Clamps texture to edge pixel in tiled mode + TEXTURE_WRAP_MIRROR_REPEAT, // Mirrors and repeats the texture in tiled mode + TEXTURE_WRAP_MIRROR_CLAMP // Mirrors and clamps to border the texture in tiled mode +} TextureWrap; + +// Cubemap layouts +typedef enum { + CUBEMAP_LAYOUT_AUTO_DETECT = 0, // Automatically detect layout type + CUBEMAP_LAYOUT_LINE_VERTICAL, // Layout is defined by a vertical line with faces + CUBEMAP_LAYOUT_LINE_HORIZONTAL, // Layout is defined by a horizontal line with faces + CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR, // Layout is defined by a 3x4 cross with cubemap faces + CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE // Layout is defined by a 4x3 cross with cubemap faces +} CubemapLayout; + +// Font type, defines generation method +typedef enum { + FONT_DEFAULT = 0, // Default font generation, anti-aliased + FONT_BITMAP, // Bitmap font generation, no anti-aliasing + FONT_SDF // SDF font generation, requires external shader +} FontType; + +// Color blending modes (pre-defined) +typedef enum { + BLEND_ALPHA = 0, // Blend textures considering alpha (default) + BLEND_ADDITIVE, // Blend textures adding colors + BLEND_MULTIPLIED, // Blend textures multiplying colors + BLEND_ADD_COLORS, // Blend textures adding colors (alternative) + BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative) + BLEND_ALPHA_PREMULTIPLY, // Blend premultiplied textures considering alpha + BLEND_CUSTOM, // Blend textures using custom src/dst factors (use rlSetBlendFactors()) + BLEND_CUSTOM_SEPARATE // Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendFactorsSeparate()) +} BlendMode; + +// Gesture +// NOTE: Provided as bit-wise flags to enable only desired gestures +typedef enum { + GESTURE_NONE = 0, // No gesture + GESTURE_TAP = 1, // Tap gesture + GESTURE_DOUBLETAP = 2, // Double tap gesture + GESTURE_HOLD = 4, // Hold gesture + GESTURE_DRAG = 8, // Drag gesture + GESTURE_SWIPE_RIGHT = 16, // Swipe right gesture + GESTURE_SWIPE_LEFT = 32, // Swipe left gesture + GESTURE_SWIPE_UP = 64, // Swipe up gesture + GESTURE_SWIPE_DOWN = 128, // Swipe down gesture + GESTURE_PINCH_IN = 256, // Pinch in gesture + GESTURE_PINCH_OUT = 512 // Pinch out gesture +} Gesture; + +// Camera system modes +typedef enum { + CAMERA_CUSTOM = 0, // Camera custom, controlled by user (UpdateCamera() does nothing) + CAMERA_FREE, // Camera free mode + CAMERA_ORBITAL, // Camera orbital, around target, zoom supported + CAMERA_FIRST_PERSON, // Camera first person + CAMERA_THIRD_PERSON // Camera third person +} CameraMode; + +// Camera projection +typedef enum { + CAMERA_PERSPECTIVE = 0, // Perspective projection + CAMERA_ORTHOGRAPHIC // Orthographic projection +} CameraProjection; + +// N-patch layout +typedef enum { + NPATCH_NINE_PATCH = 0, // Npatch layout: 3x3 tiles + NPATCH_THREE_PATCH_VERTICAL, // Npatch layout: 1x3 tiles + NPATCH_THREE_PATCH_HORIZONTAL // Npatch layout: 3x1 tiles +} NPatchLayout; + +// Callbacks to hook some internal functions +// WARNING: These callbacks are intended for advanced users +typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args); // Logging: Redirect trace log messages +typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, int *dataSize); // FileIO: Load binary data +typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, int dataSize); // FileIO: Save binary data +typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data +typedef bool (*SaveFileTextCallback)(const char *fileName, const char *text); // FileIO: Save text data + +//------------------------------------------------------------------------------------ +// Global Variables Definition +//------------------------------------------------------------------------------------ +// It's lonely here... + +//------------------------------------------------------------------------------------ +// Window and Graphics Device Functions (Module: core) +//------------------------------------------------------------------------------------ + +#if defined(__cplusplus) +extern "C" { // Prevents name mangling of functions +#endif + +// Window-related functions +RLAPI void InitWindow(int width, int height, const char *title); // Initialize window and OpenGL context +RLAPI void CloseWindow(void); // Close window and unload OpenGL context +RLAPI bool WindowShouldClose(void); // Check if application should close (KEY_ESCAPE pressed or windows close icon clicked) +RLAPI bool IsWindowReady(void); // Check if window has been initialized successfully +RLAPI bool IsWindowFullscreen(void); // Check if window is currently fullscreen +RLAPI bool IsWindowHidden(void); // Check if window is currently hidden +RLAPI bool IsWindowMinimized(void); // Check if window is currently minimized +RLAPI bool IsWindowMaximized(void); // Check if window is currently maximized +RLAPI bool IsWindowFocused(void); // Check if window is currently focused +RLAPI bool IsWindowResized(void); // Check if window has been resized last frame +RLAPI bool IsWindowState(unsigned int flag); // Check if one specific window flag is enabled +RLAPI void SetWindowState(unsigned int flags); // Set window configuration state using flags +RLAPI void ClearWindowState(unsigned int flags); // Clear window configuration state flags +RLAPI void ToggleFullscreen(void); // Toggle window state: fullscreen/windowed, resizes monitor to match window resolution +RLAPI void ToggleBorderlessWindowed(void); // Toggle window state: borderless windowed, resizes window to match monitor resolution +RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable +RLAPI void MinimizeWindow(void); // Set window state: minimized, if resizable +RLAPI void RestoreWindow(void); // Restore window from being minimized/maximized +RLAPI void SetWindowIcon(Image image); // Set icon for window (single image, RGBA 32bit) +RLAPI void SetWindowIcons(Image *images, int count); // Set icon for window (multiple images, RGBA 32bit) +RLAPI void SetWindowTitle(const char *title); // Set title for window +RLAPI void SetWindowPosition(int x, int y); // Set window position on screen +RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window +RLAPI void SetWindowMinSize(int width, int height); // Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE) +RLAPI void SetWindowMaxSize(int width, int height); // Set window maximum dimensions (for FLAG_WINDOW_RESIZABLE) +RLAPI void SetWindowSize(int width, int height); // Set window dimensions +RLAPI void SetWindowOpacity(float opacity); // Set window opacity [0.0f..1.0f] +RLAPI void SetWindowFocused(void); // Set window focused +RLAPI void *GetWindowHandle(void); // Get native window handle +RLAPI int GetScreenWidth(void); // Get current screen width +RLAPI int GetScreenHeight(void); // Get current screen height +RLAPI int GetRenderWidth(void); // Get current render width (it considers HiDPI) +RLAPI int GetRenderHeight(void); // Get current render height (it considers HiDPI) +RLAPI int GetMonitorCount(void); // Get number of connected monitors +RLAPI int GetCurrentMonitor(void); // Get current monitor where window is placed +RLAPI Vector2 GetMonitorPosition(int monitor); // Get specified monitor position +RLAPI int GetMonitorWidth(int monitor); // Get specified monitor width (current video mode used by monitor) +RLAPI int GetMonitorHeight(int monitor); // Get specified monitor height (current video mode used by monitor) +RLAPI int GetMonitorPhysicalWidth(int monitor); // Get specified monitor physical width in millimetres +RLAPI int GetMonitorPhysicalHeight(int monitor); // Get specified monitor physical height in millimetres +RLAPI int GetMonitorRefreshRate(int monitor); // Get specified monitor refresh rate +RLAPI Vector2 GetWindowPosition(void); // Get window position XY on monitor +RLAPI Vector2 GetWindowScaleDPI(void); // Get window scale DPI factor +RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the specified monitor +RLAPI void SetClipboardText(const char *text); // Set clipboard text content +RLAPI const char *GetClipboardText(void); // Get clipboard text content +RLAPI Image GetClipboardImage(void); // Get clipboard image content +RLAPI void EnableEventWaiting(void); // Enable waiting for events on EndDrawing(), no automatic event polling +RLAPI void DisableEventWaiting(void); // Disable waiting for events on EndDrawing(), automatic events polling + +// Cursor-related functions +RLAPI void ShowCursor(void); // Shows cursor +RLAPI void HideCursor(void); // Hides cursor +RLAPI bool IsCursorHidden(void); // Check if cursor is not visible +RLAPI void EnableCursor(void); // Enables cursor (unlock cursor) +RLAPI void DisableCursor(void); // Disables cursor (lock cursor) +RLAPI bool IsCursorOnScreen(void); // Check if cursor is on the screen + +// Drawing-related functions +RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color) +RLAPI void BeginDrawing(void); // Setup canvas (framebuffer) to start drawing +RLAPI void EndDrawing(void); // End canvas drawing and swap buffers (double buffering) +RLAPI void BeginMode2D(Camera2D camera); // Begin 2D mode with custom camera (2D) +RLAPI void EndMode2D(void); // Ends 2D mode with custom camera +RLAPI void BeginMode3D(Camera3D camera); // Begin 3D mode with custom camera (3D) +RLAPI void EndMode3D(void); // Ends 3D mode and returns to default 2D orthographic mode +RLAPI void BeginTextureMode(RenderTexture2D target); // Begin drawing to render texture +RLAPI void EndTextureMode(void); // Ends drawing to render texture +RLAPI void BeginShaderMode(Shader shader); // Begin custom shader drawing +RLAPI void EndShaderMode(void); // End custom shader drawing (use default shader) +RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied, subtract, custom) +RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending) +RLAPI void BeginScissorMode(int x, int y, int width, int height); // Begin scissor mode (define screen area for following drawing) +RLAPI void EndScissorMode(void); // End scissor mode +RLAPI void BeginVrStereoMode(VrStereoConfig config); // Begin stereo rendering (requires VR simulator) +RLAPI void EndVrStereoMode(void); // End stereo rendering (requires VR simulator) + +// VR stereo config functions for VR simulator +RLAPI VrStereoConfig LoadVrStereoConfig(VrDeviceInfo device); // Load VR stereo config for VR simulator device parameters +RLAPI void UnloadVrStereoConfig(VrStereoConfig config); // Unload VR stereo config + +// Shader management functions +// NOTE: Shader functionality is not available on OpenGL 1.1 +RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations +RLAPI Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations +RLAPI bool IsShaderValid(Shader shader); // Check if a shader is valid (loaded on GPU) +RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location +RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName); // Get shader attribute location +RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value +RLAPI void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count); // Set shader uniform value vector +RLAPI void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat); // Set shader uniform value (matrix 4x4) +RLAPI void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture); // Set shader uniform value and bind the texture (sampler2d) +RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) + +// Screen-space-related functions +#define GetMouseRay GetScreenToWorldRay // Compatibility hack for previous raylib versions +RLAPI Ray GetScreenToWorldRay(Vector2 position, Camera camera); // Get a ray trace from screen position (i.e mouse) +RLAPI Ray GetScreenToWorldRayEx(Vector2 position, Camera camera, int width, int height); // Get a ray trace from screen position (i.e mouse) in a viewport +RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Get the screen space position for a 3d world space position +RLAPI Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height); // Get size position for a 3d world space position +RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); // Get the screen space position for a 2d camera world space position +RLAPI Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera); // Get the world space position for a 2d camera screen space position +RLAPI Matrix GetCameraMatrix(Camera camera); // Get camera transform matrix (view matrix) +RLAPI Matrix GetCameraMatrix2D(Camera2D camera); // Get camera 2d transform matrix + +// Timing-related functions +RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum) +RLAPI float GetFrameTime(void); // Get time in seconds for last frame drawn (delta time) +RLAPI double GetTime(void); // Get elapsed time in seconds since InitWindow() +RLAPI int GetFPS(void); // Get current FPS + +// 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 +RLAPI void SwapScreenBuffer(void); // Swap back buffer with front buffer (screen drawing) +RLAPI void PollInputEvents(void); // Register all input events +RLAPI void WaitTime(double seconds); // Wait for some time (halt program execution) + +// Random values generation functions +RLAPI void SetRandomSeed(unsigned int seed); // Set the seed for the random number generator +RLAPI int GetRandomValue(int min, int max); // Get a random value between min and max (both included) +RLAPI int *LoadRandomSequence(unsigned int count, int min, int max); // Load random values sequence, no values repeated +RLAPI void UnloadRandomSequence(int *sequence); // Unload random values sequence + +// Misc. functions +RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (filename extension defines format) +RLAPI void SetConfigFlags(unsigned int flags); // Setup init configuration flags (view FLAGS) +RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available) + +// Logging system +RLAPI void SetTraceLogLevel(int logLevel); // Set the current threshold (minimum) log level +RLAPI void TraceLog(int logLevel, const char *text, ...); // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...) +RLAPI void SetTraceLogCallback(TraceLogCallback callback); // Set custom trace log + +// Memory management, using internal allocators +RLAPI void *MemAlloc(unsigned int size); // Internal memory allocator +RLAPI void *MemRealloc(void *ptr, unsigned int size); // Internal memory reallocator +RLAPI void MemFree(void *ptr); // Internal memory free + +// File system management functions +RLAPI unsigned char *LoadFileData(const char *fileName, int *dataSize); // Load file data as byte array (read) +RLAPI void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData() +RLAPI bool SaveFileData(const char *fileName, void *data, int dataSize); // Save data to file from byte array (write), returns true on success +RLAPI bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileName); // Export data to code (.h), returns true on success +RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string +RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText() +RLAPI bool SaveFileText(const char *fileName, const char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success + +// File access custom callbacks +// WARNING: Callbacks setup is intended for advanced users +RLAPI void SetLoadFileDataCallback(LoadFileDataCallback callback); // Set custom file binary data loader +RLAPI void SetSaveFileDataCallback(SaveFileDataCallback callback); // Set custom file binary data saver +RLAPI void SetLoadFileTextCallback(LoadFileTextCallback callback); // Set custom file text data loader +RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback); // Set custom file text data saver + +RLAPI int FileRename(const char *fileName, const char *fileRename); // Rename file (if exists) +RLAPI int FileRemove(const char *fileName); // Remove file (if exists) +RLAPI int FileCopy(const char *srcPath, const char *dstPath); // Copy file from one path to another, dstPath created if it doesn't exist +RLAPI int FileMove(const char *srcPath, const char *dstPath); // Move file from one directory to another, dstPath created if it doesn't exist +RLAPI int FileTextReplace(const char *fileName, const char *search, const char *replacement); // Replace text in an existing file +RLAPI int FileTextFindIndex(const char *fileName, const char *search); // Find text in existing file +RLAPI bool FileExists(const char *fileName); // Check if file exists +RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists +RLAPI bool IsFileExtension(const char *fileName, const char *ext); // Check file extension (recommended include point: .png, .wav) +RLAPI int GetFileLength(const char *fileName); // Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h) +RLAPI long GetFileModTime(const char *fileName); // Get file modification time (last write time) +RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: '.png') +RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string +RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string) +RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string) +RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string) +RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) +RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string) +RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success +RLAPI bool ChangeDirectory(const char *dirPath); // Change working directory, return true on success +RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory +RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS +RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths, files and directories, no subdirs scan +RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and subdir scan; some filters available: "*.*", "FILES*", "DIRS*" +RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths +RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window +RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths +RLAPI void UnloadDroppedFiles(FilePathList files); // Unload dropped filepaths +RLAPI unsigned int GetDirectoryFileCount(const char *dirPath); // Get the file count in a directory +RLAPI unsigned int GetDirectoryFileCountEx(const char *basePath, const char *filter, bool scanSubdirs); // Get the file count in a directory with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result + +// Compression/Encoding functionality +RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree() +RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // Decompress data (DEFLATE algorithm), memory must be MemFree() +RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string (includes NULL terminator), memory must be MemFree() +RLAPI unsigned char *DecodeDataBase64(const char *text, int *outputSize); // Decode Base64 string (expected NULL terminated), memory must be MemFree() +RLAPI unsigned int ComputeCRC32(unsigned char *data, int dataSize); // Compute CRC32 hash code +RLAPI unsigned int *ComputeMD5(unsigned char *data, int dataSize); // Compute MD5 hash code, returns static int[4] (16 bytes) +RLAPI unsigned int *ComputeSHA1(unsigned char *data, int dataSize); // Compute SHA1 hash code, returns static int[5] (20 bytes) +RLAPI unsigned int *ComputeSHA256(unsigned char *data, int dataSize); // Compute SHA256 hash code, returns static int[8] (32 bytes) + +// Automation events functionality +RLAPI AutomationEventList LoadAutomationEventList(const char *fileName); // Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS +RLAPI void UnloadAutomationEventList(AutomationEventList list); // Unload automation events list from file +RLAPI bool ExportAutomationEventList(AutomationEventList list, const char *fileName); // Export automation events list as text file +RLAPI void SetAutomationEventList(AutomationEventList *list); // Set automation event list to record to +RLAPI void SetAutomationEventBaseFrame(int frame); // Set automation event internal base frame to start recording +RLAPI void StartAutomationEventRecording(void); // Start recording automation events (AutomationEventList must be set) +RLAPI void StopAutomationEventRecording(void); // Stop recording automation events +RLAPI void PlayAutomationEvent(AutomationEvent event); // Play a recorded automation event + +//------------------------------------------------------------------------------------ +// Input Handling Functions (Module: core) +//------------------------------------------------------------------------------------ + +// Input-related functions: keyboard +RLAPI bool IsKeyPressed(int key); // Check if a key has been pressed once +RLAPI bool IsKeyPressedRepeat(int key); // Check if a key has been pressed again +RLAPI bool IsKeyDown(int key); // Check if a key is being pressed +RLAPI bool IsKeyReleased(int key); // Check if a key has been released once +RLAPI bool IsKeyUp(int key); // Check if a key is NOT being pressed +RLAPI int GetKeyPressed(void); // Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty +RLAPI int GetCharPressed(void); // Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty +RLAPI const char *GetKeyName(int key); // Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard) +RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC) + +// Input-related functions: gamepads +RLAPI bool IsGamepadAvailable(int gamepad); // Check if a gamepad is available +RLAPI const char *GetGamepadName(int gamepad); // Get gamepad internal name id +RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Check if a gamepad button has been pressed once +RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Check if a gamepad button is being pressed +RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Check if a gamepad button has been released once +RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Check if a gamepad button is NOT being pressed +RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed +RLAPI int GetGamepadAxisCount(int gamepad); // Get axis count for a gamepad +RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Get movement value for a gamepad axis +RLAPI int SetGamepadMappings(const char *mappings); // Set internal gamepad mappings (SDL_GameControllerDB) +RLAPI void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float duration); // Set gamepad vibration for both motors (duration in seconds) + +// Input-related functions: mouse +RLAPI bool IsMouseButtonPressed(int button); // Check if a mouse button has been pressed once +RLAPI bool IsMouseButtonDown(int button); // Check if a mouse button is being pressed +RLAPI bool IsMouseButtonReleased(int button); // Check if a mouse button has been released once +RLAPI bool IsMouseButtonUp(int button); // Check if a mouse button is NOT being pressed +RLAPI int GetMouseX(void); // Get mouse position X +RLAPI int GetMouseY(void); // Get mouse position Y +RLAPI Vector2 GetMousePosition(void); // Get mouse position XY +RLAPI Vector2 GetMouseDelta(void); // Get mouse delta between frames +RLAPI void SetMousePosition(int x, int y); // Set mouse position XY +RLAPI void SetMouseOffset(int offsetX, int offsetY); // Set mouse offset +RLAPI void SetMouseScale(float scaleX, float scaleY); // Set mouse scaling +RLAPI float GetMouseWheelMove(void); // Get mouse wheel movement for X or Y, whichever is larger +RLAPI Vector2 GetMouseWheelMoveV(void); // Get mouse wheel movement for both X and Y +RLAPI void SetMouseCursor(int cursor); // Set mouse cursor + +// Input-related functions: touch +RLAPI int GetTouchX(void); // Get touch position X for touch point 0 (relative to screen size) +RLAPI int GetTouchY(void); // Get touch position Y for touch point 0 (relative to screen size) +RLAPI Vector2 GetTouchPosition(int index); // Get touch position XY for a touch point index (relative to screen size) +RLAPI int GetTouchPointId(int index); // Get touch point identifier for given index +RLAPI int GetTouchPointCount(void); // Get number of touch points + +//------------------------------------------------------------------------------------ +// Gestures and Touch Handling Functions (Module: rgestures) +//------------------------------------------------------------------------------------ +RLAPI void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags +RLAPI bool IsGestureDetected(unsigned int gesture); // Check if a gesture have been detected +RLAPI int GetGestureDetected(void); // Get latest detected gesture +RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in seconds +RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector +RLAPI float GetGestureDragAngle(void); // Get gesture drag angle +RLAPI Vector2 GetGesturePinchVector(void); // Get gesture pinch delta +RLAPI float GetGesturePinchAngle(void); // Get gesture pinch angle + +//------------------------------------------------------------------------------------ +// Camera System Functions (Module: rcamera) +//------------------------------------------------------------------------------------ +RLAPI void UpdateCamera(Camera *camera, int mode); // Update camera position for selected mode +RLAPI void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom); // Update camera movement/rotation + +//------------------------------------------------------------------------------------ +// 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 +RLAPI void SetShapesTexture(Texture2D texture, Rectangle source); // Set texture and rectangle to be used on shapes drawing +RLAPI Texture2D GetShapesTexture(void); // Get texture that is used for shapes drawing +RLAPI Rectangle GetShapesTextureRectangle(void); // Get texture source rectangle that is used for shapes drawing + +// Basic shapes drawing functions +RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel using geometry [Can be slow, use with care] +RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel using geometry (Vector version) [Can be slow, use with care] +RLAPI void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line +RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (using gl lines) +RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line (using triangles/quads) +RLAPI void DrawLineStrip(const Vector2 *points, int pointCount, Color color); // Draw lines sequence (using gl lines) +RLAPI void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw line segment cubic-bezier in-out interpolation +RLAPI void DrawLineDashed(Vector2 startPos, Vector2 endPos, int dashSize, int spaceSize, Color color); // Draw a dashed line +RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color); // Draw a color-filled circle +RLAPI void DrawCircleV(Vector2 center, float radius, Color color); // Draw a color-filled circle (Vector version) +RLAPI void DrawCircleGradient(Vector2 center, float radius, Color inner, Color outer); // Draw a gradient-filled circle +RLAPI void DrawCircleSector(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw a piece of a circle +RLAPI void DrawCircleSectorLines(Vector2 center, float radius, float startAngle, float endAngle, int segments, Color color); // Draw circle sector outline +RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline +RLAPI void DrawCircleLinesV(Vector2 center, float radius, Color color); // Draw circle outline (Vector version) +RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse +RLAPI void DrawEllipseV(Vector2 center, float radiusH, float radiusV, Color color); // Draw ellipse (Vector version) +RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse outline +RLAPI void DrawEllipseLinesV(Vector2 center, float radiusH, float radiusV, Color color); // Draw ellipse outline (Vector version) +RLAPI void DrawRing(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring +RLAPI void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, float startAngle, float endAngle, int segments, Color color); // Draw ring outline +RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle +RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version) +RLAPI void DrawRectangleRec(Rectangle rec, Color color); // Draw a color-filled rectangle +RLAPI void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters +RLAPI void DrawRectangleGradientV(int posX, int posY, int width, int height, Color top, Color bottom); // Draw a vertical-gradient-filled rectangle +RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color left, Color right); // Draw a horizontal-gradient-filled rectangle +RLAPI void DrawRectangleGradientEx(Rectangle rec, Color topLeft, Color bottomLeft, Color bottomRight, Color topRight); // Draw a gradient-filled rectangle with custom vertex colors +RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline +RLAPI void DrawRectangleLinesEx(Rectangle rec, float lineThick, Color color); // Draw rectangle outline with extended parameters +RLAPI void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle with rounded edges +RLAPI void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color); // Draw rectangle lines with rounded edges +RLAPI void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, float lineThick, Color color); // Draw rectangle with rounded edges outline +RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle (vertex in counter-clockwise order!) +RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline (vertex in counter-clockwise order!) +RLAPI void DrawTriangleFan(const Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points (first vertex is the center) +RLAPI void DrawTriangleStrip(const Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points +RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version) +RLAPI void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a polygon outline of n sides +RLAPI void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float lineThick, Color color); // Draw a polygon outline of n sides with extended parameters + +// Splines drawing functions +RLAPI void DrawSplineLinear(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Linear, minimum 2 points +RLAPI void DrawSplineBasis(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: B-Spline, minimum 4 points +RLAPI void DrawSplineCatmullRom(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Catmull-Rom, minimum 4 points +RLAPI void DrawSplineBezierQuadratic(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] +RLAPI void DrawSplineBezierCubic(const Vector2 *points, int pointCount, float thick, Color color); // Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] +RLAPI void DrawSplineSegmentLinear(Vector2 p1, Vector2 p2, float thick, Color color); // Draw spline segment: Linear, 2 points +RLAPI void DrawSplineSegmentBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color); // Draw spline segment: B-Spline, 4 points +RLAPI void DrawSplineSegmentCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float thick, Color color); // Draw spline segment: Catmull-Rom, 4 points +RLAPI void DrawSplineSegmentBezierQuadratic(Vector2 p1, Vector2 c2, Vector2 p3, float thick, Color color); // Draw spline segment: Quadratic Bezier, 2 points, 1 control point +RLAPI void DrawSplineSegmentBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float thick, Color color); // Draw spline segment: Cubic Bezier, 2 points, 2 control points + +// Spline segment point evaluation functions, for a given t [0.0f .. 1.0f] +RLAPI Vector2 GetSplinePointLinear(Vector2 startPos, Vector2 endPos, float t); // Get (evaluate) spline point: Linear +RLAPI Vector2 GetSplinePointBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t); // Get (evaluate) spline point: B-Spline +RLAPI Vector2 GetSplinePointCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t); // Get (evaluate) spline point: Catmull-Rom +RLAPI Vector2 GetSplinePointBezierQuad(Vector2 p1, Vector2 c2, Vector2 p3, float t); // Get (evaluate) spline point: Quadratic Bezier +RLAPI Vector2 GetSplinePointBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float t); // Get (evaluate) spline point: Cubic Bezier + +// Basic shapes collision detection functions +RLAPI bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2); // Check collision between two rectangles +RLAPI bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2); // Check collision between two circles +RLAPI bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec); // Check collision between circle and rectangle +RLAPI bool CheckCollisionCircleLine(Vector2 center, float radius, Vector2 p1, Vector2 p2); // Check if circle collides with a line created betweeen two points [p1] and [p2] +RLAPI bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle +RLAPI bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius); // Check if point is inside circle +RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3); // Check if point is inside a triangle +RLAPI bool CheckCollisionPointLine(Vector2 point, Vector2 p1, Vector2 p2, int threshold); // Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] +RLAPI bool CheckCollisionPointPoly(Vector2 point, const Vector2 *points, int pointCount); // Check if point is within a polygon described by array of vertices +RLAPI bool CheckCollisionLines(Vector2 startPos1, Vector2 endPos1, Vector2 startPos2, Vector2 endPos2, Vector2 *collisionPoint); // Check the collision between two lines defined by two points each, returns collision point by reference +RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); // Get collision rectangle for two rectangles collision + +//------------------------------------------------------------------------------------ +// Texture Loading and Drawing Functions (Module: textures) +//------------------------------------------------------------------------------------ + +// Image loading functions +// NOTE: These functions do not require GPU access +RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM) +RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data +RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data) +RLAPI Image LoadImageAnimFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int *frames); // Load image sequence from memory buffer +RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png' +RLAPI Image LoadImageFromTexture(Texture2D texture); // Load image from GPU texture data +RLAPI Image LoadImageFromScreen(void); // Load image from screen buffer and (screenshot) +RLAPI bool IsImageValid(Image image); // Check if an image is valid (data and parameters) +RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM) +RLAPI bool ExportImage(Image image, const char *fileName); // Export image data to file, returns true on success +RLAPI unsigned char *ExportImageToMemory(Image image, const char *fileType, int *fileSize); // Export image to memory buffer, memory must be MemFree() +RLAPI bool ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes, returns true on success + +// Image generation functions +RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color +RLAPI Image GenImageGradientLinear(int width, int height, int direction, Color start, Color end); // Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient +RLAPI Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer); // Generate image: radial gradient +RLAPI Image GenImageGradientSquare(int width, int height, float density, Color inner, Color outer); // Generate image: square gradient +RLAPI Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2); // Generate image: checked +RLAPI Image GenImageWhiteNoise(int width, int height, float factor); // Generate image: white noise +RLAPI Image GenImagePerlinNoise(int width, int height, int offsetX, int offsetY, float scale); // Generate image: perlin noise +RLAPI Image GenImageCellular(int width, int height, int tileSize); // Generate image: cellular algorithm, bigger tileSize means bigger cells +RLAPI Image GenImageText(int width, int height, const char *text); // Generate image: grayscale image from text data + +// Image manipulation functions +RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations) +RLAPI Image ImageFromImage(Image image, Rectangle rec); // Create an image from another image piece +RLAPI Image ImageFromChannel(Image image, int selectedChannel); // Create an image from a selected channel of another image (GRAYSCALE) +RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) +RLAPI Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint); // Create an image from text (custom sprite font) +RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format +RLAPI void ImageToPOT(Image *image, Color fill); // Convert image to POT (power-of-two) +RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle +RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value +RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color +RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image +RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel +RLAPI void ImageBlurGaussian(Image *image, int blurSize); // Apply Gaussian blur using a box blur approximation +RLAPI void ImageKernelConvolution(Image *image, const float *kernel, int kernelSize); // Apply custom square convolution kernel to image +RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (Bicubic scaling algorithm) +RLAPI void ImageResizeNN(Image *image, int newWidth, int newHeight); // Resize image (Nearest-Neighbor scaling algorithm) +RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill); // Resize canvas and fill with color +RLAPI void ImageMipmaps(Image *image); // Compute all mipmap levels for a provided image +RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) +RLAPI void ImageFlipVertical(Image *image); // Flip image vertically +RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally +RLAPI void ImageRotate(Image *image, int degrees); // Rotate image by input angle in degrees (-359 to 359) +RLAPI void ImageRotateCW(Image *image); // Rotate image clockwise 90deg +RLAPI void ImageRotateCCW(Image *image); // Rotate image counter-clockwise 90deg +RLAPI void ImageColorTint(Image *image, Color color); // Modify image color: tint +RLAPI void ImageColorInvert(Image *image); // Modify image color: invert +RLAPI void ImageColorGrayscale(Image *image); // Modify image color: grayscale +RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100) +RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) +RLAPI void ImageColorReplace(Image *image, Color color, Color replace); // Modify image color: replace color +RLAPI Color *LoadImageColors(Image image); // Load color data from image as a Color array (RGBA - 32bit) +RLAPI Color *LoadImagePalette(Image image, int maxPaletteSize, int *colorCount); // Load colors palette from image as a Color array (RGBA - 32bit) +RLAPI void UnloadImageColors(Color *colors); // Unload color data loaded with LoadImageColors() +RLAPI void UnloadImagePalette(Color *colors); // Unload colors palette loaded with LoadImagePalette() +RLAPI Rectangle GetImageAlphaBorder(Image image, float threshold); // Get image alpha border rectangle +RLAPI Color GetImageColor(Image image, int x, int y); // Get image pixel color at (x, y) position + +// Image drawing functions +// NOTE: Image software-rendering functions (CPU) +RLAPI void ImageClearBackground(Image *dst, Color color); // Clear image background with given color +RLAPI void ImageDrawPixel(Image *dst, int posX, int posY, Color color); // Draw pixel within an image +RLAPI void ImageDrawPixelV(Image *dst, Vector2 position, Color color); // Draw pixel within an image (Vector version) +RLAPI void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw line within an image +RLAPI void ImageDrawLineV(Image *dst, Vector2 start, Vector2 end, Color color); // Draw line within an image (Vector version) +RLAPI void ImageDrawLineEx(Image *dst, Vector2 start, Vector2 end, int thick, Color color); // Draw a line defining thickness within an image +RLAPI void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color); // Draw a filled circle within an image +RLAPI void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color); // Draw a filled circle within an image (Vector version) +RLAPI void ImageDrawCircleLines(Image *dst, int centerX, int centerY, int radius, Color color); // Draw circle outline within an image +RLAPI void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color color); // Draw circle outline within an image (Vector version) +RLAPI void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color); // Draw rectangle within an image +RLAPI void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color); // Draw rectangle within an image (Vector version) +RLAPI void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color); // Draw rectangle within an image +RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color); // Draw rectangle lines within an image +RLAPI void ImageDrawTriangle(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle within an image +RLAPI void ImageDrawTriangleEx(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color c1, Color c2, Color c3); // Draw triangle with interpolated colors within an image +RLAPI void ImageDrawTriangleLines(Image *dst, Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline within an image +RLAPI void ImageDrawTriangleFan(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points within an image (first vertex is the center) +RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCount, Color color); // Draw a triangle strip defined by points within an image +RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source) +RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination) +RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination) + +// Texture loading functions +// NOTE: These functions require GPU access +RLAPI Texture2D LoadTexture(const char *fileName); // Load texture from file into GPU memory (VRAM) +RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data +RLAPI TextureCubemap LoadTextureCubemap(Image image, int layout); // Load cubemap from image, multiple image cubemap layouts supported +RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer) +RLAPI bool IsTextureValid(Texture2D texture); // Check if a texture is valid (loaded in GPU) +RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) +RLAPI bool IsRenderTextureValid(RenderTexture2D target); // Check if a render texture is valid (loaded in GPU) +RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM) +RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data (pixels should be able to fill texture) +RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data (pixels and rec should fit in texture) + +// Texture configuration functions +RLAPI void GenTextureMipmaps(Texture2D *texture); // Generate GPU mipmaps for a texture +RLAPI void SetTextureFilter(Texture2D texture, int filter); // Set texture scaling filter mode +RLAPI void SetTextureWrap(Texture2D texture, int wrap); // Set texture wrapping mode + +// Texture drawing functions +RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D +RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2 +RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters +RLAPI void DrawTextureRec(Texture2D texture, Rectangle source, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle +RLAPI void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters +RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely + +// Color/pixel related functions +RLAPI bool ColorIsEqual(Color col1, Color col2); // Check if two colors are equal +RLAPI Color Fade(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f +RLAPI int ColorToInt(Color color); // Get hexadecimal value for a Color (0xRRGGBBAA) +RLAPI Vector4 ColorNormalize(Color color); // Get Color normalized as float [0..1] +RLAPI Color ColorFromNormalized(Vector4 normalized); // Get Color from normalized values [0..1] +RLAPI Vector3 ColorToHSV(Color color); // Get HSV values for a Color, hue [0..360], saturation/value [0..1] +RLAPI Color ColorFromHSV(float hue, float saturation, float value); // Get a Color from HSV values, hue [0..360], saturation/value [0..1] +RLAPI Color ColorTint(Color color, Color tint); // Get color multiplied with another color +RLAPI Color ColorBrightness(Color color, float factor); // Get color with brightness correction, brightness factor goes from -1.0f to 1.0f +RLAPI Color ColorContrast(Color color, float contrast); // Get color with contrast correction, contrast values between -1.0f and 1.0f +RLAPI Color ColorAlpha(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f +RLAPI Color ColorAlphaBlend(Color dst, Color src, Color tint); // Get src alpha-blended into dst color with tint +RLAPI Color ColorLerp(Color color1, Color color2, float factor); // Get color lerp interpolation between two colors, factor [0.0f..1.0f] +RLAPI Color GetColor(unsigned int hexValue); // Get Color structure from hexadecimal value +RLAPI Color GetPixelColor(void *srcPtr, int format); // Get Color from a source pixel pointer of certain format +RLAPI void SetPixelColor(void *dstPtr, Color color, int format); // Set color formatted into destination pixel pointer +RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes for certain format + +//------------------------------------------------------------------------------------ +// Font Loading and Text Drawing Functions (Module: text) +//------------------------------------------------------------------------------------ + +// Font loading/unloading functions +RLAPI Font GetFontDefault(void); // Get the default Font +RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM) +RLAPI Font LoadFontEx(const char *fileName, int fontSize, const int *codepoints, int codepointCount); // Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height +RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style) +RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, const int *codepoints, int codepointCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf' +RLAPI bool IsFontValid(Font font); // Check if a font is valid (font data loaded, WARNING: GPU texture not checked) +RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, const int *codepoints, int codepointCount, int type, int *glyphCount); // Load font data for further use +RLAPI Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info +RLAPI void UnloadFontData(GlyphInfo *glyphs, int glyphCount); // Unload font chars info data (RAM) +RLAPI void UnloadFont(Font font); // Unload font from GPU memory (VRAM) +RLAPI bool ExportFontAsCode(Font font, const char *fileName); // Export font as code file, returns true on success + +// Text drawing functions +RLAPI void DrawFPS(int posX, int posY); // Draw current FPS +RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) +RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters +RLAPI void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint); // Draw text using Font and pro parameters (rotation) +RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint) +RLAPI void DrawTextCodepoints(Font font, const int *codepoints, int codepointCount, Vector2 position, float fontSize, float spacing, Color tint); // Draw multiple character (codepoint) + +// Text font info functions +RLAPI void SetTextLineSpacing(int spacing); // Set vertical line spacing when drawing with line-breaks +RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font +RLAPI Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font +RLAPI Vector2 MeasureTextCodepoints(Font font, const int *codepoints, int length, float fontSize, float spacing); // Measure string size for an existing array of codepoints for Font +RLAPI int GetGlyphIndex(Font font, int codepoint); // Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found +RLAPI GlyphInfo GetGlyphInfo(Font font, int codepoint); // Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found +RLAPI Rectangle GetGlyphAtlasRec(Font font, int codepoint); // Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found + +// Text codepoints management functions (unicode characters) +RLAPI char *LoadUTF8(const int *codepoints, int length); // Load UTF-8 text encoded from codepoints array +RLAPI void UnloadUTF8(char *text); // Unload UTF-8 text encoded from codepoints array +RLAPI int *LoadCodepoints(const char *text, int *count); // Load all codepoints from a UTF-8 text string, codepoints count returned by parameter +RLAPI void UnloadCodepoints(int *codepoints); // Unload codepoints data from memory +RLAPI int GetCodepointCount(const char *text); // Get total number of codepoints in a UTF-8 encoded string +RLAPI int GetCodepoint(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure +RLAPI int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure +RLAPI int GetCodepointPrevious(const char *text, int *codepointSize); // Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure +RLAPI const char *CodepointToUTF8(int codepoint, int *utf8Size); // Encode one codepoint into UTF-8 byte array (array length returned as parameter) + +// Text strings management functions (no UTF-8 strings, only byte chars) +// WARNING 1: Most of these functions use internal static buffers[], it's recommended to store returned data on user-side for re-use +// WARNING 2: Some functions allocate memory internally for the returned strings, those strings must be freed by user using MemFree() +RLAPI char **LoadTextLines(const char *text, int *count); // Load text as separate lines ('\n') +RLAPI void UnloadTextLines(char **text, int lineCount); // Unload text lines +RLAPI int TextCopy(char *dst, const char *src); // Copy one string to another, returns bytes copied +RLAPI bool TextIsEqual(const char *text1, const char *text2); // Check if two text string are equal +RLAPI unsigned int TextLength(const char *text); // Get text length, checks for '\0' ending +RLAPI const char *TextFormat(const char *text, ...); // Text formatting with variables (sprintf() style) +RLAPI const char *TextSubtext(const char *text, int position, int length); // Get a piece of a text string +RLAPI const char *TextRemoveSpaces(const char *text); // Remove text spaces, concat words +RLAPI char *GetTextBetween(const char *text, const char *begin, const char *end); // Get text between two strings +RLAPI char *TextReplace(const char *text, const char *search, const char *replacement); // Replace text string with new string +RLAPI char *TextReplaceAlloc(const char *text, const char *search, const char *replacement); // Replace text string with new string, memory must be MemFree() +RLAPI char *TextReplaceBetween(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings +RLAPI char *TextReplaceBetweenAlloc(const char *text, const char *begin, const char *end, const char *replacement); // Replace text between two specific strings, memory must be MemFree() +RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a defined byte position +RLAPI char *TextInsertAlloc(const char *text, const char *insert, int position); // Insert text in a defined byte position, memory must be MemFree() +RLAPI char *TextJoin(char **textList, int count, const char *delimiter); // Join text strings with delimiter +RLAPI char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings +RLAPI void TextAppend(char *text, const char *append, int *position); // Append text at specific position and move cursor +RLAPI int TextFindIndex(const char *text, const char *search); // Find first text occurrence within a string, -1 if not found +RLAPI char *TextToUpper(const char *text); // Get upper case version of provided string +RLAPI char *TextToLower(const char *text); // Get lower case version of provided string +RLAPI char *TextToPascal(const char *text); // Get Pascal case notation version of provided string +RLAPI char *TextToSnake(const char *text); // Get Snake case notation version of provided string +RLAPI char *TextToCamel(const char *text); // Get Camel case notation version of provided string +RLAPI int TextToInteger(const char *text); // Get integer value from text +RLAPI float TextToFloat(const char *text); // Get float value from text + +//------------------------------------------------------------------------------------ +// Basic 3d Shapes Drawing Functions (Module: models) +//------------------------------------------------------------------------------------ + +// Basic geometric 3D shapes drawing functions +RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space +RLAPI void DrawPoint3D(Vector3 position, Color color); // Draw a point in 3D space, actually a small line +RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color); // Draw a circle in 3D world space +RLAPI void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color); // Draw a color-filled triangle (vertex in counter-clockwise order!) +RLAPI void DrawTriangleStrip3D(const Vector3 *points, int pointCount, Color color); // Draw a triangle strip defined by points +RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color); // Draw cube +RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version) +RLAPI void DrawCubeWires(Vector3 position, float width, float height, float length, Color color); // Draw cube wires +RLAPI void DrawCubeWiresV(Vector3 position, Vector3 size, Color color); // Draw cube wires (Vector version) +RLAPI void DrawSphere(Vector3 centerPos, float radius, Color color); // Draw sphere +RLAPI void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere with extended parameters +RLAPI void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires +RLAPI void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone +RLAPI void DrawCylinderEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder with base at startPos and top at endPos +RLAPI void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires +RLAPI void DrawCylinderWiresEx(Vector3 startPos, Vector3 endPos, float startRadius, float endRadius, int sides, Color color); // Draw a cylinder wires with base at startPos and top at endPos +RLAPI void DrawCapsule(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color); // Draw a capsule with the center of its sphere caps at startPos and endPos +RLAPI void DrawCapsuleWires(Vector3 startPos, Vector3 endPos, float radius, int slices, int rings, Color color); // Draw capsule wireframe with the center of its sphere caps at startPos and endPos +RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color); // Draw a plane XZ +RLAPI void DrawRay(Ray ray, Color color); // Draw a ray line +RLAPI void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0)) + +//------------------------------------------------------------------------------------ +// Model 3d Loading and Drawing Functions (Module: models) +//------------------------------------------------------------------------------------ + +// Model management functions +RLAPI Model LoadModel(const char *fileName); // Load model from files (meshes and materials) +RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh (default material) +RLAPI bool IsModelValid(Model model); // Check if a model is valid (loaded in GPU, VAO/VBOs) +RLAPI void UnloadModel(Model model); // Unload model (including meshes) from memory (RAM and/or VRAM) +RLAPI BoundingBox GetModelBoundingBox(Model model); // Compute model bounding box limits (considers all meshes) + +// Model drawing functions +RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) +RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters +RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set) +RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters +RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires) +RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a billboard texture +RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint); // Draw a billboard texture defined by source +RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint); // Draw a billboard texture defined by source and rotation + +// Mesh management functions +RLAPI void UploadMesh(Mesh *mesh, bool dynamic); // Upload mesh vertex data in GPU and provide VAO/VBO ids +RLAPI void UpdateMeshBuffer(Mesh mesh, int index, const void *data, int dataSize, int offset); // Update mesh vertex data in GPU for a specific buffer index +RLAPI void UnloadMesh(Mesh mesh); // Unload mesh data from CPU and GPU +RLAPI void DrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform +RLAPI void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, int instances); // Draw multiple mesh instances with material and different transforms +RLAPI BoundingBox GetMeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits +RLAPI void GenMeshTangents(Mesh *mesh); // Compute mesh tangents +RLAPI bool ExportMesh(Mesh mesh, const char *fileName); // Export mesh data to file, returns true on success +RLAPI bool ExportMeshAsCode(Mesh mesh, const char *fileName); // Export mesh as code file (.h) defining multiple arrays of vertex attributes + +// Mesh generation functions +RLAPI Mesh GenMeshPoly(int sides, float radius); // Generate polygonal mesh +RLAPI Mesh GenMeshPlane(float width, float length, int resX, int resZ); // Generate plane mesh (with subdivisions) +RLAPI Mesh GenMeshCube(float width, float height, float length); // Generate cuboid mesh +RLAPI Mesh GenMeshSphere(float radius, int rings, int slices); // Generate sphere mesh (standard sphere) +RLAPI Mesh GenMeshHemiSphere(float radius, int rings, int slices); // Generate half-sphere mesh (no bottom cap) +RLAPI Mesh GenMeshCylinder(float radius, float height, int slices); // Generate cylinder mesh +RLAPI Mesh GenMeshCone(float radius, float height, int slices); // Generate cone/pyramid mesh +RLAPI Mesh GenMeshTorus(float radius, float size, int radSeg, int sides); // Generate torus mesh +RLAPI Mesh GenMeshKnot(float radius, float size, int radSeg, int sides); // Generate trefoil knot mesh +RLAPI Mesh GenMeshHeightmap(Image heightmap, Vector3 size); // Generate heightmap mesh from image data +RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); // Generate cubes-based map mesh from image data + +// Material loading/unloading functions +RLAPI Material *LoadMaterials(const char *fileName, int *materialCount); // Load materials from model file +RLAPI Material LoadMaterialDefault(void); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) +RLAPI bool IsMaterialValid(Material material); // Check if a material is valid (shader assigned, map textures loaded in GPU) +RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM) +RLAPI void SetMaterialTexture(Material *material, int mapType, Texture2D texture); // Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) +RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId); // Set material for a mesh + +// Model animations loading/unloading functions +RLAPI ModelAnimation *LoadModelAnimations(const char *fileName, int *animCount); // Load model animations from file +RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, float frame); // Update model animation pose (vertex buffers and bone matrices) +RLAPI void UpdateModelAnimationEx(Model model, ModelAnimation animA, float frameA, ModelAnimation animB, float frameB, float blend); // Update model animation pose, blending two animations +RLAPI void UnloadModelAnimations(ModelAnimation *animations, int animCount); // Unload animation array data +RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match + +// Collision detection functions +RLAPI bool CheckCollisionSpheres(Vector3 center1, float radius1, Vector3 center2, float radius2); // Check collision between two spheres +RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Check collision between two bounding boxes +RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius); // Check collision between box and sphere +RLAPI RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius); // Get collision info between ray and sphere +RLAPI RayCollision GetRayCollisionBox(Ray ray, BoundingBox box); // Get collision info between ray and box +RLAPI RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform); // Get collision info between ray and mesh +RLAPI RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle +RLAPI RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4); // Get collision info between ray and quad + +//------------------------------------------------------------------------------------ +// Audio Loading and Playing Functions (Module: audio) +//------------------------------------------------------------------------------------ +typedef void (*AudioCallback)(void *bufferData, unsigned int frames); + +// Audio device management functions +RLAPI void InitAudioDevice(void); // Initialize audio device and context +RLAPI void CloseAudioDevice(void); // Close the audio device and context +RLAPI bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully +RLAPI void SetMasterVolume(float volume); // Set master volume (listener) +RLAPI float GetMasterVolume(void); // Get master volume (listener) + +// Wave/Sound loading/unloading functions +RLAPI Wave LoadWave(const char *fileName); // Load wave data from file +RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. '.wav' +RLAPI bool IsWaveValid(Wave wave); // Checks if wave data is valid (data loaded and parameters) +RLAPI Sound LoadSound(const char *fileName); // Load sound from file +RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data +RLAPI Sound LoadSoundAlias(Sound source); // Create a new sound that shares the same sample data as the source sound, does not own the sound data +RLAPI bool IsSoundValid(Sound sound); // Checks if a sound is valid (data loaded and buffers initialized) +RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data (default data format: 32 bit float, stereo) +RLAPI void UnloadWave(Wave wave); // Unload wave data +RLAPI void UnloadSound(Sound sound); // Unload sound +RLAPI void UnloadSoundAlias(Sound alias); // Unload a sound alias (does not deallocate sample data) +RLAPI bool ExportWave(Wave wave, const char *fileName); // Export wave data to file, returns true on success +RLAPI bool ExportWaveAsCode(Wave wave, const char *fileName); // Export wave sample data to code (.h), returns true on success + +// Wave/Sound management functions +RLAPI void PlaySound(Sound sound); // Play a sound +RLAPI void StopSound(Sound sound); // Stop playing a sound +RLAPI void PauseSound(Sound sound); // Pause a sound +RLAPI void ResumeSound(Sound sound); // Resume a paused sound +RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing +RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) +RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) +RLAPI void SetSoundPan(Sound sound, float pan); // Set pan for a sound (-1.0 left, 0.0 center, 1.0 right) +RLAPI Wave WaveCopy(Wave wave); // Copy a wave to a new wave +RLAPI void WaveCrop(Wave *wave, int initFrame, int finalFrame); // Crop a wave to defined frames range +RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format +RLAPI float *LoadWaveSamples(Wave wave); // Load samples data from wave as a 32bit float data array +RLAPI void UnloadWaveSamples(float *samples); // Unload samples data loaded with LoadWaveSamples() + +// Music management functions +RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file +RLAPI Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, int dataSize); // Load music stream from data +RLAPI bool IsMusicValid(Music music); // Checks if a music stream is valid (context and buffers initialized) +RLAPI void UnloadMusicStream(Music music); // Unload music stream +RLAPI void PlayMusicStream(Music music); // Start music playing +RLAPI bool IsMusicStreamPlaying(Music music); // Check if music is playing +RLAPI void UpdateMusicStream(Music music); // Updates buffers for music streaming +RLAPI void StopMusicStream(Music music); // Stop music playing +RLAPI void PauseMusicStream(Music music); // Pause music playing +RLAPI void ResumeMusicStream(Music music); // Resume playing paused music +RLAPI void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds) +RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) +RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) +RLAPI void SetMusicPan(Music music, float pan); // Set pan for a music (-1.0 left, 0.0 center, 1.0 right) +RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds) +RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) + +// AudioStream management functions +RLAPI AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Load audio stream (to stream raw audio pcm data) +RLAPI bool IsAudioStreamValid(AudioStream stream); // Checks if an audio stream is valid (buffers initialized) +RLAPI void UnloadAudioStream(AudioStream stream); // Unload audio stream and free memory +RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int frameCount); // Update audio stream buffers with data +RLAPI bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill +RLAPI void PlayAudioStream(AudioStream stream); // Play audio stream +RLAPI void PauseAudioStream(AudioStream stream); // Pause audio stream +RLAPI void ResumeAudioStream(AudioStream stream); // Resume audio stream +RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check if audio stream is playing +RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream +RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level) +RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) +RLAPI void SetAudioStreamPan(AudioStream stream, float pan); // Set pan for audio stream (-1.0 to 1.0 range, 0.0 is centered) +RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams +RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback); // Audio thread callback to request new data + +RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream, receives frames x 2 samples as 'float' (stereo) +RLAPI void DetachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Detach audio stream processor from stream + +RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo) +RLAPI void DetachAudioMixedProcessor(AudioCallback processor); // Detach audio stream processor from the entire audio pipeline + +#if defined(__cplusplus) +} +#endif + +#endif // RAYLIB_H diff --git a/raylib-6.0_linux_amd64/include/raymath.h b/raylib-6.0_linux_amd64/include/raymath.h new file mode 100644 index 0000000..9398258 --- /dev/null +++ b/raylib-6.0_linux_amd64/include/raymath.h @@ -0,0 +1,3139 @@ +/********************************************************************************************** +* +* raymath v2.0 - Math functions to work with Vector2, Vector3, Matrix and Quaternions +* +* CONVENTIONS: +* - Matrix structure is defined as row-major (memory layout) but parameters naming AND all +* math operations performed by the library consider the structure as it was column-major +* It is like transposed versions of the matrices are used for all the maths +* It benefits some functions making them cache-friendly and also avoids matrix +* transpositions sometimes required by OpenGL +* Example: In memory order, row0 is [m0 m4 m8 m12] but in semantic math row0 is [m0 m1 m2 m3] +* - Functions are always self-contained, no function use another raymath function inside, +* required code is directly re-implemented inside +* - Functions input parameters are always received by value (2 unavoidable exceptions) +* - Functions use always a "result" variable for return (except C++ operators) +* - Functions are always defined inline +* - Angles are always in radians (DEG2RAD/RAD2DEG macros provided for convenience) +* - No compound literals used to make sure the library is compatible with C++ +* +* CONFIGURATION: +* #define RAYMATH_IMPLEMENTATION +* Generates the implementation of the library into the included file +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation +* +* #define RAYMATH_STATIC_INLINE +* Define static inline functions code, so #include header suffices for use +* This may use up lots of memory +* +* #define RAYMATH_DISABLE_CPP_OPERATORS +* Disables C++ operator overloads for raymath types. +* +* #define RAYMATH_USE_SIMD_INTRINSICS 1 +* Try to enable SIMD intrinsics for MatrixMultiply() +* Note that users enabling it must be aware of the target platform where application will +* run to support the selected SIMD intrinsic, for now, only SSE is supported +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2015-2026 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef RAYMATH_H +#define RAYMATH_H + +#if defined(RAYMATH_IMPLEMENTATION) && defined(RAYMATH_STATIC_INLINE) + #error "Specifying both RAYMATH_IMPLEMENTATION and RAYMATH_STATIC_INLINE is contradictory" +#endif + +// Function specifiers definition +#if defined(RAYMATH_IMPLEMENTATION) + #if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED) + #define RMAPI __declspec(dllexport) extern inline // Building raylib as a Win32 shared library (.dll) + #elif defined(BUILD_LIBTYPE_SHARED) + #define RMAPI __attribute__((visibility("default"))) // Building raylib as a Unix shared library (.so/.dylib) + #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED) + #define RMAPI __declspec(dllimport) // Using raylib as a Win32 shared library (.dll) + #else + #define RMAPI extern inline // Provide external definition + #endif +#elif defined(RAYMATH_STATIC_INLINE) + #define RMAPI static inline // Functions may be inlined, no external out-of-line definition +#else + #if defined(__TINYC__) + #define RMAPI static inline // plain inline not supported by tinycc (See issue #435) + #else + #define RMAPI inline // Functions may be inlined or external definition used + #endif +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#ifndef PI + #define PI 3.14159265358979323846f +#endif + +#ifndef EPSILON + #define EPSILON 0.000001f +#endif + +#ifndef DEG2RAD + #define DEG2RAD (PI/180.0f) +#endif + +#ifndef RAD2DEG + #define RAD2DEG (180.0f/PI) +#endif + +// Get float vector for Matrix +#ifndef MatrixToFloat + #define MatrixToFloat(mat) (MatrixToFloatV(mat).v) +#endif + +// Get float vector for Vector3 +#ifndef Vector3ToFloat + #define Vector3ToFloat(vec) (Vector3ToFloatV(vec).v) +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +#if !defined(RL_VECTOR2_TYPE) +// Vector2 type +typedef struct Vector2 { + float x; + float y; +} Vector2; +#define RL_VECTOR2_TYPE +#endif + +#if !defined(RL_VECTOR3_TYPE) +// Vector3 type +typedef struct Vector3 { + float x; + float y; + float z; +} Vector3; +#define RL_VECTOR3_TYPE +#endif + +#if !defined(RL_VECTOR4_TYPE) +// Vector4 type +typedef struct Vector4 { + float x; + float y; + float z; + float w; +} Vector4; +#define RL_VECTOR4_TYPE +#endif + +#if !defined(RL_QUATERNION_TYPE) +// Quaternion type +typedef Vector4 Quaternion; +#define RL_QUATERNION_TYPE +#endif + +#if !defined(RL_MATRIX_TYPE) +// Matrix type (OpenGL style 4x4 - right handed, column major) +typedef struct Matrix { + float m0, m4, m8, m12; // Matrix first row (4 components) + float m1, m5, m9, m13; // Matrix second row (4 components) + float m2, m6, m10, m14; // Matrix third row (4 components) + float m3, m7, m11, m15; // Matrix fourth row (4 components) +} Matrix; +#define RL_MATRIX_TYPE +#endif + +// NOTE: Helper types to be used instead of array return types for *ToFloat functions +#if !defined(RL_FLOAT3_TYPE) +typedef struct float3 { + float v[3]; +} float3; +#define RL_FLOAT3_TYPE +#endif + +#if !defined(RL_FLOAT16_TYPE) +typedef struct float16 { + float v[16]; +} float16; +#define RL_FLOAT16_TYPE +#endif + +#include // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), floor(), fminf(), fmaxf(), fabsf() + +#if RAYMATH_USE_SIMD_INTRINSICS + // SIMD is used on the most costly raymath function MatrixMultiply() + // NOTE: Only SSE intrinsics support implemented + // TODO: Consider support for other SIMD intrinsics: + // - SSEx, AVX, AVX2, FMA, NEON, RVV + /* + #if defined(__SSE4_2__) + #include + #define RAYMATH_SSE42_ENABLED + #elif defined(__SSE4_1__) + #include + #define RAYMATH_SSE41_ENABLED + #elif defined(__SSSE3__) + #include + #define RAYMATH_SSSE3_ENABLED + #elif defined(__SSE3__) + #include + #define RAYMATH_SSE3_ENABLED + #elif defined(__SSE2__) || (defined(_M_AMD64) || defined(_M_X64)) // SSE2 x64 + #include + #define RAYMATH_SSE2_ENABLED + #endif + */ + #if defined(__SSE__) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 1)) + #include + #define RAYMATH_SSE_ENABLED + #endif +#endif + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Utils math +//---------------------------------------------------------------------------------- + +// Clamp float value +RMAPI float Clamp(float value, float min, float max) +{ + float result = (value < min)? min : value; + + if (result > max) result = max; + + return result; +} + +// Calculate linear interpolation between two floats +RMAPI float Lerp(float start, float end, float amount) +{ + float result = start + amount*(end - start); + + return result; +} + +// Normalize input value within input range +RMAPI float Normalize(float value, float start, float end) +{ + float result = (value - start)/(end - start); + + return result; +} + +// Remap input value within input range to output range +RMAPI float Remap(float value, float inputStart, float inputEnd, float outputStart, float outputEnd) +{ + float result = (value - inputStart)/(inputEnd - inputStart)*(outputEnd - outputStart) + outputStart; + + return result; +} + +// Wrap input value from min to max +RMAPI float Wrap(float value, float min, float max) +{ + float result = value - (max - min)*floorf((value - min)/(max - min)); + + return result; +} + +// Check whether two given floats are almost equal +RMAPI int FloatEquals(float x, float y) +{ +#if !defined(EPSILON) + #define EPSILON 0.000001f +#endif + + int result = (fabsf(x - y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(x), fabsf(y)))); + + return result; +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Vector2 math +//---------------------------------------------------------------------------------- + +// Vector with components value 0.0f +RMAPI Vector2 Vector2Zero(void) +{ + Vector2 result = { 0.0f, 0.0f }; + + return result; +} + +// Vector with components value 1.0f +RMAPI Vector2 Vector2One(void) +{ + Vector2 result = { 1.0f, 1.0f }; + + return result; +} + +// Add two vectors (v1 + v2) +RMAPI Vector2 Vector2Add(Vector2 v1, Vector2 v2) +{ + Vector2 result = { v1.x + v2.x, v1.y + v2.y }; + + return result; +} + +// Add vector and float value +RMAPI Vector2 Vector2AddValue(Vector2 v, float add) +{ + Vector2 result = { v.x + add, v.y + add }; + + return result; +} + +// Subtract two vectors (v1 - v2) +RMAPI Vector2 Vector2Subtract(Vector2 v1, Vector2 v2) +{ + Vector2 result = { v1.x - v2.x, v1.y - v2.y }; + + return result; +} + +// Subtract vector by float value +RMAPI Vector2 Vector2SubtractValue(Vector2 v, float sub) +{ + Vector2 result = { v.x - sub, v.y - sub }; + + return result; +} + +// Calculate vector length +RMAPI float Vector2Length(Vector2 v) +{ + float result = sqrtf((v.x*v.x) + (v.y*v.y)); + + return result; +} + +// Calculate vector square length +RMAPI float Vector2LengthSqr(Vector2 v) +{ + float result = (v.x*v.x) + (v.y*v.y); + + return result; +} + +// Calculate two vectors dot product +RMAPI float Vector2DotProduct(Vector2 v1, Vector2 v2) +{ + float result = (v1.x*v2.x + v1.y*v2.y); + + return result; +} + +// Calculate two vectors cross product +RMAPI float Vector2CrossProduct(Vector2 v1, Vector2 v2) +{ + float result = (v1.x*v2.y - v1.y*v2.x); + + return result; +} + +// Calculate distance between two vectors +RMAPI float Vector2Distance(Vector2 v1, Vector2 v2) +{ + float result = sqrtf((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y)); + + return result; +} + +// Calculate square distance between two vectors +RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2) +{ + float result = ((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y)); + + return result; +} + +// Calculate the signed angle from v1 to v2, relative to the origin (0, 0) +// NOTE: Coordinate system convention: positive X right, positive Y down +// positive angles appear clockwise, and negative angles appear counterclockwise +RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) +{ + float result = 0.0f; + + float dot = v1.x*v2.x + v1.y*v2.y; + float det = v1.x*v2.y - v1.y*v2.x; + + result = atan2f(det, dot); + + return result; +} + +// Calculate angle defined by a two vectors line +// NOTE: Parameters need to be normalized +// Current implementation should be aligned with glm::angle +RMAPI float Vector2LineAngle(Vector2 start, Vector2 end) +{ + float result = 0.0f; + + // TODO(10/9/2023): Currently angles move clockwise, determine if this is wanted behavior + result = -atan2f(end.y - start.y, end.x - start.x); + + return result; +} + +// Scale vector (multiply by value) +RMAPI Vector2 Vector2Scale(Vector2 v, float scale) +{ + Vector2 result = { v.x*scale, v.y*scale }; + + return result; +} + +// Multiply vector by vector +RMAPI Vector2 Vector2Multiply(Vector2 v1, Vector2 v2) +{ + Vector2 result = { v1.x*v2.x, v1.y*v2.y }; + + return result; +} + +// Negate vector +RMAPI Vector2 Vector2Negate(Vector2 v) +{ + Vector2 result = { -v.x, -v.y }; + + return result; +} + +// Divide vector by vector +RMAPI Vector2 Vector2Divide(Vector2 v1, Vector2 v2) +{ + Vector2 result = { v1.x/v2.x, v1.y/v2.y }; + + return result; +} + +// Normalize provided vector +RMAPI Vector2 Vector2Normalize(Vector2 v) +{ + Vector2 result = { 0 }; + float length = sqrtf((v.x*v.x) + (v.y*v.y)); + + if (length > 0) + { + float ilength = 1.0f/length; + result.x = v.x*ilength; + result.y = v.y*ilength; + } + + return result; +} + +// Transforms a Vector2 by a given Matrix +RMAPI Vector2 Vector2Transform(Vector2 v, Matrix mat) +{ + Vector2 result = { 0 }; + + float x = v.x; + float y = v.y; + float z = 0; + + result.x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12; + result.y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13; + + return result; +} + +// Calculate linear interpolation between two vectors +RMAPI Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount) +{ + Vector2 result = { 0 }; + + result.x = v1.x + amount*(v2.x - v1.x); + result.y = v1.y + amount*(v2.y - v1.y); + + return result; +} + +// Calculate reflected vector to normal +RMAPI Vector2 Vector2Reflect(Vector2 v, Vector2 normal) +{ + Vector2 result = { 0 }; + + float dotProduct = (v.x*normal.x + v.y*normal.y); // Dot product + + result.x = v.x - (2.0f*normal.x)*dotProduct; + result.y = v.y - (2.0f*normal.y)*dotProduct; + + return result; +} + +// Get min value for each pair of components +RMAPI Vector2 Vector2Min(Vector2 v1, Vector2 v2) +{ + Vector2 result = { 0 }; + + result.x = fminf(v1.x, v2.x); + result.y = fminf(v1.y, v2.y); + + return result; +} + +// Get max value for each pair of components +RMAPI Vector2 Vector2Max(Vector2 v1, Vector2 v2) +{ + Vector2 result = { 0 }; + + result.x = fmaxf(v1.x, v2.x); + result.y = fmaxf(v1.y, v2.y); + + return result; +} + +// Rotate vector by angle +RMAPI Vector2 Vector2Rotate(Vector2 v, float angle) +{ + Vector2 result = { 0 }; + + float cosres = cosf(angle); + float sinres = sinf(angle); + + result.x = v.x*cosres - v.y*sinres; + result.y = v.x*sinres + v.y*cosres; + + return result; +} + +// Move Vector towards target +RMAPI Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance) +{ + Vector2 result = { 0 }; + + float dx = target.x - v.x; + float dy = target.y - v.y; + float value = (dx*dx) + (dy*dy); + + if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) return target; + + float dist = sqrtf(value); + + result.x = v.x + dx/dist*maxDistance; + result.y = v.y + dy/dist*maxDistance; + + return result; +} + +// Invert the given vector +RMAPI Vector2 Vector2Invert(Vector2 v) +{ + Vector2 result = { 1.0f/v.x, 1.0f/v.y }; + + return result; +} + +// Clamp the components of the vector between +// min and max values specified by the given vectors +RMAPI Vector2 Vector2Clamp(Vector2 v, Vector2 min, Vector2 max) +{ + Vector2 result = { 0 }; + + result.x = fminf(max.x, fmaxf(min.x, v.x)); + result.y = fminf(max.y, fmaxf(min.y, v.y)); + + return result; +} + +// Clamp the magnitude of the vector between two min and max values +RMAPI Vector2 Vector2ClampValue(Vector2 v, float min, float max) +{ + Vector2 result = v; + + float length = (v.x*v.x) + (v.y*v.y); + if (length > 0.0f) + { + length = sqrtf(length); + + float scale = 1; // By default, 1 as the neutral element + if (length < min) scale = min/length; + else if (length > max) scale = max/length; + + result.x = v.x*scale; + result.y = v.y*scale; + } + + return result; +} + +// Check whether two given vectors are almost equal +RMAPI int Vector2Equals(Vector2 p, Vector2 q) +{ +#if !defined(EPSILON) + #define EPSILON 0.000001f +#endif + + int result = ((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) && + ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))); + + return result; +} + +// 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 +RMAPI Vector2 Vector2Refract(Vector2 v, Vector2 n, float r) +{ + Vector2 result = { 0 }; + + float dot = v.x*n.x + v.y*n.y; + float d = 1.0f - r*r*(1.0f - dot*dot); + + if (d >= 0.0f) + { + d = sqrtf(d); + v.x = r*v.x - (r*dot + d)*n.x; + v.y = r*v.y - (r*dot + d)*n.y; + + result = v; + } + + return result; +} + + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Vector3 math +//---------------------------------------------------------------------------------- + +// Vector with components value 0.0f +RMAPI Vector3 Vector3Zero(void) +{ + Vector3 result = { 0.0f, 0.0f, 0.0f }; + + return result; +} + +// Vector with components value 1.0f +RMAPI Vector3 Vector3One(void) +{ + Vector3 result = { 1.0f, 1.0f, 1.0f }; + + return result; +} + +// Add two vectors +RMAPI Vector3 Vector3Add(Vector3 v1, Vector3 v2) +{ + Vector3 result = { v1.x + v2.x, v1.y + v2.y, v1.z + v2.z }; + + return result; +} + +// Add vector and float value +RMAPI Vector3 Vector3AddValue(Vector3 v, float add) +{ + Vector3 result = { v.x + add, v.y + add, v.z + add }; + + return result; +} + +// Subtract two vectors +RMAPI Vector3 Vector3Subtract(Vector3 v1, Vector3 v2) +{ + Vector3 result = { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z }; + + return result; +} + +// Subtract vector by float value +RMAPI Vector3 Vector3SubtractValue(Vector3 v, float sub) +{ + Vector3 result = { v.x - sub, v.y - sub, v.z - sub }; + + return result; +} + +// Multiply vector by scalar +RMAPI Vector3 Vector3Scale(Vector3 v, float scalar) +{ + Vector3 result = { v.x*scalar, v.y*scalar, v.z*scalar }; + + return result; +} + +// Multiply vector by vector +RMAPI Vector3 Vector3Multiply(Vector3 v1, Vector3 v2) +{ + Vector3 result = { v1.x*v2.x, v1.y*v2.y, v1.z*v2.z }; + + return result; +} + +// Calculate two vectors cross product +RMAPI Vector3 Vector3CrossProduct(Vector3 v1, Vector3 v2) +{ + Vector3 result = { v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x }; + + return result; +} + +// Calculate one vector perpendicular vector +RMAPI Vector3 Vector3Perpendicular(Vector3 v) +{ + Vector3 result = { 0 }; + + float min = fabsf(v.x); + Vector3 cardinalAxis = {1.0f, 0.0f, 0.0f}; + + if (fabsf(v.y) < min) + { + min = fabsf(v.y); + Vector3 tmp = {0.0f, 1.0f, 0.0f}; + cardinalAxis = tmp; + } + + if (fabsf(v.z) < min) + { + Vector3 tmp = {0.0f, 0.0f, 1.0f}; + cardinalAxis = tmp; + } + + // Cross product between vectors + result.x = v.y*cardinalAxis.z - v.z*cardinalAxis.y; + result.y = v.z*cardinalAxis.x - v.x*cardinalAxis.z; + result.z = v.x*cardinalAxis.y - v.y*cardinalAxis.x; + + return result; +} + +// Calculate vector length +RMAPI float Vector3Length(const Vector3 v) +{ + float result = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); + + return result; +} + +// Calculate vector square length +RMAPI float Vector3LengthSqr(const Vector3 v) +{ + float result = v.x*v.x + v.y*v.y + v.z*v.z; + + return result; +} + +// Calculate two vectors dot product +RMAPI float Vector3DotProduct(Vector3 v1, Vector3 v2) +{ + float result = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); + + return result; +} + +// Calculate distance between two vectors +RMAPI float Vector3Distance(Vector3 v1, Vector3 v2) +{ + float result = 0.0f; + + float dx = v2.x - v1.x; + float dy = v2.y - v1.y; + float dz = v2.z - v1.z; + result = sqrtf(dx*dx + dy*dy + dz*dz); + + return result; +} + +// Calculate square distance between two vectors +RMAPI float Vector3DistanceSqr(Vector3 v1, Vector3 v2) +{ + float result = 0.0f; + + float dx = v2.x - v1.x; + float dy = v2.y - v1.y; + float dz = v2.z - v1.z; + result = dx*dx + dy*dy + dz*dz; + + return result; +} + +// Calculate angle between two vectors +RMAPI float Vector3Angle(Vector3 v1, Vector3 v2) +{ + float result = 0.0f; + + Vector3 cross = { v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x }; + float len = sqrtf(cross.x*cross.x + cross.y*cross.y + cross.z*cross.z); + float dot = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); + result = atan2f(len, dot); + + return result; +} + +// Negate provided vector (invert direction) +RMAPI Vector3 Vector3Negate(Vector3 v) +{ + Vector3 result = { -v.x, -v.y, -v.z }; + + return result; +} + +// Divide vector by vector +RMAPI Vector3 Vector3Divide(Vector3 v1, Vector3 v2) +{ + Vector3 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z }; + + return result; +} + +// Normalize provided vector +RMAPI Vector3 Vector3Normalize(Vector3 v) +{ + Vector3 result = v; + + float length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); + if (length != 0.0f) + { + float ilength = 1.0f/length; + + result.x *= ilength; + result.y *= ilength; + result.z *= ilength; + } + + return result; +} + +//Calculate the projection of the vector v1 on to v2 +RMAPI Vector3 Vector3Project(Vector3 v1, Vector3 v2) +{ + Vector3 result = { 0 }; + + float v1dv2 = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); + float v2dv2 = (v2.x*v2.x + v2.y*v2.y + v2.z*v2.z); + + float mag = v1dv2/v2dv2; + + result.x = v2.x*mag; + result.y = v2.y*mag; + result.z = v2.z*mag; + + return result; +} + +//Calculate the rejection of the vector v1 on to v2 +RMAPI Vector3 Vector3Reject(Vector3 v1, Vector3 v2) +{ + Vector3 result = { 0 }; + + float v1dv2 = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z); + float v2dv2 = (v2.x*v2.x + v2.y*v2.y + v2.z*v2.z); + + float mag = v1dv2/v2dv2; + + result.x = v1.x - (v2.x*mag); + result.y = v1.y - (v2.y*mag); + result.z = v1.z - (v2.z*mag); + + return result; +} + +// Orthonormalize provided vectors +// Makes vectors normalized and orthogonal to each other +// Gram-Schmidt function implementation +RMAPI void Vector3OrthoNormalize(Vector3 *v1, Vector3 *v2) +{ + float length = 0.0f; + float ilength = 0.0f; + + // Vector3Normalize(*v1); + Vector3 v = *v1; + length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); + if (length == 0.0f) length = 1.0f; + ilength = 1.0f/length; + v1->x *= ilength; + v1->y *= ilength; + v1->z *= ilength; + + // Vector3CrossProduct(*v1, *v2) + Vector3 vn1 = { v1->y*v2->z - v1->z*v2->y, v1->z*v2->x - v1->x*v2->z, v1->x*v2->y - v1->y*v2->x }; + + // Vector3Normalize(vn1); + v = vn1; + length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); + if (length == 0.0f) length = 1.0f; + ilength = 1.0f/length; + vn1.x *= ilength; + vn1.y *= ilength; + vn1.z *= ilength; + + // Vector3CrossProduct(vn1, *v1) + Vector3 vn2 = { vn1.y*v1->z - vn1.z*v1->y, vn1.z*v1->x - vn1.x*v1->z, vn1.x*v1->y - vn1.y*v1->x }; + + *v2 = vn2; +} + +// Transforms a Vector3 by a given Matrix +RMAPI Vector3 Vector3Transform(Vector3 v, Matrix mat) +{ + Vector3 result = { 0 }; + + float x = v.x; + float y = v.y; + float z = v.z; + + result.x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12; + result.y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13; + result.z = mat.m2*x + mat.m6*y + mat.m10*z + mat.m14; + + return result; +} + +// Transform a vector by quaternion rotation +RMAPI Vector3 Vector3RotateByQuaternion(Vector3 v, Quaternion q) +{ + Vector3 result = { 0 }; + + result.x = v.x*(q.x*q.x + q.w*q.w - q.y*q.y - q.z*q.z) + v.y*(2*q.x*q.y - 2*q.w*q.z) + v.z*(2*q.x*q.z + 2*q.w*q.y); + result.y = v.x*(2*q.w*q.z + 2*q.x*q.y) + v.y*(q.w*q.w - q.x*q.x + q.y*q.y - q.z*q.z) + v.z*(-2*q.w*q.x + 2*q.y*q.z); + result.z = v.x*(-2*q.w*q.y + 2*q.x*q.z) + v.y*(2*q.w*q.x + 2*q.y*q.z)+ v.z*(q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z); + + return result; +} + +// Rotates a vector around an axis +RMAPI Vector3 Vector3RotateByAxisAngle(Vector3 v, Vector3 axis, float angle) +{ + // Using Euler-Rodrigues Formula + // Ref.: https://en.wikipedia.org/w/index.php?title=Euler%E2%80%93Rodrigues_formula + + Vector3 result = v; + + // Vector3Normalize(axis); + float length = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z); + if (length == 0.0f) length = 1.0f; + float ilength = 1.0f/length; + axis.x *= ilength; + axis.y *= ilength; + axis.z *= ilength; + + angle /= 2.0f; + float a = sinf(angle); + float b = axis.x*a; + float c = axis.y*a; + float d = axis.z*a; + a = cosf(angle); + Vector3 w = { b, c, d }; + + // Vector3CrossProduct(w, v) + Vector3 wv = { w.y*v.z - w.z*v.y, w.z*v.x - w.x*v.z, w.x*v.y - w.y*v.x }; + + // Vector3CrossProduct(w, wv) + Vector3 wwv = { w.y*wv.z - w.z*wv.y, w.z*wv.x - w.x*wv.z, w.x*wv.y - w.y*wv.x }; + + // Vector3Scale(wv, 2*a) + a *= 2; + wv.x *= a; + wv.y *= a; + wv.z *= a; + + // Vector3Scale(wwv, 2) + wwv.x *= 2; + wwv.y *= 2; + wwv.z *= 2; + + result.x += wv.x; + result.y += wv.y; + result.z += wv.z; + + result.x += wwv.x; + result.y += wwv.y; + result.z += wwv.z; + + return result; +} + +// Move Vector towards target +RMAPI Vector3 Vector3MoveTowards(Vector3 v, Vector3 target, float maxDistance) +{ + Vector3 result = { 0 }; + + float dx = target.x - v.x; + float dy = target.y - v.y; + float dz = target.z - v.z; + float value = (dx*dx) + (dy*dy) + (dz*dz); + + if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) return target; + + float dist = sqrtf(value); + + result.x = v.x + dx/dist*maxDistance; + result.y = v.y + dy/dist*maxDistance; + result.z = v.z + dz/dist*maxDistance; + + return result; +} + +// Calculate linear interpolation between two vectors +RMAPI Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount) +{ + Vector3 result = { 0 }; + + result.x = v1.x + amount*(v2.x - v1.x); + result.y = v1.y + amount*(v2.y - v1.y); + result.z = v1.z + amount*(v2.z - v1.z); + + return result; +} + +// 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 +RMAPI Vector3 Vector3CubicHermite(Vector3 v1, Vector3 tangent1, Vector3 v2, Vector3 tangent2, float amount) +{ + Vector3 result = { 0 }; + + float amountPow2 = amount*amount; + float amountPow3 = amount*amount*amount; + + result.x = (2*amountPow3 - 3*amountPow2 + 1)*v1.x + (amountPow3 - 2*amountPow2 + amount)*tangent1.x + (-2*amountPow3 + 3*amountPow2)*v2.x + (amountPow3 - amountPow2)*tangent2.x; + result.y = (2*amountPow3 - 3*amountPow2 + 1)*v1.y + (amountPow3 - 2*amountPow2 + amount)*tangent1.y + (-2*amountPow3 + 3*amountPow2)*v2.y + (amountPow3 - amountPow2)*tangent2.y; + result.z = (2*amountPow3 - 3*amountPow2 + 1)*v1.z + (amountPow3 - 2*amountPow2 + amount)*tangent1.z + (-2*amountPow3 + 3*amountPow2)*v2.z + (amountPow3 - amountPow2)*tangent2.z; + + return result; +} + +// Calculate reflected vector to normal +RMAPI Vector3 Vector3Reflect(Vector3 v, Vector3 normal) +{ + Vector3 result = { 0 }; + + // I is the original vector + // N is the normal of the incident plane + // R = I - (2*N*(DotProduct[I, N])) + + float dotProduct = (v.x*normal.x + v.y*normal.y + v.z*normal.z); + + result.x = v.x - (2.0f*normal.x)*dotProduct; + result.y = v.y - (2.0f*normal.y)*dotProduct; + result.z = v.z - (2.0f*normal.z)*dotProduct; + + return result; +} + +// Get min value for each pair of components +RMAPI Vector3 Vector3Min(Vector3 v1, Vector3 v2) +{ + Vector3 result = { 0 }; + + result.x = fminf(v1.x, v2.x); + result.y = fminf(v1.y, v2.y); + result.z = fminf(v1.z, v2.z); + + return result; +} + +// Get max value for each pair of components +RMAPI Vector3 Vector3Max(Vector3 v1, Vector3 v2) +{ + Vector3 result = { 0 }; + + result.x = fmaxf(v1.x, v2.x); + result.y = fmaxf(v1.y, v2.y); + result.z = fmaxf(v1.z, v2.z); + + return result; +} + +// 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 +RMAPI Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c) +{ + Vector3 result = { 0 }; + + Vector3 v0 = { b.x - a.x, b.y - a.y, b.z - a.z }; // Vector3Subtract(b, a) + Vector3 v1 = { c.x - a.x, c.y - a.y, c.z - a.z }; // Vector3Subtract(c, a) + Vector3 v2 = { p.x - a.x, p.y - a.y, p.z - a.z }; // Vector3Subtract(p, a) + float d00 = (v0.x*v0.x + v0.y*v0.y + v0.z*v0.z); // Vector3DotProduct(v0, v0) + float d01 = (v0.x*v1.x + v0.y*v1.y + v0.z*v1.z); // Vector3DotProduct(v0, v1) + float d11 = (v1.x*v1.x + v1.y*v1.y + v1.z*v1.z); // Vector3DotProduct(v1, v1) + float d20 = (v2.x*v0.x + v2.y*v0.y + v2.z*v0.z); // Vector3DotProduct(v2, v0) + float d21 = (v2.x*v1.x + v2.y*v1.y + v2.z*v1.z); // Vector3DotProduct(v2, v1) + + float denom = d00*d11 - d01*d01; + + result.y = (d11*d20 - d01*d21)/denom; + result.z = (d00*d21 - d01*d20)/denom; + result.x = 1.0f - (result.z + result.y); + + return result; +} + +// Projects a Vector3 from screen space into object space +// NOTE: Self-contained function, no other raymath functions are called +RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view) +{ + Vector3 result = { 0 }; + + // Calculate unprojected matrix (multiply view matrix by projection matrix) and invert it + Matrix matViewProj = { // MatrixMultiply(view, projection); + view.m0*projection.m0 + view.m1*projection.m4 + view.m2*projection.m8 + view.m3*projection.m12, + view.m0*projection.m1 + view.m1*projection.m5 + view.m2*projection.m9 + view.m3*projection.m13, + view.m0*projection.m2 + view.m1*projection.m6 + view.m2*projection.m10 + view.m3*projection.m14, + view.m0*projection.m3 + view.m1*projection.m7 + view.m2*projection.m11 + view.m3*projection.m15, + view.m4*projection.m0 + view.m5*projection.m4 + view.m6*projection.m8 + view.m7*projection.m12, + view.m4*projection.m1 + view.m5*projection.m5 + view.m6*projection.m9 + view.m7*projection.m13, + view.m4*projection.m2 + view.m5*projection.m6 + view.m6*projection.m10 + view.m7*projection.m14, + view.m4*projection.m3 + view.m5*projection.m7 + view.m6*projection.m11 + view.m7*projection.m15, + view.m8*projection.m0 + view.m9*projection.m4 + view.m10*projection.m8 + view.m11*projection.m12, + view.m8*projection.m1 + view.m9*projection.m5 + view.m10*projection.m9 + view.m11*projection.m13, + view.m8*projection.m2 + view.m9*projection.m6 + view.m10*projection.m10 + view.m11*projection.m14, + view.m8*projection.m3 + view.m9*projection.m7 + view.m10*projection.m11 + view.m11*projection.m15, + view.m12*projection.m0 + view.m13*projection.m4 + view.m14*projection.m8 + view.m15*projection.m12, + view.m12*projection.m1 + view.m13*projection.m5 + view.m14*projection.m9 + view.m15*projection.m13, + view.m12*projection.m2 + view.m13*projection.m6 + view.m14*projection.m10 + view.m15*projection.m14, + view.m12*projection.m3 + view.m13*projection.m7 + view.m14*projection.m11 + view.m15*projection.m15 }; + + // Calculate inverted matrix -> MatrixInvert(matViewProj); + // Cache the matrix values (speed optimization) + float a00 = matViewProj.m0, a01 = matViewProj.m1, a02 = matViewProj.m2, a03 = matViewProj.m3; + float a10 = matViewProj.m4, a11 = matViewProj.m5, a12 = matViewProj.m6, a13 = matViewProj.m7; + float a20 = matViewProj.m8, a21 = matViewProj.m9, a22 = matViewProj.m10, a23 = matViewProj.m11; + float a30 = matViewProj.m12, a31 = matViewProj.m13, a32 = matViewProj.m14, a33 = matViewProj.m15; + + float b00 = a00*a11 - a01*a10; + float b01 = a00*a12 - a02*a10; + float b02 = a00*a13 - a03*a10; + float b03 = a01*a12 - a02*a11; + float b04 = a01*a13 - a03*a11; + float b05 = a02*a13 - a03*a12; + float b06 = a20*a31 - a21*a30; + float b07 = a20*a32 - a22*a30; + float b08 = a20*a33 - a23*a30; + float b09 = a21*a32 - a22*a31; + float b10 = a21*a33 - a23*a31; + float b11 = a22*a33 - a23*a32; + + // Calculate the invert determinant (inlined to avoid double-caching) + float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06); + + Matrix matViewProjInv = { + (a11*b11 - a12*b10 + a13*b09)*invDet, + (-a01*b11 + a02*b10 - a03*b09)*invDet, + (a31*b05 - a32*b04 + a33*b03)*invDet, + (-a21*b05 + a22*b04 - a23*b03)*invDet, + (-a10*b11 + a12*b08 - a13*b07)*invDet, + (a00*b11 - a02*b08 + a03*b07)*invDet, + (-a30*b05 + a32*b02 - a33*b01)*invDet, + (a20*b05 - a22*b02 + a23*b01)*invDet, + (a10*b10 - a11*b08 + a13*b06)*invDet, + (-a00*b10 + a01*b08 - a03*b06)*invDet, + (a30*b04 - a31*b02 + a33*b00)*invDet, + (-a20*b04 + a21*b02 - a23*b00)*invDet, + (-a10*b09 + a11*b07 - a12*b06)*invDet, + (a00*b09 - a01*b07 + a02*b06)*invDet, + (-a30*b03 + a31*b01 - a32*b00)*invDet, + (a20*b03 - a21*b01 + a22*b00)*invDet }; + + // Create quaternion from source point + Quaternion quat = { source.x, source.y, source.z, 1.0f }; + + // Multiply quat point by unprojected matrix + Quaternion qtransformed = { // QuaternionTransform(quat, matViewProjInv) + matViewProjInv.m0*quat.x + matViewProjInv.m4*quat.y + matViewProjInv.m8*quat.z + matViewProjInv.m12*quat.w, + matViewProjInv.m1*quat.x + matViewProjInv.m5*quat.y + matViewProjInv.m9*quat.z + matViewProjInv.m13*quat.w, + matViewProjInv.m2*quat.x + matViewProjInv.m6*quat.y + matViewProjInv.m10*quat.z + matViewProjInv.m14*quat.w, + matViewProjInv.m3*quat.x + matViewProjInv.m7*quat.y + matViewProjInv.m11*quat.z + matViewProjInv.m15*quat.w }; + + // Normalized world points in vectors + result.x = qtransformed.x/qtransformed.w; + result.y = qtransformed.y/qtransformed.w; + result.z = qtransformed.z/qtransformed.w; + + return result; +} + +// Get Vector3 as float array +RMAPI float3 Vector3ToFloatV(Vector3 v) +{ + float3 buffer = { 0 }; + + buffer.v[0] = v.x; + buffer.v[1] = v.y; + buffer.v[2] = v.z; + + return buffer; +} + +// Invert the given vector +RMAPI Vector3 Vector3Invert(Vector3 v) +{ + Vector3 result = { 1.0f/v.x, 1.0f/v.y, 1.0f/v.z }; + + return result; +} + +// Clamp the components of the vector between +// min and max values specified by the given vectors +RMAPI Vector3 Vector3Clamp(Vector3 v, Vector3 min, Vector3 max) +{ + Vector3 result = { 0 }; + + result.x = fminf(max.x, fmaxf(min.x, v.x)); + result.y = fminf(max.y, fmaxf(min.y, v.y)); + result.z = fminf(max.z, fmaxf(min.z, v.z)); + + return result; +} + +// Clamp the magnitude of the vector between two values +RMAPI Vector3 Vector3ClampValue(Vector3 v, float min, float max) +{ + Vector3 result = v; + + float length = (v.x*v.x) + (v.y*v.y) + (v.z*v.z); + if (length > 0.0f) + { + length = sqrtf(length); + + float scale = 1; // By default, 1 as the neutral element + if (length < min) scale = min/length; + else if (length > max) scale = max/length; + + result.x = v.x*scale; + result.y = v.y*scale; + result.z = v.z*scale; + } + + return result; +} + +// Check whether two given vectors are almost equal +RMAPI int Vector3Equals(Vector3 p, Vector3 q) +{ +#if !defined(EPSILON) + #define EPSILON 0.000001f +#endif + + int result = ((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) && + ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) && + ((fabsf(p.z - q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))); + + return result; +} + +// 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 +RMAPI Vector3 Vector3Refract(Vector3 v, Vector3 n, float r) +{ + Vector3 result = { 0 }; + + float dot = v.x*n.x + v.y*n.y + v.z*n.z; + float d = 1.0f - r*r*(1.0f - dot*dot); + + if (d >= 0.0f) + { + d = sqrtf(d); + v.x = r*v.x - (r*dot + d)*n.x; + v.y = r*v.y - (r*dot + d)*n.y; + v.z = r*v.z - (r*dot + d)*n.z; + + result = v; + } + + return result; +} + + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Vector4 math +//---------------------------------------------------------------------------------- +// Get vector zero +RMAPI Vector4 Vector4Zero(void) +{ + Vector4 result = { 0.0f, 0.0f, 0.0f, 0.0f }; + return result; +} + +// Get vector one +RMAPI Vector4 Vector4One(void) +{ + Vector4 result = { 1.0f, 1.0f, 1.0f, 1.0f }; + return result; +} + +// Add two vectors +RMAPI Vector4 Vector4Add(Vector4 v1, Vector4 v2) +{ + Vector4 result = { + v1.x + v2.x, + v1.y + v2.y, + v1.z + v2.z, + v1.w + v2.w + }; + return result; +} + +// Add value to vector components +RMAPI Vector4 Vector4AddValue(Vector4 v, float add) +{ + Vector4 result = { + v.x + add, + v.y + add, + v.z + add, + v.w + add + }; + return result; +} + +// Substract vectors +RMAPI Vector4 Vector4Subtract(Vector4 v1, Vector4 v2) +{ + Vector4 result = { + v1.x - v2.x, + v1.y - v2.y, + v1.z - v2.z, + v1.w - v2.w + }; + return result; +} + +// Substract value from vector components +RMAPI Vector4 Vector4SubtractValue(Vector4 v, float add) +{ + Vector4 result = { + v.x - add, + v.y - add, + v.z - add, + v.w - add + }; + return result; +} + +// Vector length +RMAPI float Vector4Length(Vector4 v) +{ + float result = sqrtf((v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w)); + return result; +} + +// Vector square length +RMAPI float Vector4LengthSqr(Vector4 v) +{ + float result = (v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w); + return result; +} + +// Vectors dot product +RMAPI float Vector4DotProduct(Vector4 v1, Vector4 v2) +{ + float result = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z + v1.w*v2.w); + return result; +} + +// Calculate distance between two vectors +RMAPI float Vector4Distance(Vector4 v1, Vector4 v2) +{ + float result = sqrtf( + (v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y) + + (v1.z - v2.z)*(v1.z - v2.z) + (v1.w - v2.w)*(v1.w - v2.w)); + return result; +} + +// Calculate square distance between two vectors +RMAPI float Vector4DistanceSqr(Vector4 v1, Vector4 v2) +{ + float result = + (v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y) + + (v1.z - v2.z)*(v1.z - v2.z) + (v1.w - v2.w)*(v1.w - v2.w); + + return result; +} + +// Scale vector components by value (multiply) +RMAPI Vector4 Vector4Scale(Vector4 v, float scale) +{ + Vector4 result = { v.x*scale, v.y*scale, v.z*scale, v.w*scale }; + return result; +} + +// Multiply vector by vector +RMAPI Vector4 Vector4Multiply(Vector4 v1, Vector4 v2) +{ + Vector4 result = { v1.x*v2.x, v1.y*v2.y, v1.z*v2.z, v1.w*v2.w }; + return result; +} + +// Negate vector +RMAPI Vector4 Vector4Negate(Vector4 v) +{ + Vector4 result = { -v.x, -v.y, -v.z, -v.w }; + return result; +} + +// Divide vector by vector +RMAPI Vector4 Vector4Divide(Vector4 v1, Vector4 v2) +{ + Vector4 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z, v1.w/v2.w }; + return result; +} + +// Normalize provided vector +RMAPI Vector4 Vector4Normalize(Vector4 v) +{ + Vector4 result = { 0 }; + float length = sqrtf((v.x*v.x) + (v.y*v.y) + (v.z*v.z) + (v.w*v.w)); + + if (length > 0) + { + float ilength = 1.0f/length; + result.x = v.x*ilength; + result.y = v.y*ilength; + result.z = v.z*ilength; + result.w = v.w*ilength; + } + + return result; +} + +// Get min value for each pair of components +RMAPI Vector4 Vector4Min(Vector4 v1, Vector4 v2) +{ + Vector4 result = { 0 }; + + result.x = fminf(v1.x, v2.x); + result.y = fminf(v1.y, v2.y); + result.z = fminf(v1.z, v2.z); + result.w = fminf(v1.w, v2.w); + + return result; +} + +// Get max value for each pair of components +RMAPI Vector4 Vector4Max(Vector4 v1, Vector4 v2) +{ + Vector4 result = { 0 }; + + result.x = fmaxf(v1.x, v2.x); + result.y = fmaxf(v1.y, v2.y); + result.z = fmaxf(v1.z, v2.z); + result.w = fmaxf(v1.w, v2.w); + + return result; +} + +// Calculate linear interpolation between two vectors +RMAPI Vector4 Vector4Lerp(Vector4 v1, Vector4 v2, float amount) +{ + Vector4 result = { 0 }; + + result.x = v1.x + amount*(v2.x - v1.x); + result.y = v1.y + amount*(v2.y - v1.y); + result.z = v1.z + amount*(v2.z - v1.z); + result.w = v1.w + amount*(v2.w - v1.w); + + return result; +} + +// Move Vector towards target +RMAPI Vector4 Vector4MoveTowards(Vector4 v, Vector4 target, float maxDistance) +{ + Vector4 result = { 0 }; + + float dx = target.x - v.x; + float dy = target.y - v.y; + float dz = target.z - v.z; + float dw = target.w - v.w; + float value = (dx*dx) + (dy*dy) + (dz*dz) + (dw*dw); + + if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) return target; + + float dist = sqrtf(value); + + result.x = v.x + dx/dist*maxDistance; + result.y = v.y + dy/dist*maxDistance; + result.z = v.z + dz/dist*maxDistance; + result.w = v.w + dw/dist*maxDistance; + + return result; +} + +// Invert the given vector +RMAPI Vector4 Vector4Invert(Vector4 v) +{ + Vector4 result = { 1.0f/v.x, 1.0f/v.y, 1.0f/v.z, 1.0f/v.w }; + return result; +} + +// Check whether two given vectors are almost equal +RMAPI int Vector4Equals(Vector4 p, Vector4 q) +{ +#if !defined(EPSILON) + #define EPSILON 0.000001f +#endif + + int result = ((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) && + ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) && + ((fabsf(p.z - q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))) && + ((fabsf(p.w - q.w)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.w), fabsf(q.w))))); + return result; +} + + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Matrix math +//---------------------------------------------------------------------------------- + +// Compute matrix determinant +RMAPI float MatrixDeterminant(Matrix mat) +{ + float result = 0.0f; +/* + // Cache the matrix values (speed optimization) + float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; + float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7; + float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; + float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15; + + // NOTE: It takes 72 multiplication to calculate 4x4 matrix determinant + result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 + + a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 + + a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 + + a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 + + a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 + + a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33; +*/ + // Using Laplace expansion (https://en.wikipedia.org/wiki/Laplace_expansion), + // previous operation can be simplified to 40 multiplications, decreasing matrix + // size from 4x4 to 2x2 using minors + + // Cache the matrix values (speed optimization) + float m0 = mat.m0, m1 = mat.m1, m2 = mat.m2, m3 = mat.m3; + float m4 = mat.m4, m5 = mat.m5, m6 = mat.m6, m7 = mat.m7; + float m8 = mat.m8, m9 = mat.m9, m10 = mat.m10, m11 = mat.m11; + float m12 = mat.m12, m13 = mat.m13, m14 = mat.m14, m15 = mat.m15; + + result = (m0*((m5*(m10*m15 - m11*m14) - m9*(m6*m15 - m7*m14) + m13*(m6*m11 - m7*m10))) - + m4*((m1*(m10*m15 - m11*m14) - m9*(m2*m15 - m3*m14) + m13*(m2*m11 - m3*m10))) + + m8*((m1*(m6*m15 - m7*m14) - m5*(m2*m15 - m3*m14) + m13*(m2*m7 - m3*m6))) - + m12*((m1*(m6*m11 - m7*m10) - m5*(m2*m11 - m3*m10) + m9*(m2*m7 - m3*m6)))); + + return result; +} + +// Get the trace of the matrix (sum of the values along the diagonal) +RMAPI float MatrixTrace(Matrix mat) +{ + float result = (mat.m0 + mat.m5 + mat.m10 + mat.m15); + + return result; +} + +// Transposes provided matrix +RMAPI Matrix MatrixTranspose(Matrix mat) +{ + Matrix result = { 0 }; + + result.m0 = mat.m0; + result.m1 = mat.m4; + result.m2 = mat.m8; + result.m3 = mat.m12; + result.m4 = mat.m1; + result.m5 = mat.m5; + result.m6 = mat.m9; + result.m7 = mat.m13; + result.m8 = mat.m2; + result.m9 = mat.m6; + result.m10 = mat.m10; + result.m11 = mat.m14; + result.m12 = mat.m3; + result.m13 = mat.m7; + result.m14 = mat.m11; + result.m15 = mat.m15; + + return result; +} + +// Invert provided matrix +RMAPI Matrix MatrixInvert(Matrix mat) +{ + Matrix result = { 0 }; + + // Cache the matrix values (speed optimization) + float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; + float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7; + float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; + float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15; + + float b00 = a00*a11 - a01*a10; + float b01 = a00*a12 - a02*a10; + float b02 = a00*a13 - a03*a10; + float b03 = a01*a12 - a02*a11; + float b04 = a01*a13 - a03*a11; + float b05 = a02*a13 - a03*a12; + float b06 = a20*a31 - a21*a30; + float b07 = a20*a32 - a22*a30; + float b08 = a20*a33 - a23*a30; + float b09 = a21*a32 - a22*a31; + float b10 = a21*a33 - a23*a31; + float b11 = a22*a33 - a23*a32; + + // Calculate the invert determinant (inlined to avoid double-caching) + float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06); + + result.m0 = (a11*b11 - a12*b10 + a13*b09)*invDet; + result.m1 = (-a01*b11 + a02*b10 - a03*b09)*invDet; + result.m2 = (a31*b05 - a32*b04 + a33*b03)*invDet; + result.m3 = (-a21*b05 + a22*b04 - a23*b03)*invDet; + result.m4 = (-a10*b11 + a12*b08 - a13*b07)*invDet; + result.m5 = (a00*b11 - a02*b08 + a03*b07)*invDet; + result.m6 = (-a30*b05 + a32*b02 - a33*b01)*invDet; + result.m7 = (a20*b05 - a22*b02 + a23*b01)*invDet; + result.m8 = (a10*b10 - a11*b08 + a13*b06)*invDet; + result.m9 = (-a00*b10 + a01*b08 - a03*b06)*invDet; + result.m10 = (a30*b04 - a31*b02 + a33*b00)*invDet; + result.m11 = (-a20*b04 + a21*b02 - a23*b00)*invDet; + result.m12 = (-a10*b09 + a11*b07 - a12*b06)*invDet; + result.m13 = (a00*b09 - a01*b07 + a02*b06)*invDet; + result.m14 = (-a30*b03 + a31*b01 - a32*b00)*invDet; + result.m15 = (a20*b03 - a21*b01 + a22*b00)*invDet; + + return result; +} + +// Get identity matrix +RMAPI Matrix MatrixIdentity(void) +{ + Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f }; + + return result; +} + +// Add two matrices +RMAPI Matrix MatrixAdd(Matrix left, Matrix right) +{ + Matrix result = { 0 }; + + result.m0 = left.m0 + right.m0; + result.m1 = left.m1 + right.m1; + result.m2 = left.m2 + right.m2; + result.m3 = left.m3 + right.m3; + result.m4 = left.m4 + right.m4; + result.m5 = left.m5 + right.m5; + result.m6 = left.m6 + right.m6; + result.m7 = left.m7 + right.m7; + result.m8 = left.m8 + right.m8; + result.m9 = left.m9 + right.m9; + result.m10 = left.m10 + right.m10; + result.m11 = left.m11 + right.m11; + result.m12 = left.m12 + right.m12; + result.m13 = left.m13 + right.m13; + result.m14 = left.m14 + right.m14; + result.m15 = left.m15 + right.m15; + + return result; +} + +// Subtract two matrices (left - right) +RMAPI Matrix MatrixSubtract(Matrix left, Matrix right) +{ + Matrix result = { 0 }; + + result.m0 = left.m0 - right.m0; + result.m1 = left.m1 - right.m1; + result.m2 = left.m2 - right.m2; + result.m3 = left.m3 - right.m3; + result.m4 = left.m4 - right.m4; + result.m5 = left.m5 - right.m5; + result.m6 = left.m6 - right.m6; + result.m7 = left.m7 - right.m7; + result.m8 = left.m8 - right.m8; + result.m9 = left.m9 - right.m9; + result.m10 = left.m10 - right.m10; + result.m11 = left.m11 - right.m11; + result.m12 = left.m12 - right.m12; + result.m13 = left.m13 - right.m13; + result.m14 = left.m14 - right.m14; + result.m15 = left.m15 - right.m15; + + return result; +} + +// Get two matrix multiplication +// NOTE: When multiplying matrices... the order matters! +RMAPI Matrix MatrixMultiply(Matrix left, Matrix right) +{ + Matrix result = { 0 }; + +#if defined(RAYMATH_SSE_ENABLED) + // Load left side and right side + __m128 c0 = _mm_set_ps(right.m12, right.m8, right.m4, right.m0); + __m128 c1 = _mm_set_ps(right.m13, right.m9, right.m5, right.m1); + __m128 c2 = _mm_set_ps(right.m14, right.m10, right.m6, right.m2); + __m128 c3 = _mm_set_ps(right.m15, right.m11, right.m7, right.m3); + + // Transpose so c0..c3 become *rows* of the right matrix in semantic order + _MM_TRANSPOSE4_PS(c0, c1, c2, c3); + + float tmp[4] = { 0 }; + __m128 row; + + // Row 0 of result: [m0, m1, m2, m3] + row = _mm_mul_ps(_mm_set1_ps(left.m0), c0); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m1), c1)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m2), c2)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m3), c3)); + _mm_storeu_ps(tmp, row); + result.m0 = tmp[0]; + result.m1 = tmp[1]; + result.m2 = tmp[2]; + result.m3 = tmp[3]; + + // Row 1 of result: [m4, m5, m6, m7] + row = _mm_mul_ps(_mm_set1_ps(left.m4), c0); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m5), c1)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m6), c2)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m7), c3)); + _mm_storeu_ps(tmp, row); + result.m4 = tmp[0]; + result.m5 = tmp[1]; + result.m6 = tmp[2]; + result.m7 = tmp[3]; + + // Row 2 of result: [m8, m9, m10, m11] + row = _mm_mul_ps(_mm_set1_ps(left.m8), c0); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m9), c1)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m10), c2)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m11), c3)); + _mm_storeu_ps(tmp, row); + result.m8 = tmp[0]; + result.m9 = tmp[1]; + result.m10 = tmp[2]; + result.m11 = tmp[3]; + + // Row 3 of result: [m12, m13, m14, m15] + row = _mm_mul_ps(_mm_set1_ps(left.m12), c0); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m13), c1)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m14), c2)); + row = _mm_add_ps(row, _mm_mul_ps(_mm_set1_ps(left.m15), c3)); + _mm_storeu_ps(tmp, row); + result.m12 = tmp[0]; + result.m13 = tmp[1]; + result.m14 = tmp[2]; + result.m15 = tmp[3]; +#else + result.m0 = left.m0*right.m0 + left.m1*right.m4 + left.m2*right.m8 + left.m3*right.m12; + result.m1 = left.m0*right.m1 + left.m1*right.m5 + left.m2*right.m9 + left.m3*right.m13; + result.m2 = left.m0*right.m2 + left.m1*right.m6 + left.m2*right.m10 + left.m3*right.m14; + result.m3 = left.m0*right.m3 + left.m1*right.m7 + left.m2*right.m11 + left.m3*right.m15; + result.m4 = left.m4*right.m0 + left.m5*right.m4 + left.m6*right.m8 + left.m7*right.m12; + result.m5 = left.m4*right.m1 + left.m5*right.m5 + left.m6*right.m9 + left.m7*right.m13; + result.m6 = left.m4*right.m2 + left.m5*right.m6 + left.m6*right.m10 + left.m7*right.m14; + result.m7 = left.m4*right.m3 + left.m5*right.m7 + left.m6*right.m11 + left.m7*right.m15; + result.m8 = left.m8*right.m0 + left.m9*right.m4 + left.m10*right.m8 + left.m11*right.m12; + result.m9 = left.m8*right.m1 + left.m9*right.m5 + left.m10*right.m9 + left.m11*right.m13; + result.m10 = left.m8*right.m2 + left.m9*right.m6 + left.m10*right.m10 + left.m11*right.m14; + result.m11 = left.m8*right.m3 + left.m9*right.m7 + left.m10*right.m11 + left.m11*right.m15; + result.m12 = left.m12*right.m0 + left.m13*right.m4 + left.m14*right.m8 + left.m15*right.m12; + result.m13 = left.m12*right.m1 + left.m13*right.m5 + left.m14*right.m9 + left.m15*right.m13; + result.m14 = left.m12*right.m2 + left.m13*right.m6 + left.m14*right.m10 + left.m15*right.m14; + result.m15 = left.m12*right.m3 + left.m13*right.m7 + left.m14*right.m11 + left.m15*right.m15; +#endif + + return result; +} + +// Multiply matrix components by value +RMAPI Matrix MatrixMultiplyValue(Matrix left, float value) +{ + Matrix result = { + left.m0*value, left.m4*value, left.m8*value, left.m12*value, + left.m1*value, left.m5*value, left.m9*value, left.m13*value, + left.m2*value, left.m6*value, left.m10*value, left.m14*value, + left.m3*value, left.m7*value, left.m11*value, left.m15*value + }; + + return result; +} + +// Get translation matrix +RMAPI Matrix MatrixTranslate(float x, float y, float z) +{ + Matrix result = { 1.0f, 0.0f, 0.0f, x, + 0.0f, 1.0f, 0.0f, y, + 0.0f, 0.0f, 1.0f, z, + 0.0f, 0.0f, 0.0f, 1.0f }; + + return result; +} + +// Create rotation matrix from axis and angle +// NOTE: Angle should be provided in radians +RMAPI Matrix MatrixRotate(Vector3 axis, float angle) +{ + Matrix result = { 0 }; + + float x = axis.x, y = axis.y, z = axis.z; + + float lengthSquared = x*x + y*y + z*z; + + if ((lengthSquared != 1.0f) && (lengthSquared != 0.0f)) + { + float ilength = 1.0f/sqrtf(lengthSquared); + x *= ilength; + y *= ilength; + z *= ilength; + } + + float sinres = sinf(angle); + float cosres = cosf(angle); + float t = 1.0f - cosres; + + result.m0 = x*x*t + cosres; + result.m1 = y*x*t + z*sinres; + result.m2 = z*x*t - y*sinres; + result.m3 = 0.0f; + + result.m4 = x*y*t - z*sinres; + result.m5 = y*y*t + cosres; + result.m6 = z*y*t + x*sinres; + result.m7 = 0.0f; + + result.m8 = x*z*t + y*sinres; + result.m9 = y*z*t - x*sinres; + result.m10 = z*z*t + cosres; + result.m11 = 0.0f; + + result.m12 = 0.0f; + result.m13 = 0.0f; + result.m14 = 0.0f; + result.m15 = 1.0f; + + return result; +} + +// Get x-rotation matrix +// NOTE: Angle must be provided in radians +RMAPI Matrix MatrixRotateX(float angle) +{ + Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() + + float cosres = cosf(angle); + float sinres = sinf(angle); + + result.m5 = cosres; + result.m6 = sinres; + result.m9 = -sinres; + result.m10 = cosres; + + return result; +} + +// Get y-rotation matrix +// NOTE: Angle must be provided in radians +RMAPI Matrix MatrixRotateY(float angle) +{ + Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() + + float cosres = cosf(angle); + float sinres = sinf(angle); + + result.m0 = cosres; + result.m2 = -sinres; + result.m8 = sinres; + result.m10 = cosres; + + return result; +} + +// Get z-rotation matrix +// NOTE: Angle must be provided in radians +RMAPI Matrix MatrixRotateZ(float angle) +{ + Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() + + float cosres = cosf(angle); + float sinres = sinf(angle); + + result.m0 = cosres; + result.m1 = sinres; + result.m4 = -sinres; + result.m5 = cosres; + + return result; +} + + +// Get xyz-rotation matrix +// NOTE: Angle must be provided in radians +RMAPI Matrix MatrixRotateXYZ(Vector3 angle) +{ + Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() + + float cosz = cosf(-angle.z); + float sinz = sinf(-angle.z); + float cosy = cosf(-angle.y); + float siny = sinf(-angle.y); + float cosx = cosf(-angle.x); + float sinx = sinf(-angle.x); + + result.m0 = cosz*cosy; + result.m1 = (cosz*siny*sinx) - (sinz*cosx); + result.m2 = (cosz*siny*cosx) + (sinz*sinx); + + result.m4 = sinz*cosy; + result.m5 = (sinz*siny*sinx) + (cosz*cosx); + result.m6 = (sinz*siny*cosx) - (cosz*sinx); + + result.m8 = -siny; + result.m9 = cosy*sinx; + result.m10= cosy*cosx; + + return result; +} + +// Get zyx-rotation matrix +// NOTE: Angle must be provided in radians +RMAPI Matrix MatrixRotateZYX(Vector3 angle) +{ + Matrix result = { 0 }; + + float cz = cosf(angle.z); + float sz = sinf(angle.z); + float cy = cosf(angle.y); + float sy = sinf(angle.y); + float cx = cosf(angle.x); + float sx = sinf(angle.x); + + result.m0 = cz*cy; + result.m4 = cz*sy*sx - cx*sz; + result.m8 = sz*sx + cz*cx*sy; + result.m12 = 0; + + result.m1 = cy*sz; + result.m5 = cz*cx + sz*sy*sx; + result.m9 = cx*sz*sy - cz*sx; + result.m13 = 0; + + result.m2 = -sy; + result.m6 = cy*sx; + result.m10 = cy*cx; + result.m14 = 0; + + result.m3 = 0; + result.m7 = 0; + result.m11 = 0; + result.m15 = 1; + + return result; +} + +// Get scaling matrix +RMAPI Matrix MatrixScale(float x, float y, float z) +{ + Matrix result = { x, 0.0f, 0.0f, 0.0f, + 0.0f, y, 0.0f, 0.0f, + 0.0f, 0.0f, z, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f }; + + return result; +} + +// Get perspective projection matrix +RMAPI Matrix MatrixFrustum(double left, double right, double bottom, double top, double nearPlane, double farPlane) +{ + Matrix result = { 0 }; + + float rl = (float)(right - left); + float tb = (float)(top - bottom); + float fn = (float)(farPlane - nearPlane); + + result.m0 = ((float)nearPlane*2.0f)/rl; + result.m1 = 0.0f; + result.m2 = 0.0f; + result.m3 = 0.0f; + + result.m4 = 0.0f; + result.m5 = ((float)nearPlane*2.0f)/tb; + result.m6 = 0.0f; + result.m7 = 0.0f; + + result.m8 = ((float)right + (float)left)/rl; + result.m9 = ((float)top + (float)bottom)/tb; + result.m10 = -((float)farPlane + (float)nearPlane)/fn; + result.m11 = -1.0f; + + result.m12 = 0.0f; + result.m13 = 0.0f; + result.m14 = -((float)farPlane*(float)nearPlane*2.0f)/fn; + result.m15 = 0.0f; + + return result; +} + +// Get perspective projection matrix +// NOTE: Fovy angle must be provided in radians +RMAPI Matrix MatrixPerspective(double fovY, double aspect, double nearPlane, double farPlane) +{ + Matrix result = { 0 }; + + double top = nearPlane*tan(fovY*0.5); + double bottom = -top; + double right = top*aspect; + double left = -right; + + // MatrixFrustum(-right, right, -top, top, near, far); + float rl = (float)(right - left); + float tb = (float)(top - bottom); + float fn = (float)(farPlane - nearPlane); + + result.m0 = ((float)nearPlane*2.0f)/rl; + result.m5 = ((float)nearPlane*2.0f)/tb; + result.m8 = ((float)right + (float)left)/rl; + result.m9 = ((float)top + (float)bottom)/tb; + result.m10 = -((float)farPlane + (float)nearPlane)/fn; + result.m11 = -1.0f; + result.m14 = -((float)farPlane*(float)nearPlane*2.0f)/fn; + + return result; +} + +// Get orthographic projection matrix +RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, double nearPlane, double farPlane) +{ + Matrix result = { 0 }; + + float rl = (float)(right - left); + float tb = (float)(top - bottom); + float fn = (float)(farPlane - nearPlane); + + result.m0 = 2.0f/rl; + result.m1 = 0.0f; + result.m2 = 0.0f; + result.m3 = 0.0f; + result.m4 = 0.0f; + result.m5 = 2.0f/tb; + result.m6 = 0.0f; + result.m7 = 0.0f; + result.m8 = 0.0f; + result.m9 = 0.0f; + result.m10 = -2.0f/fn; + result.m11 = 0.0f; + result.m12 = -((float)left + (float)right)/rl; + result.m13 = -((float)top + (float)bottom)/tb; + result.m14 = -((float)farPlane + (float)nearPlane)/fn; + result.m15 = 1.0f; + + return result; +} + +// Get camera look-at matrix (view matrix) +RMAPI Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up) +{ + Matrix result = { 0 }; + + float length = 0.0f; + float ilength = 0.0f; + + // Vector3Subtract(eye, target) + Vector3 vz = { eye.x - target.x, eye.y - target.y, eye.z - target.z }; + + // Vector3Normalize(vz) + Vector3 v = vz; + length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); + if (length == 0.0f) length = 1.0f; + ilength = 1.0f/length; + vz.x *= ilength; + vz.y *= ilength; + vz.z *= ilength; + + // Vector3CrossProduct(up, vz) + Vector3 vx = { up.y*vz.z - up.z*vz.y, up.z*vz.x - up.x*vz.z, up.x*vz.y - up.y*vz.x }; + + // Vector3Normalize(x) + v = vx; + length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z); + if (length == 0.0f) length = 1.0f; + ilength = 1.0f/length; + vx.x *= ilength; + vx.y *= ilength; + vx.z *= ilength; + + // Vector3CrossProduct(vz, vx) + Vector3 vy = { vz.y*vx.z - vz.z*vx.y, vz.z*vx.x - vz.x*vx.z, vz.x*vx.y - vz.y*vx.x }; + + result.m0 = vx.x; + result.m1 = vy.x; + result.m2 = vz.x; + result.m3 = 0.0f; + result.m4 = vx.y; + result.m5 = vy.y; + result.m6 = vz.y; + result.m7 = 0.0f; + result.m8 = vx.z; + result.m9 = vy.z; + result.m10 = vz.z; + result.m11 = 0.0f; + result.m12 = -(vx.x*eye.x + vx.y*eye.y + vx.z*eye.z); // Vector3DotProduct(vx, eye) + result.m13 = -(vy.x*eye.x + vy.y*eye.y + vy.z*eye.z); // Vector3DotProduct(vy, eye) + result.m14 = -(vz.x*eye.x + vz.y*eye.y + vz.z*eye.z); // Vector3DotProduct(vz, eye) + result.m15 = 1.0f; + + return result; +} + +// Get float array of matrix data +RMAPI float16 MatrixToFloatV(Matrix mat) +{ + float16 result = { 0 }; + + result.v[0] = mat.m0; + result.v[1] = mat.m1; + result.v[2] = mat.m2; + result.v[3] = mat.m3; + result.v[4] = mat.m4; + result.v[5] = mat.m5; + result.v[6] = mat.m6; + result.v[7] = mat.m7; + result.v[8] = mat.m8; + result.v[9] = mat.m9; + result.v[10] = mat.m10; + result.v[11] = mat.m11; + result.v[12] = mat.m12; + result.v[13] = mat.m13; + result.v[14] = mat.m14; + result.v[15] = mat.m15; + + return result; +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Quaternion math +//---------------------------------------------------------------------------------- + +// Add two quaternions +RMAPI Quaternion QuaternionAdd(Quaternion q1, Quaternion q2) +{ + Quaternion result = {q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w}; + + return result; +} + +// Add quaternion and float value +RMAPI Quaternion QuaternionAddValue(Quaternion q, float add) +{ + Quaternion result = {q.x + add, q.y + add, q.z + add, q.w + add}; + + return result; +} + +// Subtract two quaternions +RMAPI Quaternion QuaternionSubtract(Quaternion q1, Quaternion q2) +{ + Quaternion result = {q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w}; + + return result; +} + +// Subtract quaternion and float value +RMAPI Quaternion QuaternionSubtractValue(Quaternion q, float sub) +{ + Quaternion result = {q.x - sub, q.y - sub, q.z - sub, q.w - sub}; + + return result; +} + +// Get identity quaternion +RMAPI Quaternion QuaternionIdentity(void) +{ + Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f }; + + return result; +} + +// Computes the length of a quaternion +RMAPI float QuaternionLength(Quaternion q) +{ + float result = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); + + return result; +} + +// Normalize provided quaternion +RMAPI Quaternion QuaternionNormalize(Quaternion q) +{ + Quaternion result = { 0 }; + + float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); + if (length == 0.0f) length = 1.0f; + float ilength = 1.0f/length; + + result.x = q.x*ilength; + result.y = q.y*ilength; + result.z = q.z*ilength; + result.w = q.w*ilength; + + return result; +} + +// Invert provided quaternion +RMAPI Quaternion QuaternionInvert(Quaternion q) +{ + Quaternion result = q; + + float lengthSq = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w; + + if (lengthSq != 0.0f) + { + float invLength = 1.0f/lengthSq; + + result.x *= -invLength; + result.y *= -invLength; + result.z *= -invLength; + result.w *= invLength; + } + + return result; +} + +// Calculate two quaternion multiplication +RMAPI Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2) +{ + Quaternion result = { 0 }; + + float qax = q1.x, qay = q1.y, qaz = q1.z, qaw = q1.w; + float qbx = q2.x, qby = q2.y, qbz = q2.z, qbw = q2.w; + + result.x = qax*qbw + qaw*qbx + qay*qbz - qaz*qby; + result.y = qay*qbw + qaw*qby + qaz*qbx - qax*qbz; + result.z = qaz*qbw + qaw*qbz + qax*qby - qay*qbx; + result.w = qaw*qbw - qax*qbx - qay*qby - qaz*qbz; + + return result; +} + +// Scale quaternion by float value +RMAPI Quaternion QuaternionScale(Quaternion q, float mul) +{ + Quaternion result = { 0 }; + + result.x = q.x*mul; + result.y = q.y*mul; + result.z = q.z*mul; + result.w = q.w*mul; + + return result; +} + +// Divide two quaternions +RMAPI Quaternion QuaternionDivide(Quaternion q1, Quaternion q2) +{ + Quaternion result = { q1.x/q2.x, q1.y/q2.y, q1.z/q2.z, q1.w/q2.w }; + + return result; +} + +// Calculate linear interpolation between two quaternions +RMAPI Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount) +{ + Quaternion result = { 0 }; + + result.x = q1.x + amount*(q2.x - q1.x); + result.y = q1.y + amount*(q2.y - q1.y); + result.z = q1.z + amount*(q2.z - q1.z); + result.w = q1.w + amount*(q2.w - q1.w); + + return result; +} + +// Calculate slerp-optimized interpolation between two quaternions +RMAPI Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount) +{ + Quaternion result = { 0 }; + + // QuaternionLerp(q1, q2, amount) + result.x = q1.x + amount*(q2.x - q1.x); + result.y = q1.y + amount*(q2.y - q1.y); + result.z = q1.z + amount*(q2.z - q1.z); + result.w = q1.w + amount*(q2.w - q1.w); + + // QuaternionNormalize(q); + Quaternion q = result; + float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); + if (length == 0.0f) length = 1.0f; + float ilength = 1.0f/length; + + result.x = q.x*ilength; + result.y = q.y*ilength; + result.z = q.z*ilength; + result.w = q.w*ilength; + + return result; +} + +// Calculates spherical linear interpolation between two quaternions +RMAPI Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount) +{ + Quaternion result = { 0 }; + +#if !defined(EPSILON) + #define EPSILON 0.000001f +#endif + + float cosHalfTheta = q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w; + + if (cosHalfTheta < 0) + { + q2.x = -q2.x; q2.y = -q2.y; q2.z = -q2.z; q2.w = -q2.w; + cosHalfTheta = -cosHalfTheta; + } + + if (fabsf(cosHalfTheta) >= 1.0f) result = q1; + else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount); + else + { + float halfTheta = acosf(cosHalfTheta); + float sinHalfTheta = sqrtf(1.0f - cosHalfTheta*cosHalfTheta); + + if (fabsf(sinHalfTheta) < EPSILON) + { + result.x = (q1.x*0.5f + q2.x*0.5f); + result.y = (q1.y*0.5f + q2.y*0.5f); + result.z = (q1.z*0.5f + q2.z*0.5f); + result.w = (q1.w*0.5f + q2.w*0.5f); + } + else + { + float ratioA = sinf((1 - amount)*halfTheta)/sinHalfTheta; + float ratioB = sinf(amount*halfTheta)/sinHalfTheta; + + result.x = (q1.x*ratioA + q2.x*ratioB); + result.y = (q1.y*ratioA + q2.y*ratioB); + result.z = (q1.z*ratioA + q2.z*ratioB); + result.w = (q1.w*ratioA + q2.w*ratioB); + } + } + + return result; +} + +// 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 +RMAPI Quaternion QuaternionCubicHermiteSpline(Quaternion q1, Quaternion outTangent1, Quaternion q2, Quaternion inTangent2, float t) +{ + float t2 = t*t; + float t3 = t2*t; + float h00 = 2*t3 - 3*t2 + 1; + float h10 = t3 - 2*t2 + t; + float h01 = -2*t3 + 3*t2; + float h11 = t3 - t2; + + Quaternion p0 = QuaternionScale(q1, h00); + Quaternion m0 = QuaternionScale(outTangent1, h10); + Quaternion p1 = QuaternionScale(q2, h01); + Quaternion m1 = QuaternionScale(inTangent2, h11); + + Quaternion result = { 0 }; + + result = QuaternionAdd(p0, m0); + result = QuaternionAdd(result, p1); + result = QuaternionAdd(result, m1); + result = QuaternionNormalize(result); + + return result; +} + +// Calculate quaternion based on the rotation from one vector to another +RMAPI Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to) +{ + Quaternion result = { 0 }; + + float cos2Theta = (from.x*to.x + from.y*to.y + from.z*to.z); // Vector3DotProduct(from, to) + Vector3 cross = { from.y*to.z - from.z*to.y, from.z*to.x - from.x*to.z, from.x*to.y - from.y*to.x }; // Vector3CrossProduct(from, to) + + result.x = cross.x; + result.y = cross.y; + result.z = cross.z; + result.w = sqrtf(cross.x*cross.x + cross.y*cross.y + cross.z*cross.z + cos2Theta*cos2Theta) + cos2Theta; + + // QuaternionNormalize(q); + // NOTE: Normalize to essentially nlerp the original and identity to 0.5 + Quaternion q = result; + float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); + if (length == 0.0f) length = 1.0f; + float ilength = 1.0f/length; + + result.x = q.x*ilength; + result.y = q.y*ilength; + result.z = q.z*ilength; + result.w = q.w*ilength; + + return result; +} + +// Get a quaternion for a given rotation matrix +RMAPI Quaternion QuaternionFromMatrix(Matrix mat) +{ + Quaternion result = { 0 }; + + float fourWSquaredMinus1 = mat.m0 + mat.m5 + mat.m10; + float fourXSquaredMinus1 = mat.m0 - mat.m5 - mat.m10; + float fourYSquaredMinus1 = mat.m5 - mat.m0 - mat.m10; + float fourZSquaredMinus1 = mat.m10 - mat.m0 - mat.m5; + + int biggestIndex = 0; + float fourBiggestSquaredMinus1 = fourWSquaredMinus1; + if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) + { + fourBiggestSquaredMinus1 = fourXSquaredMinus1; + biggestIndex = 1; + } + + if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) + { + fourBiggestSquaredMinus1 = fourYSquaredMinus1; + biggestIndex = 2; + } + + if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) + { + fourBiggestSquaredMinus1 = fourZSquaredMinus1; + biggestIndex = 3; + } + + float biggestVal = sqrtf(fourBiggestSquaredMinus1 + 1.0f)*0.5f; + float mult = 0.25f/biggestVal; + + switch (biggestIndex) + { + case 0: + result.w = biggestVal; + result.x = (mat.m6 - mat.m9)*mult; + result.y = (mat.m8 - mat.m2)*mult; + result.z = (mat.m1 - mat.m4)*mult; + break; + case 1: + result.x = biggestVal; + result.w = (mat.m6 - mat.m9)*mult; + result.y = (mat.m1 + mat.m4)*mult; + result.z = (mat.m8 + mat.m2)*mult; + break; + case 2: + result.y = biggestVal; + result.w = (mat.m8 - mat.m2)*mult; + result.x = (mat.m1 + mat.m4)*mult; + result.z = (mat.m6 + mat.m9)*mult; + break; + case 3: + result.z = biggestVal; + result.w = (mat.m1 - mat.m4)*mult; + result.x = (mat.m8 + mat.m2)*mult; + result.y = (mat.m6 + mat.m9)*mult; + break; + } + + return result; +} + +// Get a matrix for a given quaternion +RMAPI Matrix QuaternionToMatrix(Quaternion q) +{ + Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() + + float a2 = q.x*q.x; + float b2 = q.y*q.y; + float c2 = q.z*q.z; + float ac = q.x*q.z; + float ab = q.x*q.y; + float bc = q.y*q.z; + float ad = q.w*q.x; + float bd = q.w*q.y; + float cd = q.w*q.z; + + result.m0 = 1 - 2*(b2 + c2); + result.m1 = 2*(ab + cd); + result.m2 = 2*(ac - bd); + + result.m4 = 2*(ab - cd); + result.m5 = 1 - 2*(a2 + c2); + result.m6 = 2*(bc + ad); + + result.m8 = 2*(ac + bd); + result.m9 = 2*(bc - ad); + result.m10 = 1 - 2*(a2 + b2); + + return result; +} + +// Get rotation quaternion for an angle and axis +// NOTE: Angle must be provided in radians +RMAPI Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle) +{ + Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f }; + + float length = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z); + + if (length != 0.0f) + { + angle *= 0.5f; + + // Vector3Normalize(axis) + float ilength = 1.0f/length; + axis.x *= ilength; + axis.y *= ilength; + axis.z *= ilength; + + float sinres = sinf(angle); + float cosres = cosf(angle); + + result.x = axis.x*sinres; + result.y = axis.y*sinres; + result.z = axis.z*sinres; + result.w = cosres; + + // QuaternionNormalize(q); + Quaternion q = result; + length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); + if (length == 0.0f) length = 1.0f; + ilength = 1.0f/length; + result.x = q.x*ilength; + result.y = q.y*ilength; + result.z = q.z*ilength; + result.w = q.w*ilength; + } + + return result; +} + +// Get the rotation angle and axis for a given quaternion +RMAPI void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle) +{ + if (fabsf(q.w) > 1.0f) + { + // QuaternionNormalize(q); + float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); + if (length == 0.0f) length = 1.0f; + float ilength = 1.0f/length; + + q.x = q.x*ilength; + q.y = q.y*ilength; + q.z = q.z*ilength; + q.w = q.w*ilength; + } + + Vector3 resAxis = { 0.0f, 0.0f, 0.0f }; + float resAngle = 2.0f*acosf(q.w); + float den = sqrtf(1.0f - q.w*q.w); + + if (den > EPSILON) + { + resAxis.x = q.x/den; + resAxis.y = q.y/den; + resAxis.z = q.z/den; + } + else + { + // This occurs when the angle is zero + // Not a problem, set an arbitrary normalized axis + resAxis.x = 1.0f; + } + + *outAxis = resAxis; + *outAngle = resAngle; +} + +// Get the quaternion equivalent to Euler angles +// NOTE: Rotation order is ZYX +RMAPI Quaternion QuaternionFromEuler(float pitch, float yaw, float roll) +{ + Quaternion result = { 0 }; + + float x0 = cosf(pitch*0.5f); + float x1 = sinf(pitch*0.5f); + float y0 = cosf(yaw*0.5f); + float y1 = sinf(yaw*0.5f); + float z0 = cosf(roll*0.5f); + float z1 = sinf(roll*0.5f); + + result.x = x1*y0*z0 - x0*y1*z1; + result.y = x0*y1*z0 + x1*y0*z1; + result.z = x0*y0*z1 - x1*y1*z0; + result.w = x0*y0*z0 + x1*y1*z1; + + return result; +} + +// Get the Euler angles equivalent to quaternion (roll, pitch, yaw) +// NOTE: Angles are returned in a Vector3 struct in radians +RMAPI Vector3 QuaternionToEuler(Quaternion q) +{ + Vector3 result = { 0 }; + + // Roll (x-axis rotation) + float x0 = 2.0f*(q.w*q.x + q.y*q.z); + float x1 = 1.0f - 2.0f*(q.x*q.x + q.y*q.y); + result.x = atan2f(x0, x1); + + // Pitch (y-axis rotation) + float y0 = 2.0f*(q.w*q.y - q.z*q.x); + y0 = y0 > 1.0f ? 1.0f : y0; + y0 = y0 < -1.0f ? -1.0f : y0; + result.y = asinf(y0); + + // Yaw (z-axis rotation) + float z0 = 2.0f*(q.w*q.z + q.x*q.y); + float z1 = 1.0f - 2.0f*(q.y*q.y + q.z*q.z); + result.z = atan2f(z0, z1); + + return result; +} + +// Transform a quaternion given a transformation matrix +RMAPI Quaternion QuaternionTransform(Quaternion q, Matrix mat) +{ + Quaternion result = { 0 }; + + result.x = mat.m0*q.x + mat.m4*q.y + mat.m8*q.z + mat.m12*q.w; + result.y = mat.m1*q.x + mat.m5*q.y + mat.m9*q.z + mat.m13*q.w; + result.z = mat.m2*q.x + mat.m6*q.y + mat.m10*q.z + mat.m14*q.w; + result.w = mat.m3*q.x + mat.m7*q.y + mat.m11*q.z + mat.m15*q.w; + + return result; +} + +// Check whether two given quaternions are almost equal +RMAPI int QuaternionEquals(Quaternion p, Quaternion q) +{ +#if !defined(EPSILON) + #define EPSILON 0.000001f +#endif + + int result = (((fabsf(p.x - q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) && + ((fabsf(p.y - q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) && + ((fabsf(p.z - q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))) && + ((fabsf(p.w - q.w)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.w), fabsf(q.w)))))) || + (((fabsf(p.x + q.x)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.x), fabsf(q.x))))) && + ((fabsf(p.y + q.y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.y), fabsf(q.y))))) && + ((fabsf(p.z + q.z)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.z), fabsf(q.z))))) && + ((fabsf(p.w + q.w)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(p.w), fabsf(q.w)))))); + + return result; +} + +// Compose a transformation matrix from rotational, translational and scaling components +// TODO: This function is not following raymath conventions defined in header: NOT self-contained +RMAPI Matrix MatrixCompose(Vector3 translation, Quaternion rotation, Vector3 scale) +{ + // Initialize vectors + Vector3 right = { 1.0f, 0.0f, 0.0f }; + Vector3 up = { 0.0f, 1.0f, 0.0f }; + Vector3 forward = { 0.0f, 0.0f, 1.0f }; + + // Scale vectors + right = Vector3Scale(right, scale.x); + up = Vector3Scale(up, scale.y); + forward = Vector3Scale(forward , scale.z); + + // Rotate vectors + right = Vector3RotateByQuaternion(right, rotation); + up = Vector3RotateByQuaternion(up, rotation); + forward = Vector3RotateByQuaternion(forward, rotation); + + // Set result matrix output + Matrix result = { + right.x, up.x, forward.x, translation.x, + right.y, up.y, forward.y, translation.y, + right.z, up.z, forward.z, translation.z, + 0.0f, 0.0f, 0.0f, 1.0f + }; + + return result; +} + +// Decompose a transformation matrix into its rotational, translational and scaling components and remove shear +// TODO: This function is not following raymath conventions defined in header: NOT self-contained +RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotation, Vector3 *scale) +{ + float eps = (float)1e-9; + + // Extract Translation + translation->x = mat.m12; + translation->y = mat.m13; + translation->z = mat.m14; + + // Matrix Columns - Rotation will be extracted into here + Vector3 matColumns[3] = {{ mat.m0, mat.m4, mat.m8 }, + { mat.m1, mat.m5, mat.m9 }, + { mat.m2, mat.m6, mat.m10 }}; + + // Shear Parameters XY, XZ, and YZ (extract and ignored) + float shear[3] = { 0 }; + + // Normalized Scale Parameters + Vector3 scl = { 0 }; + + // Max-Normalizing helps numerical stability + float stabilizer = eps; + for (int i = 0; i < 3; i++) + { + stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].x)); + stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].y)); + stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].z)); + } + matColumns[0] = Vector3Scale(matColumns[0], 1.0f / stabilizer); + matColumns[1] = Vector3Scale(matColumns[1], 1.0f / stabilizer); + matColumns[2] = Vector3Scale(matColumns[2], 1.0f / stabilizer); + + // X Scale + scl.x = Vector3Length(matColumns[0]); + if (scl.x > eps) matColumns[0] = Vector3Scale(matColumns[0], 1.0f / scl.x); + + // Compute XY shear and make col2 orthogonal + shear[0] = Vector3DotProduct(matColumns[0], matColumns[1]); + matColumns[1] = Vector3Subtract(matColumns[1], Vector3Scale(matColumns[0], shear[0])); + + // Y Scale + scl.y = Vector3Length(matColumns[1]); + if (scl.y > eps) + { + matColumns[1] = Vector3Scale(matColumns[1], 1.0f / scl.y); + shear[0] /= scl.y; // Correct XY shear + } + + // Compute XZ and YZ shears and make col3 orthogonal + shear[1] = Vector3DotProduct(matColumns[0], matColumns[2]); + matColumns[2] = Vector3Subtract(matColumns[2], Vector3Scale(matColumns[0], shear[1])); + shear[2] = Vector3DotProduct(matColumns[1], matColumns[2]); + matColumns[2] = Vector3Subtract(matColumns[2], Vector3Scale(matColumns[1], shear[2])); + + // Z Scale + scl.z = Vector3Length(matColumns[2]); + if (scl.z > eps) + { + matColumns[2] = Vector3Scale(matColumns[2], 1.0f / scl.z); + shear[1] /= scl.z; // Correct XZ shear + shear[2] /= scl.z; // Correct YZ shear + } + + // matColumns are now orthonormal in O(3). Now ensure its in SO(3) by enforcing det = 1 + if (Vector3DotProduct(matColumns[0], Vector3CrossProduct(matColumns[1], matColumns[2])) < 0) + { + scl = Vector3Negate(scl); + matColumns[0] = Vector3Negate(matColumns[0]); + matColumns[1] = Vector3Negate(matColumns[1]); + matColumns[2] = Vector3Negate(matColumns[2]); + } + + // Set Scale + *scale = Vector3Scale(scl, stabilizer); + + // Extract Rotation + Matrix rotationMatrix = { matColumns[0].x, matColumns[0].y, matColumns[0].z, 0, + matColumns[1].x, matColumns[1].y, matColumns[1].z, 0, + matColumns[2].x, matColumns[2].y, matColumns[2].z, 0, + 0, 0, 0, 1 }; + *rotation = QuaternionFromMatrix(rotationMatrix); +} + +#if defined(__cplusplus) && !defined(RAYMATH_DISABLE_CPP_OPERATORS) + +// Optional C++ math operators +//------------------------------------------------------------------------------- + +// Vector2 operators +static constexpr Vector2 Vector2Zeros = { 0, 0 }; +static constexpr Vector2 Vector2Ones = { 1, 1 }; +static constexpr Vector2 Vector2UnitX = { 1, 0 }; +static constexpr Vector2 Vector2UnitY = { 0, 1 }; + +inline Vector2 operator + (const Vector2& lhs, const Vector2& rhs) +{ + return Vector2Add(lhs, rhs); +} + +inline const Vector2& operator += (Vector2& lhs, const Vector2& rhs) +{ + lhs = Vector2Add(lhs, rhs); + return lhs; +} + +inline Vector2 operator - (const Vector2& lhs, const Vector2& rhs) +{ + return Vector2Subtract(lhs, rhs); +} + +inline const Vector2& operator -= (Vector2& lhs, const Vector2& rhs) +{ + lhs = Vector2Subtract(lhs, rhs); + return lhs; +} + +inline Vector2 operator * (const Vector2& lhs, const float& rhs) +{ + return Vector2Scale(lhs, rhs); +} + +inline const Vector2& operator *= (Vector2& lhs, const float& rhs) +{ + lhs = Vector2Scale(lhs, rhs); + return lhs; +} + +inline Vector2 operator * (const Vector2& lhs, const Vector2& rhs) +{ + return Vector2Multiply(lhs, rhs); +} + +inline const Vector2& operator *= (Vector2& lhs, const Vector2& rhs) +{ + lhs = Vector2Multiply(lhs, rhs); + return lhs; +} + +inline Vector2 operator * (const Vector2& lhs, const Matrix& rhs) +{ + return Vector2Transform(lhs, rhs); +} + +inline const Vector2& operator *= (Vector2& lhs, const Matrix& rhs) +{ + lhs = Vector2Transform(lhs, rhs); + return lhs; +} + +inline Vector2 operator / (const Vector2& lhs, const float& rhs) +{ + return Vector2Scale(lhs, 1.0f/rhs); +} + +inline const Vector2& operator /= (Vector2& lhs, const float& rhs) +{ + lhs = Vector2Scale(lhs, 1.0f/rhs); + return lhs; +} + +inline Vector2 operator / (const Vector2& lhs, const Vector2& rhs) +{ + return Vector2Divide(lhs, rhs); +} + +inline const Vector2& operator /= (Vector2& lhs, const Vector2& rhs) +{ + lhs = Vector2Divide(lhs, rhs); + return lhs; +} + +inline bool operator == (const Vector2& lhs, const Vector2& rhs) +{ + return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y); +} + +inline bool operator != (const Vector2& lhs, const Vector2& rhs) +{ + return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y); +} + +// Vector3 operators +static constexpr Vector3 Vector3Zeros = { 0, 0, 0 }; +static constexpr Vector3 Vector3Ones = { 1, 1, 1 }; +static constexpr Vector3 Vector3UnitX = { 1, 0, 0 }; +static constexpr Vector3 Vector3UnitY = { 0, 1, 0 }; +static constexpr Vector3 Vector3UnitZ = { 0, 0, 1 }; + +inline Vector3 operator + (const Vector3& lhs, const Vector3& rhs) +{ + return Vector3Add(lhs, rhs); +} + +inline const Vector3& operator += (Vector3& lhs, const Vector3& rhs) +{ + lhs = Vector3Add(lhs, rhs); + return lhs; +} + +inline Vector3 operator - (const Vector3& lhs, const Vector3& rhs) +{ + return Vector3Subtract(lhs, rhs); +} + +inline const Vector3& operator -= (Vector3& lhs, const Vector3& rhs) +{ + lhs = Vector3Subtract(lhs, rhs); + return lhs; +} + +inline Vector3 operator * (const Vector3& lhs, const float& rhs) +{ + return Vector3Scale(lhs, rhs); +} + +inline const Vector3& operator *= (Vector3& lhs, const float& rhs) +{ + lhs = Vector3Scale(lhs, rhs); + return lhs; +} + +inline Vector3 operator * (const Vector3& lhs, const Vector3& rhs) +{ + return Vector3Multiply(lhs, rhs); +} + +inline const Vector3& operator *= (Vector3& lhs, const Vector3& rhs) +{ + lhs = Vector3Multiply(lhs, rhs); + return lhs; +} + +inline Vector3 operator * (const Vector3& lhs, const Matrix& rhs) +{ + return Vector3Transform(lhs, rhs); +} + +inline const Vector3& operator *= (Vector3& lhs, const Matrix& rhs) +{ + lhs = Vector3Transform(lhs, rhs); + return lhs; +} + +inline Vector3 operator / (const Vector3& lhs, const float& rhs) +{ + return Vector3Scale(lhs, 1.0f/rhs); +} + +inline const Vector3& operator /= (Vector3& lhs, const float& rhs) +{ + lhs = Vector3Scale(lhs, 1.0f/rhs); + return lhs; +} + +inline Vector3 operator / (const Vector3& lhs, const Vector3& rhs) +{ + return Vector3Divide(lhs, rhs); +} + +inline const Vector3& operator /= (Vector3& lhs, const Vector3& rhs) +{ + lhs = Vector3Divide(lhs, rhs); + return lhs; +} + +inline bool operator == (const Vector3& lhs, const Vector3& rhs) +{ + return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z); +} + +inline bool operator != (const Vector3& lhs, const Vector3& rhs) +{ + return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z); +} + +// Vector4 operators +static constexpr Vector4 Vector4Zeros = { 0, 0, 0, 0 }; +static constexpr Vector4 Vector4Ones = { 1, 1, 1, 1 }; +static constexpr Vector4 Vector4UnitX = { 1, 0, 0, 0 }; +static constexpr Vector4 Vector4UnitY = { 0, 1, 0, 0 }; +static constexpr Vector4 Vector4UnitZ = { 0, 0, 1, 0 }; +static constexpr Vector4 Vector4UnitW = { 0, 0, 0, 1 }; + +inline Vector4 operator + (const Vector4& lhs, const Vector4& rhs) +{ + return Vector4Add(lhs, rhs); +} + +inline const Vector4& operator += (Vector4& lhs, const Vector4& rhs) +{ + lhs = Vector4Add(lhs, rhs); + return lhs; +} + +inline Vector4 operator - (const Vector4& lhs, const Vector4& rhs) +{ + return Vector4Subtract(lhs, rhs); +} + +inline const Vector4& operator -= (Vector4& lhs, const Vector4& rhs) +{ + lhs = Vector4Subtract(lhs, rhs); + return lhs; +} + +inline Vector4 operator * (const Vector4& lhs, const float& rhs) +{ + return Vector4Scale(lhs, rhs); +} + +inline const Vector4& operator *= (Vector4& lhs, const float& rhs) +{ + lhs = Vector4Scale(lhs, rhs); + return lhs; +} + +inline Vector4 operator * (const Vector4& lhs, const Vector4& rhs) +{ + return Vector4Multiply(lhs, rhs); +} + +inline const Vector4& operator *= (Vector4& lhs, const Vector4& rhs) +{ + lhs = Vector4Multiply(lhs, rhs); + return lhs; +} + +inline Vector4 operator / (const Vector4& lhs, const float& rhs) +{ + return Vector4Scale(lhs, 1.0f/rhs); +} + +inline const Vector4& operator /= (Vector4& lhs, const float& rhs) +{ + lhs = Vector4Scale(lhs, 1.0f/rhs); + return lhs; +} + +inline Vector4 operator / (const Vector4& lhs, const Vector4& rhs) +{ + return Vector4Divide(lhs, rhs); +} + +inline const Vector4& operator /= (Vector4& lhs, const Vector4& rhs) +{ + lhs = Vector4Divide(lhs, rhs); + return lhs; +} + +inline bool operator == (const Vector4& lhs, const Vector4& rhs) +{ + return FloatEquals(lhs.x, rhs.x) && FloatEquals(lhs.y, rhs.y) && FloatEquals(lhs.z, rhs.z) && FloatEquals(lhs.w, rhs.w); +} + +inline bool operator != (const Vector4& lhs, const Vector4& rhs) +{ + return !FloatEquals(lhs.x, rhs.x) || !FloatEquals(lhs.y, rhs.y) || !FloatEquals(lhs.z, rhs.z) || !FloatEquals(lhs.w, rhs.w); +} + +// Quaternion operators +static constexpr Quaternion QuaternionZeros = { 0, 0, 0, 0 }; +static constexpr Quaternion QuaternionOnes = { 1, 1, 1, 1 }; +static constexpr Quaternion QuaternionUnitX = { 0, 0, 0, 1 }; + +inline Quaternion operator + (const Quaternion& lhs, const float& rhs) +{ + return QuaternionAddValue(lhs, rhs); +} + +inline const Quaternion& operator += (Quaternion& lhs, const float& rhs) +{ + lhs = QuaternionAddValue(lhs, rhs); + return lhs; +} + +inline Quaternion operator - (const Quaternion& lhs, const float& rhs) +{ + return QuaternionSubtractValue(lhs, rhs); +} + +inline const Quaternion& operator -= (Quaternion& lhs, const float& rhs) +{ + lhs = QuaternionSubtractValue(lhs, rhs); + return lhs; +} + +inline Quaternion operator * (const Quaternion& lhs, const Matrix& rhs) +{ + return QuaternionTransform(lhs, rhs); +} + +inline const Quaternion& operator *= (Quaternion& lhs, const Matrix& rhs) +{ + lhs = QuaternionTransform(lhs, rhs); + return lhs; +} + +// Matrix operators +static constexpr Matrix MatrixUnit = { 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 }; + +inline Matrix operator + (const Matrix& lhs, const Matrix& rhs) +{ + return MatrixAdd(lhs, rhs); +} + +inline const Matrix& operator += (Matrix& lhs, const Matrix& rhs) +{ + lhs = MatrixAdd(lhs, rhs); + return lhs; +} + +inline Matrix operator - (const Matrix& lhs, const Matrix& rhs) +{ + return MatrixSubtract(lhs, rhs); +} + +inline const Matrix& operator -= (Matrix& lhs, const Matrix& rhs) +{ + lhs = MatrixSubtract(lhs, rhs); + return lhs; +} + +inline Matrix operator * (const Matrix& lhs, const Matrix& rhs) +{ + return MatrixMultiply(lhs, rhs); +} + +inline const Matrix& operator *= (Matrix& lhs, const Matrix& rhs) +{ + lhs = MatrixMultiply(lhs, rhs); + return lhs; +} + +inline Matrix operator * (const Matrix& lhs, const float value) +{ + return MatrixMultiplyValue(lhs, value); +} + +inline const Matrix& operator *= (Matrix& lhs, const float value) +{ + lhs = MatrixMultiplyValue(lhs, value); + return lhs; +} + +//------------------------------------------------------------------------------- +#endif // C++ operators + +#endif // RAYMATH_H diff --git a/raylib-6.0_linux_amd64/include/rlgl.h b/raylib-6.0_linux_amd64/include/rlgl.h new file mode 100644 index 0000000..5c6e95a --- /dev/null +++ b/raylib-6.0_linux_amd64/include/rlgl.h @@ -0,0 +1,5421 @@ +/********************************************************************************************** +* +* rlgl v6.0 - A multi-OpenGL abstraction layer with an immediate-mode style API +* +* DESCRIPTION: +* An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0, ES 3.0) +* that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...) +* +* ADDITIONAL NOTES: +* When choosing an OpenGL backend different than OpenGL 1.1, some internal buffers are +* initialized on rlglInit() to accumulate vertex data +* +* When an internal state change is required all the stored vertex data is rendered in a batch, +* additionally, rlDrawRenderBatchActive() could be called to force flushing of the batch +* +* Some resources are also loaded for convenience, here the complete list: +* - Default batch (RLGL.defaultBatch): RenderBatch system to accumulate vertex data +* - Default texture (RLGL.defaultTextureId): 1x1 white pixel R8G8B8A8 +* - Default shader (RLGL.State.defaultShaderId, RLGL.State.defaultShaderLocs) +* +* Internal buffer (and resources) must be manually unloaded calling rlglClose() +* +* CONFIGURATION: +* #define GRAPHICS_API_OPENGL_SOFTWARE +* #define GRAPHICS_API_OPENGL_11 +* #define GRAPHICS_API_OPENGL_21 +* #define GRAPHICS_API_OPENGL_33 +* #define GRAPHICS_API_OPENGL_43 +* #define GRAPHICS_API_OPENGL_ES2 +* #define GRAPHICS_API_OPENGL_ES3 +* Use selected OpenGL graphics backend, should be supported by platform +* Those preprocessor defines are only used on the rlgl module, if OpenGL version is +* required by any other module, use rlGetVersion() to check it +* +* #define RLGL_IMPLEMENTATION +* Generates the implementation of the library into the included file +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation +* +* #if RLGL_SHOW_GL_DETAILS_INFO +* Show OpenGL extensions and capabilities detailed logs on init +* +* #if RLGL_ENABLE_OPENGL_DEBUG_CONTEXT +* Enable debug context (only available on OpenGL 4.3) +* +* rlgl capabilities could be customized defining some internal +* values before library inclusion (default values listed): +* +* #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 8192 // Default internal render batch elements limits +* #define RL_DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering) +* #define RL_DEFAULT_BATCH_DRAWCALLS 256 // Default number of batch draw calls (by state changes: mode, texture) +* #define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS 4 // Maximum number of texture units that can be activated on batch drawing (SetShaderValueTexture()) +* +* #define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack +* #define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported +* #define RL_CULL_DISTANCE_NEAR 0.05 // Default projection matrix near cull distance +* #define RL_CULL_DISTANCE_FAR 4000.0 // Default projection matrix far cull distance +* +* When loading a shader, the following vertex attributes and uniform +* location names are tried to be set automatically: +* +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES "vertexBoneIndices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS +* #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix +* #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix +* #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix +* #define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix +* #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView))) +* #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color) +* #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // bone matrices +* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0) +* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1) +* #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2) +* +* DEPENDENCIES: +* - OpenGL libraries (depending on platform and OpenGL version selected) +* - GLAD OpenGL extensions loading library (only for OpenGL 3.3 Core, 4.3 Core) +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2014-2026 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef RLGL_H +#define RLGL_H + +#define RLGL_VERSION "6.0" + +// Function specifiers in case library is build/used as a shared library +// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll +// NOTE: visibility(default) attribute makes symbols "visible" when compiled with -fvisibility=hidden +#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED) + #define RLAPI __declspec(dllexport) // Building the library as a Win32 shared library (.dll) +#elif defined(BUILD_LIBTYPE_SHARED) + #define RLAPI __attribute__((visibility("default"))) // Building the library as a Unix shared library (.so/.dylib) +#elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED) + #define RLAPI __declspec(dllimport) // Using the library as a Win32 shared library (.dll) +#endif + +// Function specifiers definition +#ifndef RLAPI + #define RLAPI // Functions defined as 'extern' by default (implicit specifiers) +#endif + +// Support TRACELOG macros +#ifndef TRACELOG + #define TRACELOG(level, ...) (void)0 +#endif + +// Allow custom memory allocators +#ifndef RL_MALLOC + #define RL_MALLOC(sz) malloc(sz) +#endif +#ifndef RL_CALLOC + #define RL_CALLOC(n,sz) calloc(n,sz) +#endif +#ifndef RL_REALLOC + #define RL_REALLOC(n,sz) realloc(n,sz) +#endif +#ifndef RL_FREE + #define RL_FREE(p) free(p) +#endif + +// Security check in case no GRAPHICS_API_OPENGL_* defined +#if !defined(GRAPHICS_API_OPENGL_SOFTWARE) && \ + !defined(GRAPHICS_API_OPENGL_11) && \ + !defined(GRAPHICS_API_OPENGL_21) && \ + !defined(GRAPHICS_API_OPENGL_33) && \ + !defined(GRAPHICS_API_OPENGL_43) && \ + !defined(GRAPHICS_API_OPENGL_ES2) && \ + !defined(GRAPHICS_API_OPENGL_ES3) + #define GRAPHICS_API_OPENGL_33 +#endif + +// Security check in case multiple GRAPHICS_API_OPENGL_* defined +#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_SOFTWARE) + #if defined(GRAPHICS_API_OPENGL_21) + #undef GRAPHICS_API_OPENGL_21 + #endif + #if defined(GRAPHICS_API_OPENGL_33) + #undef GRAPHICS_API_OPENGL_33 + #endif + #if defined(GRAPHICS_API_OPENGL_43) + #undef GRAPHICS_API_OPENGL_43 + #endif + #if defined(GRAPHICS_API_OPENGL_ES2) + #undef GRAPHICS_API_OPENGL_ES2 + #endif +#endif + +// Software implementation uses OpenGL 1.1 functionality +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) + #define GRAPHICS_API_OPENGL_11 +#endif + +// OpenGL 2.1 uses most of OpenGL 3.3 Core functionality +// WARNING: Specific parts are checked with #if defines +#if defined(GRAPHICS_API_OPENGL_21) + #define GRAPHICS_API_OPENGL_33 +#endif + +// OpenGL 4.3 uses OpenGL 3.3 Core functionality +#if defined(GRAPHICS_API_OPENGL_43) + #define GRAPHICS_API_OPENGL_33 +#endif + +// OpenGL ES 3.0 uses OpenGL ES 2.0 functionality (and more) +#if defined(GRAPHICS_API_OPENGL_ES3) + #define GRAPHICS_API_OPENGL_ES2 +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- + +// Default internal render batch elements limits +#ifndef RL_DEFAULT_BATCH_BUFFER_ELEMENTS + #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) + // This is the maximum amount of elements (quads) per batch + // NOTE: Be careful with text, every letter maps to a quad + #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 8192 + #endif + #if defined(GRAPHICS_API_OPENGL_ES2) + // Reducing memory sizes for embedded systems (RPI and HTML5) + // NOTE: On HTML5 (emscripten) this is allocated on heap, + // by default heap is only 16MB!...just take care... + #define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 2048 + #endif +#endif +#ifndef RL_DEFAULT_BATCH_BUFFERS + #define RL_DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering) +#endif +#ifndef RL_DEFAULT_BATCH_DRAWCALLS + #define RL_DEFAULT_BATCH_DRAWCALLS 256 // Default number of batch draw calls (by state changes: mode, texture) +#endif +#ifndef RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS + #define RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS 4 // Maximum number of textures units that can be activated on batch drawing (SetShaderValueTexture()) +#endif + +// Internal Matrix stack +#ifndef RL_MAX_MATRIX_STACK_SIZE + #define RL_MAX_MATRIX_STACK_SIZE 32 // Maximum size of Matrix stack +#endif + +// Shader limits +#ifndef RL_MAX_SHADER_LOCATIONS + #define RL_MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported +#endif + +// Projection matrix culling +#ifndef RL_CULL_DISTANCE_NEAR + #define RL_CULL_DISTANCE_NEAR 0.05 // Default near cull distance +#endif +#ifndef RL_CULL_DISTANCE_FAR + #define RL_CULL_DISTANCE_FAR 4000.0 // Default far cull distance +#endif + +// Texture parameters (equivalent to OpenGL defines) +#define RL_TEXTURE_WRAP_S 0x2802 // GL_TEXTURE_WRAP_S +#define RL_TEXTURE_WRAP_T 0x2803 // GL_TEXTURE_WRAP_T +#define RL_TEXTURE_MAG_FILTER 0x2800 // GL_TEXTURE_MAG_FILTER +#define RL_TEXTURE_MIN_FILTER 0x2801 // GL_TEXTURE_MIN_FILTER + +#define RL_TEXTURE_FILTER_NEAREST 0x2600 // GL_NEAREST +#define RL_TEXTURE_FILTER_LINEAR 0x2601 // GL_LINEAR +#define RL_TEXTURE_FILTER_MIP_NEAREST 0x2700 // GL_NEAREST_MIPMAP_NEAREST +#define RL_TEXTURE_FILTER_NEAREST_MIP_LINEAR 0x2702 // GL_NEAREST_MIPMAP_LINEAR +#define RL_TEXTURE_FILTER_LINEAR_MIP_NEAREST 0x2701 // GL_LINEAR_MIPMAP_NEAREST +#define RL_TEXTURE_FILTER_MIP_LINEAR 0x2703 // GL_LINEAR_MIPMAP_LINEAR +#define RL_TEXTURE_FILTER_ANISOTROPIC 0x3000 // Anisotropic filter (custom identifier) +#define RL_TEXTURE_MIPMAP_BIAS_RATIO 0x4000 // Texture mipmap bias, percentage ratio (custom identifier) + +#define RL_TEXTURE_WRAP_REPEAT 0x2901 // GL_REPEAT +#define RL_TEXTURE_WRAP_CLAMP 0x812F // GL_CLAMP_TO_EDGE +#define RL_TEXTURE_WRAP_MIRROR_REPEAT 0x8370 // GL_MIRRORED_REPEAT +#define RL_TEXTURE_WRAP_MIRROR_CLAMP 0x8742 // GL_MIRROR_CLAMP_EXT + +// Matrix modes (equivalent to OpenGL) +#define RL_MODELVIEW 0x1700 // GL_MODELVIEW +#define RL_PROJECTION 0x1701 // GL_PROJECTION +#define RL_TEXTURE 0x1702 // GL_TEXTURE + +// Primitive assembly draw modes +#define RL_LINES 0x0001 // GL_LINES +#define RL_TRIANGLES 0x0004 // GL_TRIANGLES +#define RL_QUADS 0x0007 // GL_QUADS + +// GL equivalent data types +#define RL_UNSIGNED_BYTE 0x1401 // GL_UNSIGNED_BYTE +#define RL_FLOAT 0x1406 // GL_FLOAT + +// GL buffer usage hint +#define RL_STREAM_DRAW 0x88E0 // GL_STREAM_DRAW +#define RL_STREAM_READ 0x88E1 // GL_STREAM_READ +#define RL_STREAM_COPY 0x88E2 // GL_STREAM_COPY +#define RL_STATIC_DRAW 0x88E4 // GL_STATIC_DRAW +#define RL_STATIC_READ 0x88E5 // GL_STATIC_READ +#define RL_STATIC_COPY 0x88E6 // GL_STATIC_COPY +#define RL_DYNAMIC_DRAW 0x88E8 // GL_DYNAMIC_DRAW +#define RL_DYNAMIC_READ 0x88E9 // GL_DYNAMIC_READ +#define RL_DYNAMIC_COPY 0x88EA // GL_DYNAMIC_COPY + +// GL Shader type +#define RL_FRAGMENT_SHADER 0x8B30 // GL_FRAGMENT_SHADER +#define RL_VERTEX_SHADER 0x8B31 // GL_VERTEX_SHADER +#define RL_COMPUTE_SHADER 0x91B9 // GL_COMPUTE_SHADER + +// GL blending factors +#define RL_ZERO 0 // GL_ZERO +#define RL_ONE 1 // GL_ONE +#define RL_SRC_COLOR 0x0300 // GL_SRC_COLOR +#define RL_ONE_MINUS_SRC_COLOR 0x0301 // GL_ONE_MINUS_SRC_COLOR +#define RL_SRC_ALPHA 0x0302 // GL_SRC_ALPHA +#define RL_ONE_MINUS_SRC_ALPHA 0x0303 // GL_ONE_MINUS_SRC_ALPHA +#define RL_DST_ALPHA 0x0304 // GL_DST_ALPHA +#define RL_ONE_MINUS_DST_ALPHA 0x0305 // GL_ONE_MINUS_DST_ALPHA +#define RL_DST_COLOR 0x0306 // GL_DST_COLOR +#define RL_ONE_MINUS_DST_COLOR 0x0307 // GL_ONE_MINUS_DST_COLOR +#define RL_SRC_ALPHA_SATURATE 0x0308 // GL_SRC_ALPHA_SATURATE +#define RL_CONSTANT_COLOR 0x8001 // GL_CONSTANT_COLOR +#define RL_ONE_MINUS_CONSTANT_COLOR 0x8002 // GL_ONE_MINUS_CONSTANT_COLOR +#define RL_CONSTANT_ALPHA 0x8003 // GL_CONSTANT_ALPHA +#define RL_ONE_MINUS_CONSTANT_ALPHA 0x8004 // GL_ONE_MINUS_CONSTANT_ALPHA + +// GL blending functions/equations +#define RL_FUNC_ADD 0x8006 // GL_FUNC_ADD +#define RL_MIN 0x8007 // GL_MIN +#define RL_MAX 0x8008 // GL_MAX +#define RL_FUNC_SUBTRACT 0x800A // GL_FUNC_SUBTRACT +#define RL_FUNC_REVERSE_SUBTRACT 0x800B // GL_FUNC_REVERSE_SUBTRACT +#define RL_BLEND_EQUATION 0x8009 // GL_BLEND_EQUATION +#define RL_BLEND_EQUATION_RGB 0x8009 // GL_BLEND_EQUATION_RGB // (Same as BLEND_EQUATION) +#define RL_BLEND_EQUATION_ALPHA 0x883D // GL_BLEND_EQUATION_ALPHA +#define RL_BLEND_DST_RGB 0x80C8 // GL_BLEND_DST_RGB +#define RL_BLEND_SRC_RGB 0x80C9 // GL_BLEND_SRC_RGB +#define RL_BLEND_DST_ALPHA 0x80CA // GL_BLEND_DST_ALPHA +#define RL_BLEND_SRC_ALPHA 0x80CB // GL_BLEND_SRC_ALPHA +#define RL_BLEND_COLOR 0x8005 // GL_BLEND_COLOR + +#define RL_READ_FRAMEBUFFER 0x8CA8 // GL_READ_FRAMEBUFFER +#define RL_DRAW_FRAMEBUFFER 0x8CA9 // GL_DRAW_FRAMEBUFFER + +// Default shader vertex attribute locations +#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3 +#endif + #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT +#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES 7 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM + #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM 9 +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +#if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800) + #include +#elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE) + // Boolean type +typedef enum bool { false = 0, true = !false } bool; +#endif + +#if !defined(RL_MATRIX_TYPE) +// Matrix, 4x4 components, column major, OpenGL style, right handed +typedef struct Matrix { + float m0, m4, m8, m12; // Matrix first row (4 components) + float m1, m5, m9, m13; // Matrix second row (4 components) + float m2, m6, m10, m14; // Matrix third row (4 components) + float m3, m7, m11, m15; // Matrix fourth row (4 components) +} Matrix; +#define RL_MATRIX_TYPE +#endif + +// Dynamic vertex buffers (position + texcoords + colors + indices arrays) +typedef struct rlVertexBuffer { + int elementCount; // Number of elements in the buffer (QUADS) + + float *vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0) + float *texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) + float *normals; // Vertex normal (XYZ - 3 components per vertex) (shader-location = 2) + unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) +#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) + unsigned int *indices; // Vertex indices (in case vertex data comes indexed) (6 indices per quad) +#endif +#if defined(GRAPHICS_API_OPENGL_ES2) + unsigned short *indices; // Vertex indices (in case vertex data comes indexed) (6 indices per quad) +#endif + unsigned int vaoId; // OpenGL Vertex Array Object id + unsigned int vboId[5]; // OpenGL Vertex Buffer Objects id (5 types of vertex data) +} rlVertexBuffer; + +// Draw call type +// NOTE: Only texture changes register a new draw, other state-change-related elements are not +// used at this moment (vaoId, shaderId, matrices), raylib forces a batch draw call if any +// of those state-change happens (this is done in core module) +typedef struct rlDrawCall { + int mode; // Drawing mode: LINES, TRIANGLES, QUADS + int vertexCount; // Number of vertex of the draw + int vertexAlignment; // Number of vertex required for index alignment (LINES, TRIANGLES) + //unsigned int vaoId; // Vertex array id to be used on the draw -> Using RLGL.currentBatch->vertexBuffer.vaoId + //unsigned int shaderId; // Shader id to be used on the draw -> Using RLGL.currentShaderId + unsigned int textureId; // Texture id to be used on the draw -> Use to create new draw call if changes + + //Matrix projection; // Projection matrix for this draw -> Using RLGL.projection by default + //Matrix modelview; // Modelview matrix for this draw -> Using RLGL.modelview by default +} rlDrawCall; + +// rlRenderBatch type +typedef struct rlRenderBatch { + int bufferCount; // Number of vertex buffers (multi-buffering support) + int currentBuffer; // Current buffer tracking in case of multi-buffering + rlVertexBuffer *vertexBuffer; // Dynamic buffer(s) for vertex data + + rlDrawCall *draws; // Draw calls array, depends on textureId + int drawCounter; // Draw calls counter + float currentDepth; // Current depth value for next draw +} rlRenderBatch; + +// OpenGL version +typedef enum { + RL_OPENGL_SOFTWARE = 0, // Software rendering + RL_OPENGL_11, // OpenGL 1.1 + RL_OPENGL_21, // OpenGL 2.1 (GLSL 120) + RL_OPENGL_33, // OpenGL 3.3 (GLSL 330) + RL_OPENGL_43, // OpenGL 4.3 (using GLSL 330) + RL_OPENGL_ES_20, // OpenGL ES 2.0 (GLSL 100) + RL_OPENGL_ES_30 // OpenGL ES 3.0 (GLSL 300 es) +} rlGlVersion; + +// Trace log level +// NOTE: Organized by priority level +typedef enum { + RL_LOG_ALL = 0, // Display all logs + RL_LOG_TRACE, // Trace logging, intended for internal use only + RL_LOG_DEBUG, // Debug logging, used for internal debugging, it should be disabled on release builds + RL_LOG_INFO, // Info logging, used for program execution info + RL_LOG_WARNING, // Warning logging, used on recoverable failures + RL_LOG_ERROR, // Error logging, used on unrecoverable failures + RL_LOG_FATAL, // Fatal logging, used to abort program: exit(EXIT_FAILURE) + RL_LOG_NONE // Disable logging +} rlTraceLogLevel; + +// Texture pixel formats +// NOTE: Support depends on OpenGL version +typedef enum { + RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) + RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) + RL_PIXELFORMAT_UNCOMPRESSED_R5G6B5, // 16 bpp + RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8, // 24 bpp + RL_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) + RL_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) + RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, // 32 bpp + RL_PIXELFORMAT_UNCOMPRESSED_R32, // 32 bpp (1 channel - float) + RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) + RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) + RL_PIXELFORMAT_UNCOMPRESSED_R16, // 16 bpp (1 channel - half float) + RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16, // 16*3 bpp (3 channels - half float) + RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16, // 16*4 bpp (4 channels - half float) + RL_PIXELFORMAT_COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) + RL_PIXELFORMAT_COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) + RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA, // 8 bpp + RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA, // 8 bpp + RL_PIXELFORMAT_COMPRESSED_ETC1_RGB, // 4 bpp + RL_PIXELFORMAT_COMPRESSED_ETC2_RGB, // 4 bpp + RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA, // 8 bpp + RL_PIXELFORMAT_COMPRESSED_PVRT_RGB, // 4 bpp + RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA, // 4 bpp + RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA, // 8 bpp + RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA // 2 bpp +} rlPixelFormat; + +// Texture parameters: filter mode +// NOTE 1: Filtering considers mipmaps if available in the texture +// NOTE 2: Filter is accordingly set for minification and magnification +typedef enum { + RL_TEXTURE_FILTER_POINT = 0, // No filter, pixel approximation + RL_TEXTURE_FILTER_BILINEAR, // Linear filtering + RL_TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) + RL_TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x + RL_TEXTURE_FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x + RL_TEXTURE_FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x +} rlTextureFilter; + +// Color blending modes (pre-defined) +typedef enum { + RL_BLEND_ALPHA = 0, // Blend textures considering alpha (default) + RL_BLEND_ADDITIVE, // Blend textures adding colors + RL_BLEND_MULTIPLIED, // Blend textures multiplying colors + RL_BLEND_ADD_COLORS, // Blend textures adding colors (alternative) + RL_BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative) + RL_BLEND_ALPHA_PREMULTIPLY, // Blend premultiplied textures considering alpha + RL_BLEND_CUSTOM, // Blend textures using custom src/dst factors (use rlSetBlendFactors()) + RL_BLEND_CUSTOM_SEPARATE // Blend textures using custom src/dst factors (use rlSetBlendFactorsSeparate()) +} rlBlendMode; + +// Shader location point type +typedef enum { + RL_SHADER_LOC_VERTEX_POSITION = 0, // Shader location: vertex attribute: position + RL_SHADER_LOC_VERTEX_TEXCOORD01, // Shader location: vertex attribute: texcoord01 + RL_SHADER_LOC_VERTEX_TEXCOORD02, // Shader location: vertex attribute: texcoord02 + RL_SHADER_LOC_VERTEX_NORMAL, // Shader location: vertex attribute: normal + RL_SHADER_LOC_VERTEX_TANGENT, // Shader location: vertex attribute: tangent + RL_SHADER_LOC_VERTEX_COLOR, // Shader location: vertex attribute: color + RL_SHADER_LOC_MATRIX_MVP, // Shader location: matrix uniform: model-view-projection + RL_SHADER_LOC_MATRIX_VIEW, // Shader location: matrix uniform: view (camera transform) + RL_SHADER_LOC_MATRIX_PROJECTION, // Shader location: matrix uniform: projection + RL_SHADER_LOC_MATRIX_MODEL, // Shader location: matrix uniform: model (transform) + RL_SHADER_LOC_MATRIX_NORMAL, // Shader location: matrix uniform: normal + RL_SHADER_LOC_VECTOR_VIEW, // Shader location: vector uniform: view + RL_SHADER_LOC_COLOR_DIFFUSE, // Shader location: vector uniform: diffuse color + RL_SHADER_LOC_COLOR_SPECULAR, // Shader location: vector uniform: specular color + RL_SHADER_LOC_COLOR_AMBIENT, // Shader location: vector uniform: ambient color + RL_SHADER_LOC_MAP_ALBEDO, // Shader location: sampler2d texture: albedo (same as: RL_SHADER_LOC_MAP_DIFFUSE) + RL_SHADER_LOC_MAP_METALNESS, // Shader location: sampler2d texture: metalness (same as: RL_SHADER_LOC_MAP_SPECULAR) + RL_SHADER_LOC_MAP_NORMAL, // Shader location: sampler2d texture: normal + RL_SHADER_LOC_MAP_ROUGHNESS, // Shader location: sampler2d texture: roughness + RL_SHADER_LOC_MAP_OCCLUSION, // Shader location: sampler2d texture: occlusion + RL_SHADER_LOC_MAP_EMISSION, // Shader location: sampler2d texture: emission + RL_SHADER_LOC_MAP_HEIGHT, // Shader location: sampler2d texture: height + RL_SHADER_LOC_MAP_CUBEMAP, // Shader location: samplerCube texture: cubemap + RL_SHADER_LOC_MAP_IRRADIANCE, // Shader location: samplerCube texture: irradiance + RL_SHADER_LOC_MAP_PREFILTER, // Shader location: samplerCube texture: prefilter + RL_SHADER_LOC_MAP_BRDF // Shader location: sampler2d texture: brdf +} rlShaderLocationIndex; + +#define RL_SHADER_LOC_MAP_DIFFUSE RL_SHADER_LOC_MAP_ALBEDO +#define RL_SHADER_LOC_MAP_SPECULAR RL_SHADER_LOC_MAP_METALNESS + +// Shader uniform data type +typedef enum { + RL_SHADER_UNIFORM_FLOAT = 0, // Shader uniform type: float + RL_SHADER_UNIFORM_VEC2, // Shader uniform type: vec2 (2 float) + RL_SHADER_UNIFORM_VEC3, // Shader uniform type: vec3 (3 float) + RL_SHADER_UNIFORM_VEC4, // Shader uniform type: vec4 (4 float) + RL_SHADER_UNIFORM_INT, // Shader uniform type: int + RL_SHADER_UNIFORM_IVEC2, // Shader uniform type: ivec2 (2 int) + RL_SHADER_UNIFORM_IVEC3, // Shader uniform type: ivec3 (3 int) + RL_SHADER_UNIFORM_IVEC4, // Shader uniform type: ivec4 (4 int) + RL_SHADER_UNIFORM_UINT, // Shader uniform type: unsigned int + RL_SHADER_UNIFORM_UIVEC2, // Shader uniform type: uivec2 (2 unsigned int) + RL_SHADER_UNIFORM_UIVEC3, // Shader uniform type: uivec3 (3 unsigned int) + RL_SHADER_UNIFORM_UIVEC4, // Shader uniform type: uivec4 (4 unsigned int) + RL_SHADER_UNIFORM_SAMPLER2D // Shader uniform type: sampler2d +} rlShaderUniformDataType; + +// Shader attribute data types +typedef enum { + RL_SHADER_ATTRIB_FLOAT = 0, // Shader attribute type: float + RL_SHADER_ATTRIB_VEC2, // Shader attribute type: vec2 (2 float) + RL_SHADER_ATTRIB_VEC3, // Shader attribute type: vec3 (3 float) + RL_SHADER_ATTRIB_VEC4 // Shader attribute type: vec4 (4 float) +} rlShaderAttributeDataType; + +// Framebuffer attachment type +// NOTE: By default up to 8 color channels defined, but it can be more +typedef enum { + RL_ATTACHMENT_COLOR_CHANNEL0 = 0, // Framebuffer attachment type: color 0 + RL_ATTACHMENT_COLOR_CHANNEL1 = 1, // Framebuffer attachment type: color 1 + RL_ATTACHMENT_COLOR_CHANNEL2 = 2, // Framebuffer attachment type: color 2 + RL_ATTACHMENT_COLOR_CHANNEL3 = 3, // Framebuffer attachment type: color 3 + RL_ATTACHMENT_COLOR_CHANNEL4 = 4, // Framebuffer attachment type: color 4 + RL_ATTACHMENT_COLOR_CHANNEL5 = 5, // Framebuffer attachment type: color 5 + RL_ATTACHMENT_COLOR_CHANNEL6 = 6, // Framebuffer attachment type: color 6 + RL_ATTACHMENT_COLOR_CHANNEL7 = 7, // Framebuffer attachment type: color 7 + RL_ATTACHMENT_DEPTH = 100, // Framebuffer attachment type: depth + RL_ATTACHMENT_STENCIL = 200, // Framebuffer attachment type: stencil +} rlFramebufferAttachType; + +// Framebuffer texture attachment type +typedef enum { + RL_ATTACHMENT_CUBEMAP_POSITIVE_X = 0, // Framebuffer texture attachment type: cubemap, +X side + RL_ATTACHMENT_CUBEMAP_NEGATIVE_X = 1, // Framebuffer texture attachment type: cubemap, -X side + RL_ATTACHMENT_CUBEMAP_POSITIVE_Y = 2, // Framebuffer texture attachment type: cubemap, +Y side + RL_ATTACHMENT_CUBEMAP_NEGATIVE_Y = 3, // Framebuffer texture attachment type: cubemap, -Y side + RL_ATTACHMENT_CUBEMAP_POSITIVE_Z = 4, // Framebuffer texture attachment type: cubemap, +Z side + RL_ATTACHMENT_CUBEMAP_NEGATIVE_Z = 5, // Framebuffer texture attachment type: cubemap, -Z side + RL_ATTACHMENT_TEXTURE2D = 100, // Framebuffer texture attachment type: texture2d + RL_ATTACHMENT_RENDERBUFFER = 200, // Framebuffer texture attachment type: renderbuffer +} rlFramebufferAttachTextureType; + +// Face culling mode +typedef enum { + RL_CULL_FACE_FRONT = 0, + RL_CULL_FACE_BACK +} rlCullMode; + +//------------------------------------------------------------------------------------ +// Functions Declaration - Matrix operations +//------------------------------------------------------------------------------------ + +#if defined(__cplusplus) +extern "C" { // Prevents name mangling of functions +#endif + +RLAPI void rlMatrixMode(int mode); // Choose the current matrix to be transformed +RLAPI void rlPushMatrix(void); // Push the current matrix to stack +RLAPI void rlPopMatrix(void); // Pop latest inserted matrix from stack +RLAPI void rlLoadIdentity(void); // Reset current matrix to identity matrix +RLAPI void rlTranslatef(float x, float y, float z); // Multiply the current matrix by a translation matrix +RLAPI void rlRotatef(float angle, float x, float y, float z); // Multiply the current matrix by a rotation matrix +RLAPI void rlScalef(float x, float y, float z); // Multiply the current matrix by a scaling matrix +RLAPI void rlMultMatrixf(const float *matf); // Multiply the current matrix by another matrix +RLAPI void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar); +RLAPI void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar); +RLAPI void rlViewport(int x, int y, int width, int height); // Set the viewport area +RLAPI void rlSetClipPlanes(double nearPlane, double farPlane); // Set clip planes distances +RLAPI double rlGetCullDistanceNear(void); // Get cull plane distance near +RLAPI double rlGetCullDistanceFar(void); // Get cull plane distance far + +//------------------------------------------------------------------------------------ +// Functions Declaration - Vertex level operations +//------------------------------------------------------------------------------------ +RLAPI void rlBegin(int mode); // Initialize drawing mode (how to organize vertex) +RLAPI void rlEnd(void); // Finish vertex providing +RLAPI void rlVertex2i(int x, int y); // Define one vertex (position) - 2 int +RLAPI void rlVertex2f(float x, float y); // Define one vertex (position) - 2 float +RLAPI void rlVertex3f(float x, float y, float z); // Define one vertex (position) - 3 float +RLAPI void rlTexCoord2f(float x, float y); // Define one vertex (texture coordinate) - 2 float +RLAPI void rlNormal3f(float x, float y, float z); // Define one vertex (normal) - 3 float +RLAPI void rlColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a); // Define one vertex (color) - 4 byte +RLAPI void rlColor3f(float x, float y, float z); // Define one vertex (color) - 3 float +RLAPI void rlColor4f(float x, float y, float z, float w); // Define one vertex (color) - 4 float + +//------------------------------------------------------------------------------------ +// Functions Declaration - OpenGL style functions (common to 1.1, 3.3+, ES2) +// NOTE: This functions are used to completely abstract raylib code from OpenGL layer, +// some of them are direct wrappers over OpenGL calls, some others are custom +//------------------------------------------------------------------------------------ + +// Vertex buffers state +RLAPI bool rlEnableVertexArray(unsigned int vaoId); // Enable vertex array (VAO, if supported) +RLAPI void rlDisableVertexArray(void); // Disable vertex array (VAO, if supported) +RLAPI void rlEnableVertexBuffer(unsigned int id); // Enable vertex buffer (VBO) +RLAPI void rlDisableVertexBuffer(void); // Disable vertex buffer (VBO) +RLAPI void rlEnableVertexBufferElement(unsigned int id); // Enable vertex buffer element (VBO element) +RLAPI void rlDisableVertexBufferElement(void); // Disable vertex buffer element (VBO element) +RLAPI void rlEnableVertexAttribute(unsigned int index); // Enable vertex attribute index +RLAPI void rlDisableVertexAttribute(unsigned int index); // Disable vertex attribute index +RLAPI void rlEnableStatePointer(int vertexAttribType, void *buffer); // Enable attribute state pointer +RLAPI void rlDisableStatePointer(int vertexAttribType); // Disable attribute state pointer + +// Textures state +RLAPI void rlActiveTextureSlot(int slot); // Select and active a texture slot +RLAPI void rlEnableTexture(unsigned int id); // Enable texture +RLAPI void rlDisableTexture(void); // Disable texture +RLAPI void rlEnableTextureCubemap(unsigned int id); // Enable texture cubemap +RLAPI void rlDisableTextureCubemap(void); // Disable texture cubemap +RLAPI void rlTextureParameters(unsigned int id, int param, int value); // Set texture parameters (filter, wrap) +RLAPI void rlCubemapParameters(unsigned int id, int param, int value); // Set cubemap parameters (filter, wrap) + +// Shader state +RLAPI void rlEnableShader(unsigned int id); // Enable shader program +RLAPI void rlDisableShader(void); // Disable shader program + +// Framebuffer state +RLAPI void rlEnableFramebuffer(unsigned int id); // Enable render texture (fbo) +RLAPI void rlDisableFramebuffer(void); // Disable render texture (fbo), return to default framebuffer +RLAPI unsigned int rlGetActiveFramebuffer(void); // Get the currently active render texture (fbo), 0 for default framebuffer +RLAPI void rlActiveDrawBuffers(int count); // Activate multiple draw color buffers +RLAPI void rlBlitFramebuffer(int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight, int bufferMask); // Blit active framebuffer to main framebuffer +RLAPI void rlBindFramebuffer(unsigned int target, unsigned int framebuffer); // Bind framebuffer (FBO) + +// General render state +RLAPI void rlEnableColorBlend(void); // Enable color blending +RLAPI void rlDisableColorBlend(void); // Disable color blending +RLAPI void rlEnableDepthTest(void); // Enable depth test +RLAPI void rlDisableDepthTest(void); // Disable depth test +RLAPI void rlEnableDepthMask(void); // Enable depth write +RLAPI void rlDisableDepthMask(void); // Disable depth write +RLAPI void rlEnableBackfaceCulling(void); // Enable backface culling +RLAPI void rlDisableBackfaceCulling(void); // Disable backface culling +RLAPI void rlColorMask(bool r, bool g, bool b, bool a); // Color mask control +RLAPI void rlSetCullFace(int mode); // Set face culling mode +RLAPI void rlEnableScissorTest(void); // Enable scissor test +RLAPI void rlDisableScissorTest(void); // Disable scissor test +RLAPI void rlScissor(int x, int y, int width, int height); // Scissor test +RLAPI void rlEnablePointMode(void); // Enable point mode +RLAPI void rlDisablePointMode(void); // Disable point mode +RLAPI void rlSetPointSize(float size); // Set the point drawing size +RLAPI float rlGetPointSize(void); // Get the point drawing size +RLAPI void rlEnableWireMode(void); // Enable wire mode +RLAPI void rlDisableWireMode(void); // Disable wire mode +RLAPI void rlSetLineWidth(float width); // Set the line drawing width +RLAPI float rlGetLineWidth(void); // Get the line drawing width +RLAPI void rlEnableSmoothLines(void); // Enable line aliasing +RLAPI void rlDisableSmoothLines(void); // Disable line aliasing +RLAPI void rlEnableStereoRender(void); // Enable stereo rendering +RLAPI void rlDisableStereoRender(void); // Disable stereo rendering +RLAPI bool rlIsStereoRenderEnabled(void); // Check if stereo render is enabled + +RLAPI void rlClearColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a); // Clear color buffer with color +RLAPI void rlClearScreenBuffers(void); // Clear used screen buffers (color and depth) +RLAPI void rlCheckErrors(void); // Check and log OpenGL error codes +RLAPI void rlSetBlendMode(int mode); // Set blending mode +RLAPI void rlSetBlendFactors(int glSrcFactor, int glDstFactor, int glEquation); // Set blending mode factor and equation (using OpenGL factors) +RLAPI void rlSetBlendFactorsSeparate(int glSrcRGB, int glDstRGB, int glSrcAlpha, int glDstAlpha, int glEqRGB, int glEqAlpha); // Set blending mode factors and equations separately (using OpenGL factors) + +//------------------------------------------------------------------------------------ +// Functions Declaration - rlgl functionality +//------------------------------------------------------------------------------------ +// rlgl initialization functions +RLAPI void rlglInit(int width, int height); // Initialize rlgl (buffers, shaders, textures, states) +RLAPI void rlglClose(void); // De-initialize rlgl (buffers, shaders, textures) +RLAPI void rlLoadExtensions(void *loader); // Load OpenGL extensions (loader function required) +RLAPI void *rlGetProcAddress(const char *procName); // Get OpenGL procedure address +RLAPI int rlGetVersion(void); // Get current OpenGL version +RLAPI void rlSetFramebufferWidth(int width); // Set current framebuffer width +RLAPI int rlGetFramebufferWidth(void); // Get default framebuffer width +RLAPI void rlSetFramebufferHeight(int height); // Set current framebuffer height +RLAPI int rlGetFramebufferHeight(void); // Get default framebuffer height + +RLAPI unsigned int rlGetTextureIdDefault(void); // Get default texture id +RLAPI unsigned int rlGetShaderIdDefault(void); // Get default shader id +RLAPI int *rlGetShaderLocsDefault(void); // Get default shader locations + +// Render batch management +// NOTE: rlgl provides a default render batch to behave like OpenGL 1.1 immediate mode +// but this render batch API is exposed in case of custom batches are required +RLAPI rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements); // Load a render batch system +RLAPI void rlUnloadRenderBatch(rlRenderBatch batch); // Unload render batch system +RLAPI void rlDrawRenderBatch(rlRenderBatch *batch); // Draw render batch data (Update->Draw->Reset) +RLAPI void rlSetRenderBatchActive(rlRenderBatch *batch); // Set the active render batch for rlgl (NULL for default internal) +RLAPI void rlDrawRenderBatchActive(void); // Update and draw internal render batch +RLAPI bool rlCheckRenderBatchLimit(int vCount); // Check internal buffer overflow for a given number of vertex + +RLAPI void rlSetTexture(unsigned int id); // Set current texture for render batch and check buffers limits + +//------------------------------------------------------------------------------------------------------------------------ + +// Vertex buffers management +RLAPI unsigned int rlLoadVertexArray(void); // Load vertex array (vao) if supported +RLAPI unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic); // Load a vertex buffer object +RLAPI unsigned int rlLoadVertexBufferElement(const void *buffer, int size, bool dynamic); // Load vertex buffer elements object +RLAPI void rlUpdateVertexBuffer(unsigned int bufferId, const void *data, int dataSize, int offset); // Update vertex buffer object data on GPU buffer +RLAPI void rlUpdateVertexBufferElements(unsigned int id, const void *data, int dataSize, int offset); // Update vertex buffer elements data on GPU buffer +RLAPI void rlUnloadVertexArray(unsigned int vaoId); // Unload vertex array (vao) +RLAPI void rlUnloadVertexBuffer(unsigned int vboId); // Unload vertex buffer object +RLAPI void rlSetVertexAttribute(unsigned int index, int compSize, int type, bool normalized, int stride, int offset); // Set vertex attribute data configuration +RLAPI void rlSetVertexAttributeDivisor(unsigned int index, int divisor); // Set vertex attribute data divisor +RLAPI void rlSetVertexAttributeDefault(int locIndex, const void *value, int attribType, int count); // Set vertex attribute default value, when attribute to provided +RLAPI void rlDrawVertexArray(int offset, int count); // Draw vertex array (currently active vao) +RLAPI void rlDrawVertexArrayElements(int offset, int count, const void *buffer); // Draw vertex array elements +RLAPI void rlDrawVertexArrayInstanced(int offset, int count, int instances); // Draw vertex array (currently active vao) with instancing +RLAPI void rlDrawVertexArrayElementsInstanced(int offset, int count, const void *buffer, int instances); // Draw vertex array elements with instancing + +// Textures management +RLAPI unsigned int rlLoadTexture(const void *data, int width, int height, int format, int mipmapCount); // Load texture data +RLAPI unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer); // Load depth texture/renderbuffer (to be attached to fbo) +RLAPI unsigned int rlLoadTextureCubemap(const void *data, int size, int format, int mipmapCount); // Load texture cubemap data +RLAPI void rlUpdateTexture(unsigned int id, int offsetX, int offsetY, int width, int height, int format, const void *data); // Update texture with new data on GPU +RLAPI void rlGetGlTextureFormats(int format, unsigned int *glInternalFormat, unsigned int *glFormat, unsigned int *glType); // Get OpenGL internal formats +RLAPI const char *rlGetPixelFormatName(unsigned int format); // Get name string for pixel format +RLAPI void rlUnloadTexture(unsigned int id); // Unload texture from GPU memory +RLAPI void rlGenTextureMipmaps(unsigned int id, int width, int height, int format, int *mipmaps); // Generate mipmap data for selected texture +RLAPI void *rlReadTexturePixels(unsigned int id, int width, int height, int format); // Read texture pixel data +RLAPI unsigned char *rlReadScreenPixels(int width, int height); // Read screen pixel data (color buffer) + +// Framebuffer management (fbo) +RLAPI unsigned int rlLoadFramebuffer(void); // Load an empty framebuffer +RLAPI void rlFramebufferAttach(unsigned int id, unsigned int texId, int attachType, int texType, int mipLevel); // Attach texture/renderbuffer to a framebuffer +RLAPI bool rlFramebufferComplete(unsigned int id); // Verify framebuffer is complete +RLAPI void rlUnloadFramebuffer(unsigned int id); // Delete framebuffer from GPU +// WARNING: Copy and resize framebuffer functionality only defined for software backend +RLAPI void rlCopyFramebuffer(int x, int y, int width, int height, int format, void *pixels); // Copy framebuffer pixel data to internal buffer +RLAPI void rlResizeFramebuffer(int width, int height); // Resize internal framebuffer + +// Shaders management +RLAPI unsigned int rlLoadShader(const char *code, int type); // Load (compile) shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER) +RLAPI unsigned int rlLoadShaderProgram(const char *vsCode, const char *fsCode); // Load shader from code strings +RLAPI unsigned int rlLoadShaderProgramEx(unsigned int vsId, unsigned int fsId); // Load shader program, using already loaded shader ids +RLAPI unsigned int rlLoadShaderProgramCompute(unsigned int csId); // Load compute shader program +RLAPI void rlUnloadShader(unsigned int id); // Unload shader, loaded with rlLoadShader() +RLAPI void rlUnloadShaderProgram(unsigned int id); // Unload shader program +RLAPI int rlGetLocationUniform(unsigned int id, const char *uniformName); // Get shader location uniform, requires shader program id +RLAPI int rlGetLocationAttrib(unsigned int id, const char *attribName); // Get shader location attribute, requires shader program id +RLAPI void rlSetUniform(int locIndex, const void *value, int uniformType, int count); // Set shader value uniform +RLAPI void rlSetUniformMatrix(int locIndex, Matrix mat); // Set shader value matrix +RLAPI void rlSetUniformMatrices(int locIndex, const Matrix *mat, int count); // Set shader value matrices +RLAPI void rlSetUniformSampler(int locIndex, unsigned int textureId); // Set shader value sampler +RLAPI void rlSetShader(unsigned int id, int *locs); // Set shader currently active (id and locations) + +// Compute shader management +RLAPI void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ); // Dispatch compute shader (equivalent to *draw* for graphics pipeline) + +// Shader buffer storage object management (ssbo) +RLAPI unsigned int rlLoadShaderBuffer(unsigned int size, const void *data, int usageHint); // Load shader storage buffer object (SSBO) +RLAPI void rlUnloadShaderBuffer(unsigned int ssboId); // Unload shader storage buffer object (SSBO) +RLAPI void rlUpdateShaderBuffer(unsigned int id, const void *data, unsigned int dataSize, unsigned int offset); // Update SSBO buffer data +RLAPI void rlBindShaderBuffer(unsigned int id, unsigned int index); // Bind SSBO buffer +RLAPI void rlReadShaderBuffer(unsigned int id, void *dest, unsigned int count, unsigned int offset); // Read SSBO buffer data (GPU->CPU) +RLAPI void rlCopyShaderBuffer(unsigned int destId, unsigned int srcId, unsigned int destOffset, unsigned int srcOffset, unsigned int count); // Copy SSBO data between buffers +RLAPI unsigned int rlGetShaderBufferSize(unsigned int id); // Get SSBO buffer size + +// Buffer management +RLAPI void rlBindImageTexture(unsigned int id, unsigned int index, int format, bool readonly); // Bind image texture + +// Matrix state management +RLAPI Matrix rlGetMatrixModelview(void); // Get internal modelview matrix +RLAPI Matrix rlGetMatrixProjection(void); // Get internal projection matrix +RLAPI Matrix rlGetMatrixTransform(void); // Get internal accumulated transform matrix +RLAPI Matrix rlGetMatrixProjectionStereo(int eye); // Get internal projection matrix for stereo render (selected eye) +RLAPI Matrix rlGetMatrixViewOffsetStereo(int eye); // Get internal view offset matrix for stereo render (selected eye) +RLAPI void rlSetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix) +RLAPI void rlSetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix) +RLAPI void rlSetMatrixProjectionStereo(Matrix right, Matrix left); // Set eyes projection matrices for stereo rendering +RLAPI void rlSetMatrixViewOffsetStereo(Matrix right, Matrix left); // Set eyes view offsets matrices for stereo rendering + +// Quick and dirty cube/quad buffers load->draw->unload +RLAPI void rlLoadDrawCube(void); // Load and draw a cube +RLAPI void rlLoadDrawQuad(void); // Load and draw a quad + +#if defined(__cplusplus) +} +#endif + +#endif // RLGL_H + +/*********************************************************************************** +* +* RLGL IMPLEMENTATION +* +************************************************************************************/ + +#if defined(RLGL_IMPLEMENTATION) + +// Expose OpenGL functions from glad in raylib +#if defined(BUILD_LIBTYPE_SHARED) + #define GLAD_API_CALL_EXPORT + #define GLAD_API_CALL_EXPORT_BUILD +#endif + +#if defined(GRAPHICS_API_OPENGL_11) + #if defined(GRAPHICS_API_OPENGL_SOFTWARE) + #define RLSW_IMPLEMENTATION + #define SW_MALLOC(sz) RL_MALLOC(sz) + #define SW_CALLOC(n,sz) RL_CALLOC(n, sz) + #define SW_REALLOC(ptr, newSz) RL_REALLOC(ptr, newSz) + #define SW_FREE(ptr) RL_FREE(ptr) + #include "external/rlsw.h" // OpenGL 1.1 software implementation + #else + #if defined(__APPLE__) + #include // OpenGL 1.1 library for OSX + #include // OpenGL extensions library + #else + // APIENTRY for OpenGL function pointer declarations is required + #if !defined(APIENTRY) + #if defined(_WIN32) + #define APIENTRY __stdcall + #else + #define APIENTRY + #endif + #endif + // WINGDIAPI definition. Some Windows OpenGL headers need it + #if !defined(WINGDIAPI) && defined(_WIN32) + #define WINGDIAPI __declspec(dllimport) + #endif + + #include // OpenGL 1.1 library + #endif + #endif +#endif + +#if defined(GRAPHICS_API_OPENGL_33) + #define GLAD_MALLOC RL_MALLOC + #define GLAD_FREE RL_FREE + + #define GLAD_GL_IMPLEMENTATION + #include "external/glad.h" // GLAD extensions loading library, includes OpenGL headers +#endif + +#if defined(GRAPHICS_API_OPENGL_ES3) + #include // OpenGL ES 3.0 library + #define GL_GLEXT_PROTOTYPES + #include // OpenGL ES 2.0 extensions library +#elif defined(GRAPHICS_API_OPENGL_ES2) + // NOTE: OpenGL ES 2.0 can be enabled on Desktop platforms, + // in that case, functions are loaded from a custom glad for OpenGL ES 2.0 + // TODO: OpenGL ES 2.0 support shouldn't be platform-dependent, neither require GLAD + #if defined(PLATFORM_DESKTOP_GLFW) || defined(PLATFORM_DESKTOP_SDL) + #define GLAD_GLES2_IMPLEMENTATION + #include "external/glad_gles2.h" + #else + #define GL_GLEXT_PROTOTYPES + //#include // EGL library -> not required, platform layer + #include // OpenGL ES 2.0 library + #include // OpenGL ES 2.0 extensions library + #endif + + // It seems OpenGL ES 2.0 instancing entry points are not defined on Raspberry Pi + // provided headers (despite being defined in official Khronos GLES2 headers) + // TODO: Avoid raylib platform-dependent code on rlgl, it should be a completely portable library + #if defined(PLATFORM_DRM) + typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC) (GLenum mode, GLint start, GLsizei count, GLsizei primcount); + typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); + typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISOREXTPROC) (GLuint index, GLuint divisor); + #endif +#endif + +#include // Required for: calloc(), free() +#include // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading] +#include // Required for: sqrtf(), sinf(), cosf(), floor(), log() + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#ifndef PI + #define PI 3.14159265358979323846f +#endif +#ifndef DEG2RAD + #define DEG2RAD (PI/180.0f) +#endif +#ifndef RAD2DEG + #define RAD2DEG (180.0f/PI) +#endif + +#ifndef GL_SHADING_LANGUAGE_VERSION + #define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#endif + +#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT + #define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#endif +#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT + #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#endif +#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT + #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#endif +#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT + #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#endif +#ifndef GL_ETC1_RGB8_OES + #define GL_ETC1_RGB8_OES 0x8D64 +#endif +#ifndef GL_COMPRESSED_RGB8_ETC2 + #define GL_COMPRESSED_RGB8_ETC2 0x9274 +#endif +#ifndef GL_COMPRESSED_RGBA8_ETC2_EAC + #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#endif +#ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG + #define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 +#endif +#ifndef GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG + #define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 +#endif +#ifndef GL_COMPRESSED_RGBA_ASTC_4x4_KHR + #define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93b0 +#endif +#ifndef GL_COMPRESSED_RGBA_ASTC_8x8_KHR + #define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93b7 +#endif + +#ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT + #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#endif +#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT + #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#endif + +#ifndef GL_PROGRAM_POINT_SIZE + #define GL_PROGRAM_POINT_SIZE 0x8642 +#endif + +#ifndef GL_LINE_WIDTH + #define GL_LINE_WIDTH 0x0B21 +#endif + +#if defined(GRAPHICS_API_OPENGL_11) + #define GL_UNSIGNED_SHORT_5_6_5 0x8363 + #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 + #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#endif + +#if defined(GRAPHICS_API_OPENGL_21) + #define GL_LUMINANCE 0x1909 + #define GL_LUMINANCE_ALPHA 0x190A +#endif + +#if defined(GRAPHICS_API_OPENGL_ES2) + #define glClearDepth glClearDepthf + #if !defined(GRAPHICS_API_OPENGL_ES3) + #define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER + #define GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER + #endif +#endif + +// Default shader vertex attribute names to set location points +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION + #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD + #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL + #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR + #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT + #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 + #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES + #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES "vertexBoneIndices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS + #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS +#endif + +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM + #define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM +#endif + +#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MVP + #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix +#endif +#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW + #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix +#endif +#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION + #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix +#endif +#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL + #define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix +#endif +#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL + #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView)) +#endif +#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR + #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color) +#endif +#ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 + #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0) +#endif +#ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 + #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1) +#endif +#ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 + #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2) +#endif +#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES + #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // bone matrices (required for GPU skinning) +#endif + +//---------------------------------------------------------------------------------- +// Module Types and Structures Definition +//---------------------------------------------------------------------------------- +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + +typedef void *(*rlglLoadProc)(const char *name); // OpenGL extension functions loader signature (same as GLADloadproc) + +typedef struct rlglData { + rlRenderBatch *currentBatch; // Current render batch + rlRenderBatch defaultBatch; // Default internal render batch + + rlglLoadProc loader; // OpenGL function loader + + struct { + int vertexCounter; // Current active render batch vertex counter (generic, used for all batches) + float texcoordx, texcoordy; // Current active texture coordinate (added on glVertex*()) + float normalx, normaly, normalz; // Current active normal (added on glVertex*()) + unsigned char colorr, colorg, colorb, colora; // Current active color (added on glVertex*()) + + int currentMatrixMode; // Current matrix mode + Matrix *currentMatrix; // Current matrix pointer + Matrix modelview; // Default modelview matrix + Matrix projection; // Default projection matrix + Matrix transform; // Transform matrix to be used with rlTranslate, rlRotate, rlScale + bool transformRequired; // Require transform matrix application to current draw-call vertex (if required) + Matrix stack[RL_MAX_MATRIX_STACK_SIZE];// Matrix stack for push/pop + int stackCounter; // Matrix stack counter + + unsigned int currentTextureId; // Current texture id to be used on glBegin + unsigned int defaultTextureId; // Default texture used on shapes/poly drawing (required by shader) + unsigned int activeTextureId[RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS]; // Active texture ids to be enabled on batch drawing (0 active by default) + unsigned int defaultVShaderId; // Default vertex shader id (used by default shader program) + unsigned int defaultFShaderId; // Default fragment shader id (used by default shader program) + unsigned int defaultShaderId; // Default shader program id, supports vertex color and diffuse texture + int *defaultShaderLocs; // Default shader locations pointer to be used on rendering + unsigned int currentShaderId; // Current shader id to be used on rendering (by default, defaultShaderId) + int *currentShaderLocs; // Current shader locations pointer to be used on rendering (by default, defaultShaderLocs) + + bool stereoRender; // Stereo rendering flag + Matrix projectionStereo[2]; // VR stereo rendering eyes projection matrices + Matrix viewOffsetStereo[2]; // VR stereo rendering eyes view offset matrices + + // Blending variables + int currentBlendMode; // Blending mode active + int glBlendSrcFactor; // Blending source factor + int glBlendDstFactor; // Blending destination factor + int glBlendEquation; // Blending equation + int glBlendSrcFactorRGB; // Blending source RGB factor + int glBlendDestFactorRGB; // Blending destination RGB factor + int glBlendSrcFactorAlpha; // Blending source alpha factor + int glBlendDestFactorAlpha; // Blending destination alpha factor + int glBlendEquationRGB; // Blending equation for RGB + int glBlendEquationAlpha; // Blending equation for alpha + bool glCustomBlendModeModified; // Custom blending factor and equation modification status + + int framebufferWidth; // Current framebuffer width + int framebufferHeight; // Current framebuffer height + + } State; // Renderer state + struct { + bool vao; // VAO support (OpenGL ES2 could not support VAO extension) (GL_ARB_vertex_array_object) + bool instancing; // Instancing supported (GL_ANGLE_instanced_arrays, GL_EXT_draw_instanced + GL_EXT_instanced_arrays) + bool texNPOT; // NPOT textures full support (GL_ARB_texture_non_power_of_two, GL_OES_texture_npot) + bool texDepth; // Depth textures supported (GL_ARB_depth_texture, GL_OES_depth_texture) + bool texDepthWebGL; // Depth textures supported WebGL specific (GL_WEBGL_depth_texture) + bool texFloat32; // float textures support (32 bit per channel) (GL_OES_texture_float) + bool texFloat16; // half float textures support (16 bit per channel) (GL_OES_texture_half_float) + bool texCompDXT; // DDS texture compression support (GL_EXT_texture_compression_s3tc, GL_WEBGL_compressed_texture_s3tc, GL_WEBKIT_WEBGL_compressed_texture_s3tc) + bool texCompETC1; // ETC1 texture compression support (GL_OES_compressed_ETC1_RGB8_texture, GL_WEBGL_compressed_texture_etc1) + bool texCompETC2; // ETC2/EAC texture compression support (GL_ARB_ES3_compatibility) + bool texCompPVRT; // PVR texture compression support (GL_IMG_texture_compression_pvrtc) + bool texCompASTC; // ASTC texture compression support (GL_KHR_texture_compression_astc_hdr, GL_KHR_texture_compression_astc_ldr) + bool texMirrorClamp; // Clamp mirror wrap mode supported (GL_EXT_texture_mirror_clamp) + bool texAnisoFilter; // Anisotropic texture filtering support (GL_EXT_texture_filter_anisotropic) + bool computeShader; // Compute shaders support (GL_ARB_compute_shader) + bool ssbo; // Shader storage buffer object support (GL_ARB_shader_storage_buffer_object) + + float maxAnisotropyLevel; // Maximum anisotropy level supported (minimum is 2.0f) + int maxDepthBits; // Maximum bits for depth component + + } ExtSupported; // Extensions supported flags +} rlglData; + +#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static bool isGpuReady = false; +static double rlCullDistanceNear = RL_CULL_DISTANCE_NEAR; +static double rlCullDistanceFar = RL_CULL_DISTANCE_FAR; + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) +static rlglData RLGL = { 0 }; +#endif + +#if defined(GRAPHICS_API_OPENGL_ES2) && !defined(GRAPHICS_API_OPENGL_ES3) +// VAO functions entry points +// NOTE: VAO functionality is exposed through extensions (OES) +static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays = NULL; +static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray = NULL; +static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays = NULL; + +// Instancing functionality entry points +// NOTE: Instancing functionality could be available through extensions +static PFNGLDRAWARRAYSINSTANCEDEXTPROC glDrawArraysInstanced = NULL; +static PFNGLDRAWELEMENTSINSTANCEDEXTPROC glDrawElementsInstanced = NULL; +static PFNGLVERTEXATTRIBDIVISOREXTPROC glVertexAttribDivisor = NULL; +#endif + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) +static void rlLoadShaderDefault(void); // Load default shader +static void rlUnloadShaderDefault(void); // Unload default shader +#if RLGL_SHOW_GL_DETAILS_INFO +static const char *rlGetCompressedFormatName(int format); // Get compressed format official GL identifier name +#endif +#endif + +static int rlGetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture) + +static Matrix rlMatrixIdentity(void); // Get identity matrix +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) +// Auxiliar matrix math functions +typedef struct rl_float16 { float v[16]; } rl_float16; +static rl_float16 rlMatrixToFloatV(Matrix mat); // Get float array of matrix data +#define rlMatrixToFloat(mat) (rlMatrixToFloatV(mat).v) // Get float vector for Matrix +static Matrix rlMatrixMultiply(Matrix left, Matrix right); // Multiply two matrices +static Matrix rlMatrixTranspose(Matrix mat); // Transposes provided matrix +static Matrix rlMatrixInvert(Matrix mat); // Invert provided matrix +#endif + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Matrix operations +//---------------------------------------------------------------------------------- + +#if defined(GRAPHICS_API_OPENGL_11) +// Fallback to OpenGL 1.1 function calls +//--------------------------------------- +void rlMatrixMode(int mode) +{ + switch (mode) + { + case RL_PROJECTION: glMatrixMode(GL_PROJECTION); break; + case RL_MODELVIEW: glMatrixMode(GL_MODELVIEW); break; + case RL_TEXTURE: glMatrixMode(GL_TEXTURE); break; + default: break; + } +} + +void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar) +{ + glFrustum(left, right, bottom, top, znear, zfar); +} + +void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar) +{ + glOrtho(left, right, bottom, top, znear, zfar); +} + +void rlPushMatrix(void) { glPushMatrix(); } +void rlPopMatrix(void) { glPopMatrix(); } +void rlLoadIdentity(void) { glLoadIdentity(); } +void rlTranslatef(float x, float y, float z) { glTranslatef(x, y, z); } +void rlRotatef(float angle, float x, float y, float z) { glRotatef(angle, x, y, z); } +void rlScalef(float x, float y, float z) { glScalef(x, y, z); } +void rlMultMatrixf(const float *matf) { glMultMatrixf(matf); } +#endif +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) +// Choose the current matrix to be transformed +void rlMatrixMode(int mode) +{ + if (mode == RL_PROJECTION) RLGL.State.currentMatrix = &RLGL.State.projection; + else if (mode == RL_MODELVIEW) RLGL.State.currentMatrix = &RLGL.State.modelview; + //else if (mode == RL_TEXTURE) // Not supported + + RLGL.State.currentMatrixMode = mode; +} + +// Push the current matrix into RLGL.State.stack +void rlPushMatrix(void) +{ + if (RLGL.State.stackCounter >= RL_MAX_MATRIX_STACK_SIZE) TRACELOG(RL_LOG_ERROR, "RLGL: Matrix stack overflow (RL_MAX_MATRIX_STACK_SIZE)"); + + if (RLGL.State.currentMatrixMode == RL_MODELVIEW) + { + RLGL.State.transformRequired = true; + RLGL.State.currentMatrix = &RLGL.State.transform; + } + + RLGL.State.stack[RLGL.State.stackCounter] = *RLGL.State.currentMatrix; + RLGL.State.stackCounter++; +} + +// Pop latest inserted matrix from RLGL.State.stack +void rlPopMatrix(void) +{ + if (RLGL.State.stackCounter > 0) + { + Matrix mat = RLGL.State.stack[RLGL.State.stackCounter - 1]; + *RLGL.State.currentMatrix = mat; + RLGL.State.stackCounter--; + } + + if ((RLGL.State.stackCounter == 0) && (RLGL.State.currentMatrixMode == RL_MODELVIEW)) + { + RLGL.State.currentMatrix = &RLGL.State.modelview; + RLGL.State.transformRequired = false; + } +} + +// Reset current matrix to identity matrix +void rlLoadIdentity(void) +{ + *RLGL.State.currentMatrix = rlMatrixIdentity(); +} + +// Multiply the current matrix by a translation matrix +void rlTranslatef(float x, float y, float z) +{ + Matrix matTranslation = rlMatrixIdentity(); + + // Set translation component of matrix + matTranslation.m12 = x; + matTranslation.m13 = y; + matTranslation.m14 = z; + + // NOTE: Transposing matrix by multiplication order + *RLGL.State.currentMatrix = rlMatrixMultiply(matTranslation, *RLGL.State.currentMatrix); +} + +// Multiply the current matrix by a rotation matrix +// NOTE: The provided angle must be in degrees +void rlRotatef(float angle, float x, float y, float z) +{ + Matrix matRotation = rlMatrixIdentity(); + + // Axis vector (x, y, z) normalization + float lengthSquared = x*x + y*y + z*z; + if ((lengthSquared != 1.0f) && (lengthSquared != 0.0f)) + { + float inverseLength = 1.0f/sqrtf(lengthSquared); + x *= inverseLength; + y *= inverseLength; + z *= inverseLength; + } + + // Rotation matrix generation + float sinres = sinf(DEG2RAD*angle); + float cosres = cosf(DEG2RAD*angle); + float t = 1.0f - cosres; + + matRotation.m0 = x*x*t + cosres; + matRotation.m1 = y*x*t + z*sinres; + matRotation.m2 = z*x*t - y*sinres; + matRotation.m3 = 0.0f; + + matRotation.m4 = x*y*t - z*sinres; + matRotation.m5 = y*y*t + cosres; + matRotation.m6 = z*y*t + x*sinres; + matRotation.m7 = 0.0f; + + matRotation.m8 = x*z*t + y*sinres; + matRotation.m9 = y*z*t - x*sinres; + matRotation.m10 = z*z*t + cosres; + matRotation.m11 = 0.0f; + + matRotation.m12 = 0.0f; + matRotation.m13 = 0.0f; + matRotation.m14 = 0.0f; + matRotation.m15 = 1.0f; + + // NOTE: Transposing matrix by multiplication order + *RLGL.State.currentMatrix = rlMatrixMultiply(matRotation, *RLGL.State.currentMatrix); +} + +// Multiply the current matrix by a scaling matrix +void rlScalef(float x, float y, float z) +{ + Matrix matScale = rlMatrixIdentity(); + + // Set scale component of matrix + matScale.m0 = x; + matScale.m5 = y; + matScale.m10 = z; + + // NOTE: Transposing matrix by multiplication order + *RLGL.State.currentMatrix = rlMatrixMultiply(matScale, *RLGL.State.currentMatrix); +} + +// Multiply the current matrix by another matrix +void rlMultMatrixf(const float *matf) +{ + // Matrix creation from array + // Conversion from column-major to row-major memory order + Matrix mat = { matf[0], matf[4], matf[8], matf[12], + matf[1], matf[5], matf[9], matf[13], + matf[2], matf[6], matf[10], matf[14], + matf[3], matf[7], matf[11], matf[15] }; + + *RLGL.State.currentMatrix = rlMatrixMultiply(mat, *RLGL.State.currentMatrix); +} + +// Multiply the current matrix by a perspective matrix generated by parameters +void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar) +{ + Matrix matFrustum = { 0 }; + + float rl = (float)(right - left); + float tb = (float)(top - bottom); + float fn = (float)(zfar - znear); + + matFrustum.m0 = ((float) znear*2.0f)/rl; + matFrustum.m1 = 0.0f; + matFrustum.m2 = 0.0f; + matFrustum.m3 = 0.0f; + + matFrustum.m4 = 0.0f; + matFrustum.m5 = ((float) znear*2.0f)/tb; + matFrustum.m6 = 0.0f; + matFrustum.m7 = 0.0f; + + matFrustum.m8 = ((float)right + (float)left)/rl; + matFrustum.m9 = ((float)top + (float)bottom)/tb; + matFrustum.m10 = -((float)zfar + (float)znear)/fn; + matFrustum.m11 = -1.0f; + + matFrustum.m12 = 0.0f; + matFrustum.m13 = 0.0f; + matFrustum.m14 = -((float)zfar*(float)znear*2.0f)/fn; + matFrustum.m15 = 0.0f; + + *RLGL.State.currentMatrix = rlMatrixMultiply(*RLGL.State.currentMatrix, matFrustum); +} + +// Multiply the current matrix by an orthographic matrix generated by parameters +void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar) +{ + // NOTE: If left-right and top-botton values are equal it could create a division by zero, + // response to it is platform/compiler dependent + Matrix matOrtho = { 0 }; + + float rl = (float)(right - left); + float tb = (float)(top - bottom); + float fn = (float)(zfar - znear); + + matOrtho.m0 = 2.0f/rl; + matOrtho.m1 = 0.0f; + matOrtho.m2 = 0.0f; + matOrtho.m3 = 0.0f; + matOrtho.m4 = 0.0f; + matOrtho.m5 = 2.0f/tb; + matOrtho.m6 = 0.0f; + matOrtho.m7 = 0.0f; + matOrtho.m8 = 0.0f; + matOrtho.m9 = 0.0f; + matOrtho.m10 = -2.0f/fn; + matOrtho.m11 = 0.0f; + matOrtho.m12 = -((float)left + (float)right)/rl; + matOrtho.m13 = -((float)top + (float)bottom)/tb; + matOrtho.m14 = -((float)zfar + (float)znear)/fn; + matOrtho.m15 = 1.0f; + + *RLGL.State.currentMatrix = rlMatrixMultiply(*RLGL.State.currentMatrix, matOrtho); +} +#endif + +// Set the viewport area (transformation from normalized device coordinates to window coordinates) +void rlViewport(int x, int y, int width, int height) +{ + glViewport(x, y, width, height); +} + +// Set clip planes distances +void rlSetClipPlanes(double nearPlane, double farPlane) +{ + rlCullDistanceNear = nearPlane; + rlCullDistanceFar = farPlane; +} + +// Get cull plane distance near +double rlGetCullDistanceNear(void) +{ + return rlCullDistanceNear; +} + +// Get cull plane distance far +double rlGetCullDistanceFar(void) +{ + return rlCullDistanceFar; +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Vertex level operations +//---------------------------------------------------------------------------------- +#if defined(GRAPHICS_API_OPENGL_11) +// Fallback to OpenGL 1.1 function calls +//--------------------------------------- +void rlBegin(int mode) +{ + switch (mode) + { + case RL_LINES: glBegin(GL_LINES); break; + case RL_TRIANGLES: glBegin(GL_TRIANGLES); break; + case RL_QUADS: glBegin(GL_QUADS); break; + default: break; + } +} + +void rlEnd(void) { glEnd(); } +void rlVertex2i(int x, int y) { glVertex2i(x, y); } +void rlVertex2f(float x, float y) { glVertex2f(x, y); } +void rlVertex3f(float x, float y, float z) { glVertex3f(x, y, z); } +void rlTexCoord2f(float x, float y) { glTexCoord2f(x, y); } +void rlNormal3f(float x, float y, float z) { glNormal3f(x, y, z); } +void rlColor4ub(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { glColor4ub(r, g, b, a); } +void rlColor3f(float x, float y, float z) { glColor3f(x, y, z); } +void rlColor4f(float x, float y, float z, float w) { glColor4f(x, y, z, w); } +#endif +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) +// Initialize drawing mode (how to organize vertex) +void rlBegin(int mode) +{ + // Draw mode can be RL_LINES, RL_TRIANGLES and RL_QUADS + // NOTE: In all three cases, vertex are accumulated over default internal vertex buffer + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode != mode) + { + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount > 0) + { + // Make sure current RLGL.currentBatch->draws[i].vertexCount is aligned a multiple of 4, + // that way, following QUADS drawing will keep aligned with index processing + // It implies adding some extra alignment vertex at the end of the draw, + // those vertex are not processed but they are considered as an additional offset + // for the next set of vertex to be drawn + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_LINES) RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount < 4)? RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount : RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%4); + else if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_TRIANGLES) RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%4))); + else RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = 0; + + if (!rlCheckRenderBatchLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment)) + { + RLGL.State.vertexCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment; + RLGL.currentBatch->drawCounter++; + } + } + + if (RLGL.currentBatch->drawCounter >= RL_DEFAULT_BATCH_DRAWCALLS) rlDrawRenderBatch(RLGL.currentBatch); + + RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode = mode; + RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = RLGL.State.currentTextureId; + RLGL.State.currentTextureId = RLGL.State.defaultTextureId; + } +} + +// Finish vertex providing +void rlEnd(void) +{ + // NOTE: Depth increment is dependent on rlOrtho(): z-near and z-far values, + // as well as depth buffer bit-depth (16bit or 24bit or 32bit) + // Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits) + RLGL.currentBatch->currentDepth += (1.0f/20000.0f); +} + +// Define one vertex (position) +// NOTE: Vertex position data is the basic information required for drawing +void rlVertex3f(float x, float y, float z) +{ + float tx = x; + float ty = y; + float tz = z; + + // Transform provided vector if required + if (RLGL.State.transformRequired) + { + tx = RLGL.State.transform.m0*x + RLGL.State.transform.m4*y + RLGL.State.transform.m8*z + RLGL.State.transform.m12; + ty = RLGL.State.transform.m1*x + RLGL.State.transform.m5*y + RLGL.State.transform.m9*z + RLGL.State.transform.m13; + tz = RLGL.State.transform.m2*x + RLGL.State.transform.m6*y + RLGL.State.transform.m10*z + RLGL.State.transform.m14; + } + + // WARNING: Be careful with primitives breaking when launching a new batch! + // RL_LINES comes in pairs, RL_TRIANGLES come in groups of 3 vertices and RL_QUADS come in groups of 4 vertices + // Checking current draw.mode when a new vertex is required and finish the batch only if the draw.mode draw.vertexCount is %2, %3 or %4 + if (RLGL.State.vertexCounter > (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4 - 4)) + { + if ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_LINES) && + (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%2 == 0)) + { + // Reached the maximum number of vertices for RL_LINES drawing + // Launch a draw call but keep current state for next vertices comming + // NOTE: Adding +1 vertex to the check for some safety + rlCheckRenderBatchLimit(2 + 1); + } + else if ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_TRIANGLES) && + (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%3 == 0)) + { + rlCheckRenderBatchLimit(3 + 1); + } + else if ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_QUADS) && + (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%4 == 0)) + { + rlCheckRenderBatchLimit(4 + 1); + } + } + + // Add vertices + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.State.vertexCounter] = tx; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.State.vertexCounter + 1] = ty; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].vertices[3*RLGL.State.vertexCounter + 2] = tz; + + // Add current texcoord + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.State.vertexCounter] = RLGL.State.texcoordx; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].texcoords[2*RLGL.State.vertexCounter + 1] = RLGL.State.texcoordy; + + // Add current normal + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].normals[3*RLGL.State.vertexCounter] = RLGL.State.normalx; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].normals[3*RLGL.State.vertexCounter + 1] = RLGL.State.normaly; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].normals[3*RLGL.State.vertexCounter + 2] = RLGL.State.normalz; + + // Add current color + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.State.vertexCounter] = RLGL.State.colorr; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.State.vertexCounter + 1] = RLGL.State.colorg; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.State.vertexCounter + 2] = RLGL.State.colorb; + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].colors[4*RLGL.State.vertexCounter + 3] = RLGL.State.colora; + + RLGL.State.vertexCounter++; + RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount++; +} + +// Define one vertex (position) +void rlVertex2f(float x, float y) +{ + rlVertex3f(x, y, RLGL.currentBatch->currentDepth); +} + +// Define one vertex (position) +void rlVertex2i(int x, int y) +{ + rlVertex3f((float)x, (float)y, RLGL.currentBatch->currentDepth); +} + +// Define one vertex (texture coordinate) +// NOTE: Texture coordinates are limited to QUADS only +void rlTexCoord2f(float x, float y) +{ + RLGL.State.texcoordx = x; + RLGL.State.texcoordy = y; +} + +// Define one vertex (normal) +// NOTE: Normals limited to TRIANGLES only? +void rlNormal3f(float x, float y, float z) +{ + float normalx = x; + float normaly = y; + float normalz = z; + if (RLGL.State.transformRequired) + { + normalx = RLGL.State.transform.m0*x + RLGL.State.transform.m4*y + RLGL.State.transform.m8*z; + normaly = RLGL.State.transform.m1*x + RLGL.State.transform.m5*y + RLGL.State.transform.m9*z; + normalz = RLGL.State.transform.m2*x + RLGL.State.transform.m6*y + RLGL.State.transform.m10*z; + } + + // NOTE: Default behavior assumes the normal vector is in the correct space for what the shader expects, + // it could be not normalized to 0.0f..1.0f, magnitud can be useed for some effects + /* + // WARNING: Vector normalization if required + float length = sqrtf(normalx*normalx + normaly*normaly + normalz*normalz); + if (length != 0.0f) + { + float ilength = 1.0f/length; + normalx *= ilength; + normaly *= ilength; + normalz *= ilength; + } + */ + RLGL.State.normalx = normalx; + RLGL.State.normaly = normaly; + RLGL.State.normalz = normalz; +} + +// Define one vertex (color) +void rlColor4ub(unsigned char x, unsigned char y, unsigned char z, unsigned char w) +{ + RLGL.State.colorr = x; + RLGL.State.colorg = y; + RLGL.State.colorb = z; + RLGL.State.colora = w; +} + +// Define one vertex (color) +void rlColor4f(float r, float g, float b, float a) +{ + rlColor4ub((unsigned char)(r*255), (unsigned char)(g*255), (unsigned char)(b*255), (unsigned char)(a*255)); +} + +// Define one vertex (color) +void rlColor3f(float x, float y, float z) +{ + rlColor4ub((unsigned char)(x*255), (unsigned char)(y*255), (unsigned char)(z*255), 255); +} + +#endif + +//-------------------------------------------------------------------------------------- +// Module Functions Definition - OpenGL style functions (common to 1.1, 3.3+, ES2) +//-------------------------------------------------------------------------------------- + +// Set current texture to use +void rlSetTexture(unsigned int id) +{ + if (id == 0) + { +#if defined(GRAPHICS_API_OPENGL_11) + rlDisableTexture(); +#else + // NOTE: If quads batch limit is reached, force a draw call and next batch starts + if (RLGL.State.vertexCounter >= + RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4) + { + rlDrawRenderBatch(RLGL.currentBatch); + } + RLGL.State.currentTextureId = RLGL.State.defaultTextureId; +#endif + } + else + { +#if defined(GRAPHICS_API_OPENGL_11) + rlEnableTexture(id); +#else + RLGL.State.currentTextureId = id; + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId != id) + { + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount > 0) + { + // Make sure current RLGL.currentBatch->draws[i].vertexCount is aligned a multiple of 4, + // that way, following QUADS drawing will keep aligned with index processing + // It implies adding some extra alignment vertex at the end of the draw, + // those vertex are not processed but they are considered as an additional offset + // for the next set of vertex to be drawn + if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_LINES) RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount < 4)? RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount : RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%4); + else if (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_TRIANGLES) RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount < 4)? 1 : (4 - (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%4))); + else RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment = 0; + + if (!rlCheckRenderBatchLimit(RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment)) + { + RLGL.State.vertexCounter += RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexAlignment; + + RLGL.currentBatch->drawCounter++; + + RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode = RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 2].mode; + + } + } + + if (RLGL.currentBatch->drawCounter >= RL_DEFAULT_BATCH_DRAWCALLS) rlDrawRenderBatch(RLGL.currentBatch); + + RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = id; + RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount = 0; + } +#endif + } +} + +// Select and active a texture slot +void rlActiveTextureSlot(int slot) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glActiveTexture(GL_TEXTURE0 + slot); +#endif +} + +// Enable texture +void rlEnableTexture(unsigned int id) +{ +#if defined(GRAPHICS_API_OPENGL_11) + glEnable(GL_TEXTURE_2D); +#endif + glBindTexture(GL_TEXTURE_2D, id); +} + +// Disable texture +void rlDisableTexture(void) +{ +#if defined(GRAPHICS_API_OPENGL_11) + glDisable(GL_TEXTURE_2D); +#endif + glBindTexture(GL_TEXTURE_2D, 0); +} + +// Enable texture cubemap +void rlEnableTextureCubemap(unsigned int id) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindTexture(GL_TEXTURE_CUBE_MAP, id); +#endif +} + +// Disable texture cubemap +void rlDisableTextureCubemap(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); +#endif +} + +// Set texture parameters (wrap mode/filter mode) +void rlTextureParameters(unsigned int id, int param, int value) +{ + glBindTexture(GL_TEXTURE_2D, id); + + switch (param) + { + case RL_TEXTURE_WRAP_S: + case RL_TEXTURE_WRAP_T: + { + if (value == RL_TEXTURE_WRAP_MIRROR_CLAMP) + { +#if !defined(GRAPHICS_API_OPENGL_11) + if (RLGL.ExtSupported.texMirrorClamp) glTexParameteri(GL_TEXTURE_2D, param, value); + else TRACELOG(RL_LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)"); +#endif + } + else glTexParameteri(GL_TEXTURE_2D, param, value); + } break; + case RL_TEXTURE_MAG_FILTER: + case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break; + case RL_TEXTURE_FILTER_ANISOTROPIC: + { +#if !defined(GRAPHICS_API_OPENGL_11) + // Reset anisotropy filter, in case it was set + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); + + if (value <= RLGL.ExtSupported.maxAnisotropyLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); + else if (RLGL.ExtSupported.maxAnisotropyLevel > 0.0f) + { + TRACELOG(RL_LOG_WARNING, "GL: Maximum anisotropic filter level supported is %iX", id, (int)RLGL.ExtSupported.maxAnisotropyLevel); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); + } + else TRACELOG(RL_LOG_WARNING, "GL: Anisotropic filtering not supported"); +#endif + } break; +#if defined(GRAPHICS_API_OPENGL_33) + case RL_TEXTURE_MIPMAP_BIAS_RATIO: glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, value/100.0f); +#endif + default: break; + } + + glBindTexture(GL_TEXTURE_2D, 0); +} + +// Set cubemap parameters (wrap mode/filter mode) +void rlCubemapParameters(unsigned int id, int param, int value) +{ +#if !defined(GRAPHICS_API_OPENGL_11) + glBindTexture(GL_TEXTURE_CUBE_MAP, id); + + // Reset anisotropy filter, in case it was set + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f); + + switch (param) + { + case RL_TEXTURE_WRAP_S: + case RL_TEXTURE_WRAP_T: + { + if (value == RL_TEXTURE_WRAP_MIRROR_CLAMP) + { + if (RLGL.ExtSupported.texMirrorClamp) glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); + else TRACELOG(RL_LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)"); + } + else glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); + } break; + case RL_TEXTURE_MAG_FILTER: + case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); break; + case RL_TEXTURE_FILTER_ANISOTROPIC: + { + if (value <= RLGL.ExtSupported.maxAnisotropyLevel) glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); + else if (RLGL.ExtSupported.maxAnisotropyLevel > 0.0f) + { + TRACELOG(RL_LOG_WARNING, "GL: Maximum anisotropic filter level supported is %iX", id, (int)RLGL.ExtSupported.maxAnisotropyLevel); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value); + } + else TRACELOG(RL_LOG_WARNING, "GL: Anisotropic filtering not supported"); + } break; +#if defined(GRAPHICS_API_OPENGL_33) + case RL_TEXTURE_MIPMAP_BIAS_RATIO: glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_LOD_BIAS, value/100.0f); +#endif + default: break; + } + + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); +#endif +} + +// Enable shader program +void rlEnableShader(unsigned int id) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) + glUseProgram(id); +#endif +} + +// Disable shader program +void rlDisableShader(void) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) + glUseProgram(0); +#endif +} + +// Enable rendering to texture (fbo) +void rlEnableFramebuffer(unsigned int id) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) + glBindFramebuffer(GL_FRAMEBUFFER, id); +#endif +} + +// return the active render texture (fbo) +unsigned int rlGetActiveFramebuffer(void) +{ + GLint fboId = 0; +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fboId); +#endif + return fboId; +} + +// Disable rendering to texture +void rlDisableFramebuffer(void) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) + glBindFramebuffer(GL_FRAMEBUFFER, 0); +#endif +} + +// Blit active framebuffer to main framebuffer +void rlBlitFramebuffer(int srcX, int srcY, int srcWidth, int srcHeight, int dstX, int dstY, int dstWidth, int dstHeight, int bufferMask) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3)) + glBlitFramebuffer(srcX, srcY, srcWidth, srcHeight, dstX, dstY, dstWidth, dstHeight, bufferMask, GL_NEAREST); +#endif +} + +// Bind framebuffer object (fbo) +void rlBindFramebuffer(unsigned int target, unsigned int framebuffer) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) + glBindFramebuffer(target, framebuffer); +#endif +} + +// Activate multiple draw color buffers +// NOTE: One color buffer is always active by default +void rlActiveDrawBuffers(int count) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES3)) + // NOTE: Maximum number of draw buffers supported is implementation dependent, + // it can be queried with glGet*() but it must be at least 8 + //GLint maxDrawBuffers = 0; + //glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); + + if (count > 0) + { + if (count > 8) TRACELOG(RL_LOG_WARNING, "GL: Max color buffers limited to 8"); + else + { + unsigned int buffers[8] = { + GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, + GL_COLOR_ATTACHMENT2, + GL_COLOR_ATTACHMENT3, + GL_COLOR_ATTACHMENT4, + GL_COLOR_ATTACHMENT5, + GL_COLOR_ATTACHMENT6, + GL_COLOR_ATTACHMENT7, + }; + + glDrawBuffers(count, buffers); + } + } + else TRACELOG(RL_LOG_WARNING, "GL: One color buffer active by default"); +#endif +} + +//---------------------------------------------------------------------------------- +// General render state configuration +//---------------------------------------------------------------------------------- + +// Enable color blending +void rlEnableColorBlend(void) { glEnable(GL_BLEND); } + +// Disable color blending +void rlDisableColorBlend(void) { glDisable(GL_BLEND); } + +// Enable depth test +void rlEnableDepthTest(void) { glEnable(GL_DEPTH_TEST); } + +// Disable depth test +void rlDisableDepthTest(void) { glDisable(GL_DEPTH_TEST); } + +// Enable depth write +void rlEnableDepthMask(void) { glDepthMask(GL_TRUE); } + +// Disable depth write +void rlDisableDepthMask(void) { glDepthMask(GL_FALSE); } + +// Enable backface culling +void rlEnableBackfaceCulling(void) { glEnable(GL_CULL_FACE); } + +// Disable backface culling +void rlDisableBackfaceCulling(void) { glDisable(GL_CULL_FACE); } + +// Set color mask active for screen read/draw +void rlColorMask(bool r, bool g, bool b, bool a) { glColorMask(r, g, b, a); } + +// Set face culling mode +void rlSetCullFace(int mode) +{ + switch (mode) + { + case RL_CULL_FACE_BACK: glCullFace(GL_BACK); break; + case RL_CULL_FACE_FRONT: glCullFace(GL_FRONT); break; + default: break; + } +} + +// Enable scissor test +void rlEnableScissorTest(void) { glEnable(GL_SCISSOR_TEST); } + +// Disable scissor test +void rlDisableScissorTest(void) { glDisable(GL_SCISSOR_TEST); } + +// Scissor test +void rlScissor(int x, int y, int width, int height) { glScissor(x, y, width, height); } + +// Enable wire mode +void rlEnableWireMode(void) +{ +#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) + // NOTE: glPolygonMode() not available on OpenGL ES + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +#endif +} + +// Disable wire mode +void rlDisableWireMode(void) +{ +#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) + // NOTE: glPolygonMode() not available on OpenGL ES + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +#endif +} + +// Enable point mode +void rlEnablePointMode(void) +{ +#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) + // NOTE: glPolygonMode() not available on OpenGL ES + glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); + glEnable(GL_PROGRAM_POINT_SIZE); +#endif +} + +// Disable point mode +void rlDisablePointMode(void) +{ +#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) + // NOTE: glPolygonMode() not available on OpenGL ES + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +#endif +} + +// Set the line drawing width +void rlSetLineWidth(float width) { glLineWidth(width); } + +// Get the line drawing width +float rlGetLineWidth(void) +{ + float width = 0; + glGetFloatv(GL_LINE_WIDTH, &width); + return width; +} + +// Set the point drawing size +void rlSetPointSize(float size) +{ +#if defined(GRAPHICS_API_OPENGL_11) + glPointSize(size); +#endif +} + +// Get the point drawing size +float rlGetPointSize(void) +{ + float size = 1; +#if defined(GRAPHICS_API_OPENGL_11) + glGetFloatv(GL_POINT_SIZE, &size); +#endif + return size; + +} + +// Enable line aliasing +void rlEnableSmoothLines(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_11) + glEnable(GL_LINE_SMOOTH); +#endif +} + +// Disable line aliasing +void rlDisableSmoothLines(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_11) + glDisable(GL_LINE_SMOOTH); +#endif +} + +// Enable stereo rendering +void rlEnableStereoRender(void) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) + RLGL.State.stereoRender = true; +#endif +} + +// Disable stereo rendering +void rlDisableStereoRender(void) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) + RLGL.State.stereoRender = false; +#endif +} + +// Check if stereo render is enabled +bool rlIsStereoRenderEnabled(void) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) + return RLGL.State.stereoRender; +#else + return false; +#endif +} + +// Clear color buffer with color +void rlClearColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + // Color values clamp to 0.0f(0) and 1.0f(255) + float cr = (float)r/255; + float cg = (float)g/255; + float cb = (float)b/255; + float ca = (float)a/255; + + glClearColor(cr, cg, cb, ca); +} + +// Clear used screen buffers (color and depth) +void rlClearScreenBuffers(void) +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear used buffers: Color and Depth (Depth is used for 3D) + //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Stencil buffer not used... +} + +// Check and log OpenGL error codes +void rlCheckErrors(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + int check = 1; + while (check) + { + const GLenum err = glGetError(); + switch (err) + { + case GL_NO_ERROR: check = 0; break; + case 0x0500: TRACELOG(RL_LOG_WARNING, "GL: Error detected: GL_INVALID_ENUM"); break; + case 0x0501: TRACELOG(RL_LOG_WARNING, "GL: Error detected: GL_INVALID_VALUE"); break; + case 0x0502: TRACELOG(RL_LOG_WARNING, "GL: Error detected: GL_INVALID_OPERATION"); break; + case 0x0503: TRACELOG(RL_LOG_WARNING, "GL: Error detected: GL_STACK_OVERFLOW"); break; + case 0x0504: TRACELOG(RL_LOG_WARNING, "GL: Error detected: GL_STACK_UNDERFLOW"); break; + case 0x0505: TRACELOG(RL_LOG_WARNING, "GL: Error detected: GL_OUT_OF_MEMORY"); break; + case 0x0506: TRACELOG(RL_LOG_WARNING, "GL: Error detected: GL_INVALID_FRAMEBUFFER_OPERATION"); break; + default: TRACELOG(RL_LOG_WARNING, "GL: Error detected: Unknown error code: %x", err); break; + } + } +#endif +} + +// Set blend mode +void rlSetBlendMode(int mode) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if ((RLGL.State.currentBlendMode != mode) || ((mode == RL_BLEND_CUSTOM || mode == RL_BLEND_CUSTOM_SEPARATE) && RLGL.State.glCustomBlendModeModified)) + { + rlDrawRenderBatch(RLGL.currentBatch); + + switch (mode) + { + case RL_BLEND_ALPHA: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); break; + case RL_BLEND_ADDITIVE: glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBlendEquation(GL_FUNC_ADD); break; + case RL_BLEND_MULTIPLIED: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); break; + case RL_BLEND_ADD_COLORS: glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); break; + case RL_BLEND_SUBTRACT_COLORS: glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_SUBTRACT); break; + case RL_BLEND_ALPHA_PREMULTIPLY: glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); break; + case RL_BLEND_CUSTOM: + { + // NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactors() + glBlendFunc(RLGL.State.glBlendSrcFactor, RLGL.State.glBlendDstFactor); glBlendEquation(RLGL.State.glBlendEquation); + } break; + case RL_BLEND_CUSTOM_SEPARATE: + { + // NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactorsSeparate() + glBlendFuncSeparate(RLGL.State.glBlendSrcFactorRGB, RLGL.State.glBlendDestFactorRGB, RLGL.State.glBlendSrcFactorAlpha, RLGL.State.glBlendDestFactorAlpha); + glBlendEquationSeparate(RLGL.State.glBlendEquationRGB, RLGL.State.glBlendEquationAlpha); + } break; + default: break; + } + + RLGL.State.currentBlendMode = mode; + RLGL.State.glCustomBlendModeModified = false; + } +#endif +} + +// Set blending mode factor and equation +void rlSetBlendFactors(int glSrcFactor, int glDstFactor, int glEquation) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if ((RLGL.State.glBlendSrcFactor != glSrcFactor) || + (RLGL.State.glBlendDstFactor != glDstFactor) || + (RLGL.State.glBlendEquation != glEquation)) + { + RLGL.State.glBlendSrcFactor = glSrcFactor; + RLGL.State.glBlendDstFactor = glDstFactor; + RLGL.State.glBlendEquation = glEquation; + + RLGL.State.glCustomBlendModeModified = true; + } +#endif +} + +// Set blending mode factor and equation separately for RGB and alpha +void rlSetBlendFactorsSeparate(int glSrcRGB, int glDstRGB, int glSrcAlpha, int glDstAlpha, int glEqRGB, int glEqAlpha) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if ((RLGL.State.glBlendSrcFactorRGB != glSrcRGB) || + (RLGL.State.glBlendDestFactorRGB != glDstRGB) || + (RLGL.State.glBlendSrcFactorAlpha != glSrcAlpha) || + (RLGL.State.glBlendDestFactorAlpha != glDstAlpha) || + (RLGL.State.glBlendEquationRGB != glEqRGB) || + (RLGL.State.glBlendEquationAlpha != glEqAlpha)) + { + RLGL.State.glBlendSrcFactorRGB = glSrcRGB; + RLGL.State.glBlendDestFactorRGB = glDstRGB; + RLGL.State.glBlendSrcFactorAlpha = glSrcAlpha; + RLGL.State.glBlendDestFactorAlpha = glDstAlpha; + RLGL.State.glBlendEquationRGB = glEqRGB; + RLGL.State.glBlendEquationAlpha = glEqAlpha; + + RLGL.State.glCustomBlendModeModified = true; + } +#endif +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition - OpenGL Debug +//---------------------------------------------------------------------------------- +#if defined(GRAPHICS_API_OPENGL_43) && RLGL_ENABLE_OPENGL_DEBUG_CONTEXT +static void GLAPIENTRY rlDebugMessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) +{ + // Ignore non-significant error/warning codes (NVidia drivers) + // NOTE: Here there are the details with a sample output: + // - #131169 - Framebuffer detailed info: The driver allocated storage for renderbuffer 2. (severity: low) + // - #131185 - Buffer detailed info: Buffer object 1 (bound to GL_ELEMENT_ARRAY_BUFFER_ARB, usage hint is GL_ENUM_88e4) + // will use VIDEO memory as the source for buffer object operations. (severity: low) + // - #131218 - Program/shader state performance warning: Vertex shader in program 7 is being recompiled based on GL state. (severity: medium) + // - #131204 - Texture state usage warning: The texture object (0) bound to texture image unit 0 does not have + // a defined base level and cannot be used for texture mapping. (severity: low) + if ((id == 131169) || (id == 131185) || (id == 131218) || (id == 131204)) return; + + const char *msgSource = NULL; + switch (source) + { + case GL_DEBUG_SOURCE_API: msgSource = "API"; break; + case GL_DEBUG_SOURCE_WINDOW_SYSTEM: msgSource = "WINDOW_SYSTEM"; break; + case GL_DEBUG_SOURCE_SHADER_COMPILER: msgSource = "SHADER_COMPILER"; break; + case GL_DEBUG_SOURCE_THIRD_PARTY: msgSource = "THIRD_PARTY"; break; + case GL_DEBUG_SOURCE_APPLICATION: msgSource = "APPLICATION"; break; + case GL_DEBUG_SOURCE_OTHER: msgSource = "OTHER"; break; + default: break; + } + + const char *msgType = NULL; + switch (type) + { + case GL_DEBUG_TYPE_ERROR: msgType = "ERROR"; break; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: msgType = "DEPRECATED_BEHAVIOR"; break; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: msgType = "UNDEFINED_BEHAVIOR"; break; + case GL_DEBUG_TYPE_PORTABILITY: msgType = "PORTABILITY"; break; + case GL_DEBUG_TYPE_PERFORMANCE: msgType = "PERFORMANCE"; break; + case GL_DEBUG_TYPE_MARKER: msgType = "MARKER"; break; + case GL_DEBUG_TYPE_PUSH_GROUP: msgType = "PUSH_GROUP"; break; + case GL_DEBUG_TYPE_POP_GROUP: msgType = "POP_GROUP"; break; + case GL_DEBUG_TYPE_OTHER: msgType = "OTHER"; break; + default: break; + } + + const char *msgSeverity = "DEFAULT"; + switch (severity) + { + case GL_DEBUG_SEVERITY_LOW: msgSeverity = "LOW"; break; + case GL_DEBUG_SEVERITY_MEDIUM: msgSeverity = "MEDIUM"; break; + case GL_DEBUG_SEVERITY_HIGH: msgSeverity = "HIGH"; break; + case GL_DEBUG_SEVERITY_NOTIFICATION: msgSeverity = "NOTIFICATION"; break; + default: break; + } + + TRACELOG(RL_LOG_WARNING, "GL: OpenGL debug message: %s", message); + TRACELOG(RL_LOG_WARNING, " > Type: %s", msgType); + TRACELOG(RL_LOG_WARNING, " > Source = %s", msgSource); + TRACELOG(RL_LOG_WARNING, " > Severity = %s", msgSeverity); +} +#endif + +//---------------------------------------------------------------------------------- +// Module Functions Definition - rlgl functionality +//---------------------------------------------------------------------------------- + +// Initialize rlgl: OpenGL extensions, default buffers/shaders/textures, OpenGL states +void rlglInit(int width, int height) +{ + isGpuReady = true; + + // Enable OpenGL debug context if requested (and supported) +#if defined(GRAPHICS_API_OPENGL_43) && RLGL_ENABLE_OPENGL_DEBUG_CONTEXT + if ((glDebugMessageCallback != NULL) && (glDebugMessageControl != NULL)) + { + glDebugMessageCallback(rlDebugMessageCallback, 0); + // glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_ERROR, GL_DEBUG_SEVERITY_HIGH, 0, 0, GL_TRUE); + + // Debug context options: + // - GL_DEBUG_OUTPUT - Faster version but not useful for breakpoints + // - GL_DEBUG_OUTPUT_SYNCHRONUS - Callback is in sync with errors, so a breakpoint can be placed on the callback in order to get a stacktrace for the GL error + glEnable(GL_DEBUG_OUTPUT); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + } +#endif + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // Init default white texture + unsigned char pixels[4] = { 255, 255, 255, 255 }; // 1 pixel RGBA (4 bytes) + RLGL.State.defaultTextureId = rlLoadTexture(pixels, 1, 1, RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1); + RLGL.State.currentTextureId = RLGL.State.defaultTextureId; + + if (RLGL.State.defaultTextureId != 0) TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Default texture loaded successfully", RLGL.State.defaultTextureId); + else TRACELOG(RL_LOG_WARNING, "TEXTURE: Failed to load default texture"); + + // Init default Shader (customized for GL 3.3 and ES2) + // Loaded: RLGL.State.defaultShaderId + RLGL.State.defaultShaderLocs + rlLoadShaderDefault(); + RLGL.State.currentShaderId = RLGL.State.defaultShaderId; + RLGL.State.currentShaderLocs = RLGL.State.defaultShaderLocs; + + // Init default vertex arrays buffers + // Simulate that the default shader has the location RL_SHADER_LOC_VERTEX_NORMAL to bind the normal buffer for the default render batch + RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_NORMAL] = RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL; + RLGL.defaultBatch = rlLoadRenderBatch(RL_DEFAULT_BATCH_BUFFERS, RL_DEFAULT_BATCH_BUFFER_ELEMENTS); + RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_NORMAL] = -1; + RLGL.currentBatch = &RLGL.defaultBatch; + + // Init stack matrices (emulating OpenGL 1.1) + for (int i = 0; i < RL_MAX_MATRIX_STACK_SIZE; i++) RLGL.State.stack[i] = rlMatrixIdentity(); + + // Init internal matrices + RLGL.State.transform = rlMatrixIdentity(); + RLGL.State.projection = rlMatrixIdentity(); + RLGL.State.modelview = rlMatrixIdentity(); + RLGL.State.currentMatrix = &RLGL.State.modelview; +#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 + +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) + // Initialize software renderer backend + int result = swInit(width, height); + if (result == 0) + { + TRACELOG(RL_LOG_ERROR, "RLSW: Software renderer initialization failed!"); + exit(-1); + } +#endif + + // Initialize OpenGL default states + //---------------------------------------------------------- + // Init state: Depth test + glDepthFunc(GL_LEQUAL); // Type of depth testing to apply + glDisable(GL_DEPTH_TEST); // Disable depth testing for 2D (only used for 3D) + + // Init state: Blending mode + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Color blending function (how colors are mixed) + glEnable(GL_BLEND); // Enable color blending (required to work with transparencies) + + // Init state: Culling + // NOTE: All shapes/models triangles are drawn CCW + glCullFace(GL_BACK); // Cull the back face (default) + glFrontFace(GL_CCW); // Front face are defined counter clockwise (default) + glEnable(GL_CULL_FACE); // Enable backface culling + +#if defined(GRAPHICS_API_OPENGL_11) + // Init state: Color hints (deprecated in OpenGL 3.0+) + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation + glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation) +#endif +#if defined(GRAPHICS_API_OPENGL_33) + // Init state: Cubemap seamless + glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Seamless cubemaps (not supported on OpenGL ES 2.0) +#endif +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // Store screen size into global variables + RLGL.State.framebufferWidth = width; + RLGL.State.framebufferHeight = height; +#endif + + // Init state: Color/Depth buffers clear + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black) + glClearDepth(1.0f); // Set clear depth value (default) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers (depth buffer required for 3D) + + TRACELOG(RL_LOG_INFO, "RLGL: Default OpenGL state initialized successfully"); + //---------------------------------------------------------- +} + +// Vertex Buffer Object deinitialization (memory free) +void rlglClose(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + rlUnloadRenderBatch(RLGL.defaultBatch); + + rlUnloadShaderDefault(); // Unload default shader + + glDeleteTextures(1, &RLGL.State.defaultTextureId); // Unload default texture + TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Default texture unloaded successfully", RLGL.State.defaultTextureId); +#endif + +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) + swClose(); // Unload sofware renderer resources +#endif + isGpuReady = false; +} + +// Load OpenGL extensions +// NOTE: External loader function must be provided +void rlLoadExtensions(void *loader) +{ +#if defined(GRAPHICS_API_OPENGL_33) // Also defined for GRAPHICS_API_OPENGL_21 + // NOTE: glad is generated and contains only required OpenGL 3.3 Core extensions (and lower versions) + if (gladLoadGL((GLADloadfunc)loader) == 0) TRACELOG(RL_LOG_WARNING, "GLAD: Cannot load OpenGL extensions"); + else TRACELOG(RL_LOG_INFO, "GLAD: OpenGL extensions loaded successfully"); + + // Get number of supported extensions + GLint numExt = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &numExt); + TRACELOG(RL_LOG_INFO, "GL: Supported extensions count: %i", numExt); + +#if RLGL_SHOW_GL_DETAILS_INFO + // Get supported extensions list + // WARNING: glGetStringi() not available on OpenGL 2.1 + TRACELOG(RL_LOG_INFO, "GL: OpenGL extensions:"); + for (int i = 0; i < numExt; i++) TRACELOG(RL_LOG_INFO, " %s", glGetStringi(GL_EXTENSIONS, i)); +#endif + +#if defined(GRAPHICS_API_OPENGL_21) + // Register supported extensions flags + // Optional OpenGL 2.1 extensions + RLGL.ExtSupported.vao = GLAD_GL_ARB_vertex_array_object; + RLGL.ExtSupported.instancing = (GLAD_GL_EXT_draw_instanced && GLAD_GL_ARB_instanced_arrays); + RLGL.ExtSupported.texNPOT = GLAD_GL_ARB_texture_non_power_of_two; + RLGL.ExtSupported.texFloat32 = GLAD_GL_ARB_texture_float; + RLGL.ExtSupported.texFloat16 = GLAD_GL_ARB_texture_float; + RLGL.ExtSupported.texDepth = GLAD_GL_ARB_depth_texture; + RLGL.ExtSupported.maxDepthBits = 32; + RLGL.ExtSupported.texAnisoFilter = GLAD_GL_EXT_texture_filter_anisotropic; + RLGL.ExtSupported.texMirrorClamp = GLAD_GL_EXT_texture_mirror_clamp; +#else + // Register supported extensions flags + // OpenGL 3.3 extensions supported by default (core) + RLGL.ExtSupported.vao = true; + RLGL.ExtSupported.instancing = true; + RLGL.ExtSupported.texNPOT = true; + RLGL.ExtSupported.texFloat32 = true; + RLGL.ExtSupported.texFloat16 = true; + RLGL.ExtSupported.texDepth = true; + RLGL.ExtSupported.maxDepthBits = 32; + RLGL.ExtSupported.texAnisoFilter = true; + RLGL.ExtSupported.texMirrorClamp = true; +#endif + + // Optional OpenGL 3.3 extensions + RLGL.ExtSupported.texCompASTC = GLAD_GL_KHR_texture_compression_astc_hdr && GLAD_GL_KHR_texture_compression_astc_ldr; + RLGL.ExtSupported.texCompDXT = GLAD_GL_EXT_texture_compression_s3tc; // Texture compression: DXT + RLGL.ExtSupported.texCompETC2 = GLAD_GL_ARB_ES3_compatibility; // Texture compression: ETC2/EAC + #if defined(GRAPHICS_API_OPENGL_43) + RLGL.ExtSupported.computeShader = GLAD_GL_ARB_compute_shader; + RLGL.ExtSupported.ssbo = GLAD_GL_ARB_shader_storage_buffer_object; + #endif + +#endif // GRAPHICS_API_OPENGL_33 + +#if defined(GRAPHICS_API_OPENGL_ES3) + // Register supported extensions flags + // OpenGL ES 3.0 extensions supported by default (or it should be) + RLGL.ExtSupported.vao = true; + RLGL.ExtSupported.instancing = true; + RLGL.ExtSupported.texNPOT = true; + RLGL.ExtSupported.texFloat32 = true; + RLGL.ExtSupported.texFloat16 = true; + RLGL.ExtSupported.texDepth = true; + RLGL.ExtSupported.texDepthWebGL = true; + RLGL.ExtSupported.maxDepthBits = 24; + RLGL.ExtSupported.texAnisoFilter = true; + RLGL.ExtSupported.texMirrorClamp = true; + // TODO: Check for additional OpenGL ES 3.0 supported extensions: + //RLGL.ExtSupported.texCompDXT = true; + //RLGL.ExtSupported.texCompETC1 = true; + //RLGL.ExtSupported.texCompETC2 = true; + //RLGL.ExtSupported.texCompPVRT = true; + //RLGL.ExtSupported.texCompASTC = true; + //RLGL.ExtSupported.maxAnisotropyLevel = true; + //RLGL.ExtSupported.computeShader = true; + //RLGL.ExtSupported.ssbo = true; + +#elif defined(GRAPHICS_API_OPENGL_ES2) + + #if defined(PLATFORM_DESKTOP_GLFW) || defined(PLATFORM_DESKTOP_SDL) + // TODO: Support GLAD loader for OpenGL ES 3.0 + if (gladLoadGLES2((GLADloadfunc)loader) == 0) TRACELOG(RL_LOG_WARNING, "GLAD: Cannot load OpenGL ES2.0 functions"); + else TRACELOG(RL_LOG_INFO, "GLAD: OpenGL ES 2.0 loaded successfully"); + #endif + + // Get supported extensions list + GLint numExt = 0; + const char **extList = (const char **)RL_CALLOC(512, sizeof(const char *)); // Allocate 512 strings pointers (2 KB) + const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string + + // NOTE: String duplication rquired because glGetString() returns a const string + int extensionsLength = (int)strlen(extensions); // Get extensions string size in bytes + char *extensionsDup = (char *)RL_CALLOC(extensionsLength + 1, sizeof(char)); // Allocate space for copy with additional EOL byte + strncpy(extensionsDup, extensions, extensionsLength); + extList[numExt] = extensionsDup; + + for (int i = 0; i < extensionsLength; i++) + { + if (extensionsDup[i] == ' ') + { + extensionsDup[i] = '\0'; + numExt++; + extList[numExt] = &extensionsDup[i + 1]; + } + } + + TRACELOG(RL_LOG_INFO, "GL: Supported extensions count: %i", numExt); + +#if RLGL_SHOW_GL_DETAILS_INFO + TRACELOG(RL_LOG_INFO, "GL: OpenGL extensions:"); + for (int i = 0; i < numExt; i++) TRACELOG(RL_LOG_INFO, " %s", extList[i]); +#endif + + // Check required extensions + for (int i = 0; i < numExt; i++) + { + // Check VAO support + // NOTE: Only check on OpenGL ES, OpenGL 3.3 has VAO support as core feature + if (strcmp(extList[i], (const char *)"GL_OES_vertex_array_object") == 0) + { + // The extension is supported by our hardware and driver, try to get related functions pointers + // NOTE: emscripten does not support VAOs natively, it uses emulation and it reduces overall performance... + glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)((rlglLoadProc)loader)("glGenVertexArraysOES"); + glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)((rlglLoadProc)loader)("glBindVertexArrayOES"); + glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSOESPROC)((rlglLoadProc)loader)("glDeleteVertexArraysOES"); + //glIsVertexArray = (PFNGLISVERTEXARRAYOESPROC)loader("glIsVertexArrayOES"); // NOTE: Fails in WebGL, omitted + + if ((glGenVertexArrays != NULL) && (glBindVertexArray != NULL) && (glDeleteVertexArrays != NULL)) RLGL.ExtSupported.vao = true; + } + + // Check instanced rendering support + if (strstr(extList[i], (const char *)"instanced_arrays") != NULL) // Broad check for instanced_arrays + { + // Specific check + if (strcmp(extList[i], (const char *)"GL_ANGLE_instanced_arrays") == 0) // ANGLE + { + glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedANGLE"); + glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedANGLE"); + glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorANGLE"); + } + else if (strcmp(extList[i], (const char *)"GL_EXT_instanced_arrays") == 0) // EXT + { + glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedEXT"); + glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedEXT"); + glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorEXT"); + } + else if (strcmp(extList[i], (const char *)"GL_NV_instanced_arrays") == 0) // NVIDIA GLES + { + glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedNV"); + glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedNV"); + glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorNV"); + } + + // The feature will only be marked as supported if the elements from GL_XXX_instanced_arrays are present + if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; + } + else if (strstr(extList[i], (const char *)"draw_instanced") != NULL) + { + // GL_ANGLE_draw_instanced doesn't exist + if (strcmp(extList[i], (const char *)"GL_EXT_draw_instanced") == 0) + { + glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedEXT"); + glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedEXT"); + } + else if (strcmp(extList[i], (const char *)"GL_NV_draw_instanced") == 0) + { + glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedNV"); + glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedNV"); + } + + // But the functions will at least be loaded if only GL_XX_EXT_draw_instanced exist + if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; + } + + // Check NPOT textures support + // NOTE: Only check on OpenGL ES, OpenGL 3.3 has NPOT textures full support as core feature + if (strcmp(extList[i], (const char *)"GL_OES_texture_npot") == 0) RLGL.ExtSupported.texNPOT = true; + + // Check texture float support + if (strcmp(extList[i], (const char *)"GL_OES_texture_float") == 0) RLGL.ExtSupported.texFloat32 = true; + if (strcmp(extList[i], (const char *)"GL_OES_texture_half_float") == 0) RLGL.ExtSupported.texFloat16 = true; + + // Check depth texture support + if (strcmp(extList[i], (const char *)"GL_OES_depth_texture") == 0) RLGL.ExtSupported.texDepth = true; + if (strcmp(extList[i], (const char *)"GL_WEBGL_depth_texture") == 0) RLGL.ExtSupported.texDepthWebGL = true; // WebGL requires unsized internal format + if (RLGL.ExtSupported.texDepthWebGL) RLGL.ExtSupported.texDepth = true; + + if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) RLGL.ExtSupported.maxDepthBits = 24; // Not available on WebGL + if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) RLGL.ExtSupported.maxDepthBits = 32; // Not available on WebGL + + // Check texture compression support: DXT + if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) || + (strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_s3tc") == 0) || + (strcmp(extList[i], (const char *)"GL_WEBKIT_WEBGL_compressed_texture_s3tc") == 0)) RLGL.ExtSupported.texCompDXT = true; + + // Check texture compression support: ETC1 + if ((strcmp(extList[i], (const char *)"GL_OES_compressed_ETC1_RGB8_texture") == 0) || + (strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_etc1") == 0)) RLGL.ExtSupported.texCompETC1 = true; + + // Check texture compression support: ETC2/EAC + if (strcmp(extList[i], (const char *)"GL_ARB_ES3_compatibility") == 0) RLGL.ExtSupported.texCompETC2 = true; + + // Check texture compression support: PVR + if (strcmp(extList[i], (const char *)"GL_IMG_texture_compression_pvrtc") == 0) RLGL.ExtSupported.texCompPVRT = true; + + // Check texture compression support: ASTC + if (strcmp(extList[i], (const char *)"GL_KHR_texture_compression_astc_hdr") == 0) RLGL.ExtSupported.texCompASTC = true; + + // Check anisotropic texture filter support + if (strcmp(extList[i], (const char *)"GL_EXT_texture_filter_anisotropic") == 0) RLGL.ExtSupported.texAnisoFilter = true; + + // Check clamp mirror wrap mode support + if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) RLGL.ExtSupported.texMirrorClamp = true; + } + + // Free extensions pointers + RL_FREE(extList); + RL_FREE(extensionsDup); // Duplicated string must be deallocated +#endif // GRAPHICS_API_OPENGL_ES2 + + // Check OpenGL information and capabilities + //------------------------------------------------------------------------------ + // Show current OpenGL and GLSL version + TRACELOG(RL_LOG_INFO, "GL: OpenGL device information:"); + TRACELOG(RL_LOG_INFO, " > Vendor: %s", glGetString(GL_VENDOR)); + TRACELOG(RL_LOG_INFO, " > Renderer: %s", glGetString(GL_RENDERER)); + TRACELOG(RL_LOG_INFO, " > Version: %s", glGetString(GL_VERSION)); + TRACELOG(RL_LOG_INFO, " > GLSL: %s", glGetString(GL_SHADING_LANGUAGE_VERSION)); + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + RLGL.loader = (rlglLoadProc)loader; + + // NOTE: Anisotropy levels capability is an extension + #ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT + #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF + #endif + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &RLGL.ExtSupported.maxAnisotropyLevel); + +#if RLGL_SHOW_GL_DETAILS_INFO + // Show some OpenGL GPU capabilities + TRACELOG(RL_LOG_INFO, "GL: OpenGL capabilities:"); + GLint capability = 0; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &capability); + TRACELOG(RL_LOG_INFO, " GL_MAX_TEXTURE_SIZE: %i", capability); + glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &capability); + TRACELOG(RL_LOG_INFO, " GL_MAX_CUBE_MAP_TEXTURE_SIZE: %i", capability); + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &capability); + TRACELOG(RL_LOG_INFO, " GL_MAX_TEXTURE_IMAGE_UNITS: %i", capability); + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &capability); + TRACELOG(RL_LOG_INFO, " GL_MAX_VERTEX_ATTRIBS: %i", capability); + #if !defined(GRAPHICS_API_OPENGL_ES2) + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &capability); + TRACELOG(RL_LOG_INFO, " GL_MAX_UNIFORM_BLOCK_SIZE: %i", capability); + glGetIntegerv(GL_MAX_DRAW_BUFFERS, &capability); + TRACELOG(RL_LOG_INFO, " GL_MAX_DRAW_BUFFERS: %i", capability); + if (RLGL.ExtSupported.texAnisoFilter) TRACELOG(RL_LOG_INFO, " GL_MAX_TEXTURE_MAX_ANISOTROPY: %.0f", RLGL.ExtSupported.maxAnisotropyLevel); + #endif + glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &capability); + TRACELOG(RL_LOG_INFO, " GL_NUM_COMPRESSED_TEXTURE_FORMATS: %i", capability); + GLint *compFormats = (GLint *)RL_CALLOC(capability, sizeof(GLint)); + glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, compFormats); + for (int i = 0; i < capability; i++) TRACELOG(RL_LOG_INFO, " %s", rlGetCompressedFormatName(compFormats[i])); + RL_FREE(compFormats); + +#if defined(GRAPHICS_API_OPENGL_43) + glGetIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &capability); + TRACELOG(RL_LOG_INFO, " GL_MAX_VERTEX_ATTRIB_BINDINGS: %i", capability); + glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &capability); + TRACELOG(RL_LOG_INFO, " GL_MAX_UNIFORM_LOCATIONS: %i", capability); +#endif + +#else // !RLGL_SHOW_GL_DETAILS_INFO + + // Show some basic info about GL supported features + if (RLGL.ExtSupported.vao) TRACELOG(RL_LOG_INFO, "GL: VAO extension detected, VAO functions loaded successfully"); + else TRACELOG(RL_LOG_WARNING, "GL: VAO extension not found, VAO not supported"); + if (RLGL.ExtSupported.texNPOT) TRACELOG(RL_LOG_INFO, "GL: NPOT textures extension detected, full NPOT textures supported"); + else TRACELOG(RL_LOG_WARNING, "GL: NPOT textures extension not found, limited NPOT support (no-mipmaps, no-repeat)"); + if (RLGL.ExtSupported.texCompDXT) TRACELOG(RL_LOG_INFO, "GL: DXT compressed textures supported"); + if (RLGL.ExtSupported.texCompETC1) TRACELOG(RL_LOG_INFO, "GL: ETC1 compressed textures supported"); + if (RLGL.ExtSupported.texCompETC2) TRACELOG(RL_LOG_INFO, "GL: ETC2/EAC compressed textures supported"); + if (RLGL.ExtSupported.texCompPVRT) TRACELOG(RL_LOG_INFO, "GL: PVRT compressed textures supported"); + if (RLGL.ExtSupported.texCompASTC) TRACELOG(RL_LOG_INFO, "GL: ASTC compressed textures supported"); + if (RLGL.ExtSupported.computeShader) TRACELOG(RL_LOG_INFO, "GL: Compute shaders supported"); + if (RLGL.ExtSupported.ssbo) TRACELOG(RL_LOG_INFO, "GL: Shader storage buffer objects supported"); +#endif + +#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 +} + +// Get OpenGL procedure address +void *rlGetProcAddress(const char *procName) +{ + void *func = NULL; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + func = RLGL.loader(procName); +#endif + return func; +} + +// Get current OpenGL version +int rlGetVersion(void) +{ + int glVersion = 0; + +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) + glVersion = RL_OPENGL_SOFTWARE; +#elif defined(GRAPHICS_API_OPENGL_11) + glVersion = RL_OPENGL_11; +#endif +#if defined(GRAPHICS_API_OPENGL_21) + glVersion = RL_OPENGL_21; +#elif defined(GRAPHICS_API_OPENGL_43) + glVersion = RL_OPENGL_43; +#elif defined(GRAPHICS_API_OPENGL_33) + glVersion = RL_OPENGL_33; +#endif +#if defined(GRAPHICS_API_OPENGL_ES3) + glVersion = RL_OPENGL_ES_30; +#elif defined(GRAPHICS_API_OPENGL_ES2) + glVersion = RL_OPENGL_ES_20; +#endif + + return glVersion; +} + +// Set current framebuffer width +void rlSetFramebufferWidth(int width) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + RLGL.State.framebufferWidth = width; +#endif +} + +// Set current framebuffer height +void rlSetFramebufferHeight(int height) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + RLGL.State.framebufferHeight = height; +#endif +} + +// Get default framebuffer width +int rlGetFramebufferWidth(void) +{ + int width = 0; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + width = RLGL.State.framebufferWidth; +#endif + return width; +} + +// Get default framebuffer height +int rlGetFramebufferHeight(void) +{ + int height = 0; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + height = RLGL.State.framebufferHeight; +#endif + return height; +} + +// Get default internal texture (white texture) +// NOTE: Default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8 +unsigned int rlGetTextureIdDefault(void) +{ + unsigned int id = 0; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + id = RLGL.State.defaultTextureId; +#endif + return id; +} + +// Get default shader id +unsigned int rlGetShaderIdDefault(void) +{ + unsigned int id = 0; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + id = RLGL.State.defaultShaderId; +#endif + return id; +} + +// Get default shader locs +int *rlGetShaderLocsDefault(void) +{ + int *locs = NULL; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + locs = RLGL.State.defaultShaderLocs; +#endif + return locs; +} + +// Render batch management +//------------------------------------------------------------------------------------------------ +// Load render batch +rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements) +{ + rlRenderBatch batch = { 0 }; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return batch; } + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // Initialize CPU (RAM) vertex buffers (position, texcoord, color data and indexes) + //-------------------------------------------------------------------------------------------- + batch.vertexBuffer = (rlVertexBuffer *)RL_CALLOC(numBuffers, sizeof(rlVertexBuffer)); + + for (int i = 0; i < numBuffers; i++) + { + batch.vertexBuffer[i].elementCount = bufferElements; + + batch.vertexBuffer[i].vertices = (float *)RL_CALLOC(bufferElements*3*4, sizeof(float)); // 3 float by vertex, 4 vertex by quad + batch.vertexBuffer[i].texcoords = (float *)RL_CALLOC(bufferElements*2*4, sizeof(float)); // 2 float by texcoord, 4 texcoord by quad + batch.vertexBuffer[i].normals = (float *)RL_CALLOC(bufferElements*3*4, sizeof(float)); // 3 float by vertex, 4 vertex by quad + batch.vertexBuffer[i].colors = (unsigned char *)RL_CALLOC(bufferElements*4*4, sizeof(unsigned char)); // 4 float by color, 4 colors by quad +#if defined(GRAPHICS_API_OPENGL_33) + batch.vertexBuffer[i].indices = (unsigned int *)RL_CALLOC(bufferElements*6, sizeof(unsigned int)); // 6 int by quad (indices) +#endif +#if defined(GRAPHICS_API_OPENGL_ES2) + batch.vertexBuffer[i].indices = (unsigned short *)RL_CALLOC(bufferElements*6, sizeof(unsigned short)); // 6 int by quad (indices) +#endif + + for (int j = 0; j < (3*4*bufferElements); j++) batch.vertexBuffer[i].vertices[j] = 0.0f; + for (int j = 0; j < (2*4*bufferElements); j++) batch.vertexBuffer[i].texcoords[j] = 0.0f; + for (int j = 0; j < (3*4*bufferElements); j++) batch.vertexBuffer[i].normals[j] = 0.0f; + for (int j = 0; j < (4*4*bufferElements); j++) batch.vertexBuffer[i].colors[j] = 0; + + int k = 0; + + // Indices can be initialized right now + for (int j = 0; j < (6*bufferElements); j += 6) + { + batch.vertexBuffer[i].indices[j] = 4*k; + batch.vertexBuffer[i].indices[j + 1] = 4*k + 1; + batch.vertexBuffer[i].indices[j + 2] = 4*k + 2; + batch.vertexBuffer[i].indices[j + 3] = 4*k; + batch.vertexBuffer[i].indices[j + 4] = 4*k + 2; + batch.vertexBuffer[i].indices[j + 5] = 4*k + 3; + + k++; + } + + RLGL.State.vertexCounter = 0; + } + + TRACELOG(RL_LOG_INFO, "RLGL: Render batch vertex buffers loaded successfully in RAM (CPU)"); + //-------------------------------------------------------------------------------------------- + + // Upload to GPU (VRAM) vertex data and initialize VAOs/VBOs + //-------------------------------------------------------------------------------------------- + for (int i = 0; i < numBuffers; i++) + { + if (RLGL.ExtSupported.vao) + { + // Initialize Quads VAO + glGenVertexArrays(1, &batch.vertexBuffer[i].vaoId); + glBindVertexArray(batch.vertexBuffer[i].vaoId); + } + + // Quads - Vertex buffers binding and attributes enable + // Vertex position buffer (shader-location = 0) + glGenBuffers(1, &batch.vertexBuffer[i].vboId[0]); + glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[0]); + glBufferData(GL_ARRAY_BUFFER, bufferElements*3*4*sizeof(float), batch.vertexBuffer[i].vertices, GL_DYNAMIC_DRAW); + glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_POSITION]); + glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); + + // Vertex texcoord buffer (shader-location = 1) + glGenBuffers(1, &batch.vertexBuffer[i].vboId[1]); + glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[1]); + glBufferData(GL_ARRAY_BUFFER, bufferElements*2*4*sizeof(float), batch.vertexBuffer[i].texcoords, GL_DYNAMIC_DRAW); + glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_TEXCOORD01]); + glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0); + + // Vertex normal buffer (shader-location = 2) + glGenBuffers(1, &batch.vertexBuffer[i].vboId[2]); + glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[2]); + glBufferData(GL_ARRAY_BUFFER, bufferElements*3*4*sizeof(float), batch.vertexBuffer[i].normals, GL_DYNAMIC_DRAW); + glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_NORMAL]); + glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_NORMAL], 3, GL_FLOAT, 0, 0, 0); + + // Vertex color buffer (shader-location = 3) + glGenBuffers(1, &batch.vertexBuffer[i].vboId[3]); + glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[3]); + glBufferData(GL_ARRAY_BUFFER, bufferElements*4*4*sizeof(unsigned char), batch.vertexBuffer[i].colors, GL_DYNAMIC_DRAW); + glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_COLOR]); + glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + + // Fill index buffer + glGenBuffers(1, &batch.vertexBuffer[i].vboId[4]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[4]); +#if defined(GRAPHICS_API_OPENGL_33) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferElements*6*sizeof(int), batch.vertexBuffer[i].indices, GL_STATIC_DRAW); +#endif +#if defined(GRAPHICS_API_OPENGL_ES2) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferElements*6*sizeof(short), batch.vertexBuffer[i].indices, GL_STATIC_DRAW); +#endif + } + + TRACELOG(RL_LOG_INFO, "RLGL: Render batch vertex buffers loaded successfully in VRAM (GPU)"); + + // Unbind the current VAO + if (RLGL.ExtSupported.vao) glBindVertexArray(0); + //-------------------------------------------------------------------------------------------- + + // Init draw calls tracking system + //-------------------------------------------------------------------------------------------- + batch.draws = (rlDrawCall *)RL_CALLOC(RL_DEFAULT_BATCH_DRAWCALLS, sizeof(rlDrawCall)); + + for (int i = 0; i < RL_DEFAULT_BATCH_DRAWCALLS; i++) + { + batch.draws[i].mode = RL_QUADS; + batch.draws[i].vertexCount = 0; + batch.draws[i].vertexAlignment = 0; + //batch.draws[i].vaoId = 0; + //batch.draws[i].shaderId = 0; + batch.draws[i].textureId = RLGL.State.defaultTextureId; + //batch.draws[i].RLGL.State.projection = rlMatrixIdentity(); + //batch.draws[i].RLGL.State.modelview = rlMatrixIdentity(); + } + + batch.bufferCount = numBuffers; // Record buffer count + batch.drawCounter = 1; // Reset draws counter + batch.currentDepth = -1.0f; // Reset depth value + //-------------------------------------------------------------------------------------------- +#endif + + return batch; +} + +// Unload default internal buffers vertex data from CPU and GPU +void rlUnloadRenderBatch(rlRenderBatch batch) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // Unbind everything + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + // Unload all vertex buffers data + for (int i = 0; i < batch.bufferCount; i++) + { + // Unbind VAO attribs data + if (RLGL.ExtSupported.vao) + { + glBindVertexArray(batch.vertexBuffer[i].vaoId); + glDisableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION); + glDisableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD); + glDisableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL); + glDisableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR); + glBindVertexArray(0); + } + + // Delete VBOs from GPU (VRAM) + glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[0]); + glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[1]); + glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[2]); + glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[3]); + glDeleteBuffers(1, &batch.vertexBuffer[i].vboId[4]); + + // Delete VAOs from GPU (VRAM) + if (RLGL.ExtSupported.vao) glDeleteVertexArrays(1, &batch.vertexBuffer[i].vaoId); + + // Free vertex arrays memory from CPU (RAM) + RL_FREE(batch.vertexBuffer[i].vertices); + RL_FREE(batch.vertexBuffer[i].texcoords); + RL_FREE(batch.vertexBuffer[i].normals); + RL_FREE(batch.vertexBuffer[i].colors); + RL_FREE(batch.vertexBuffer[i].indices); + } + + // Unload arrays + RL_FREE(batch.vertexBuffer); + RL_FREE(batch.draws); +#endif +} + +// Draw render batch +// NOTE: Batch is reseted and current buffer is updated (for multi-buffer config) +void rlDrawRenderBatch(rlRenderBatch *batch) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // Update batch vertex buffers + //------------------------------------------------------------------------------------------------------------ + // NOTE: If there is not vertex data, buffers doesn't need to be updated (vertexCount > 0) + if (RLGL.State.vertexCounter > 0) + { + // Activate elements VAO + if (RLGL.ExtSupported.vao) glBindVertexArray(batch->vertexBuffer[batch->currentBuffer].vaoId); + + // TODO: If no data changed on the CPU arrays there is no need to re-upload data to GPU, + // a flag can be used to detect changes but it would imply keeping a copy buffer and memcmp() both, does it worth it? + + // Vertex positions buffer + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[0]); + glBufferSubData(GL_ARRAY_BUFFER, 0, RLGL.State.vertexCounter*3*sizeof(float), batch->vertexBuffer[batch->currentBuffer].vertices); + //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*batch->vertexBuffer[batch->currentBuffer].elementCount, batch->vertexBuffer[batch->currentBuffer].vertices, GL_DYNAMIC_DRAW); // Update all buffer + + // Texture coordinates buffer + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[1]); + glBufferSubData(GL_ARRAY_BUFFER, 0, RLGL.State.vertexCounter*2*sizeof(float), batch->vertexBuffer[batch->currentBuffer].texcoords); + //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*batch->vertexBuffer[batch->currentBuffer].elementCount, batch->vertexBuffer[batch->currentBuffer].texcoords, GL_DYNAMIC_DRAW); // Update all buffer + + // Normals buffer + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[2]); + glBufferSubData(GL_ARRAY_BUFFER, 0, RLGL.State.vertexCounter*3*sizeof(float), batch->vertexBuffer[batch->currentBuffer].normals); + //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*batch->vertexBuffer[batch->currentBuffer].elementCount, batch->vertexBuffer[batch->currentBuffer].normals, GL_DYNAMIC_DRAW); // Update all buffer + + // Colors buffer + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[3]); + glBufferSubData(GL_ARRAY_BUFFER, 0, RLGL.State.vertexCounter*4*sizeof(unsigned char), batch->vertexBuffer[batch->currentBuffer].colors); + //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*batch->vertexBuffer[batch->currentBuffer].elementCount, batch->vertexBuffer[batch->currentBuffer].colors, GL_DYNAMIC_DRAW); // Update all buffer + + // NOTE: glMapBuffer() causes sync issue + // If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job + // To avoid waiting (idle), glBufferData() can bee called first with NULL pointer before glMapBuffer() + // Doing that, the previous data in PBO will be discarded and glMapBuffer() returns a new + // allocated pointer immediately even if GPU is still working with the previous data + + // Another option: map the buffer object into client's memory + //batch->vertexBuffer[batch->currentBuffer].vertices = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); + //if (batch->vertexBuffer[batch->currentBuffer].vertices) + //{ + // Update vertex data + //} + //glUnmapBuffer(GL_ARRAY_BUFFER); + + // Unbind the current VAO + if (RLGL.ExtSupported.vao) glBindVertexArray(0); + } + //------------------------------------------------------------------------------------------------------------ + + // Draw batch vertex buffers (considering VR stereo if required) + //------------------------------------------------------------------------------------------------------------ + Matrix matProjection = RLGL.State.projection; + Matrix matModelView = RLGL.State.modelview; + + int eyeCount = 1; + if (RLGL.State.stereoRender) eyeCount = 2; + + for (int eye = 0; eye < eyeCount; eye++) + { + if (eyeCount == 2) + { + // Setup current eye viewport (half screen width) + rlViewport(eye*RLGL.State.framebufferWidth/2, 0, RLGL.State.framebufferWidth/2, RLGL.State.framebufferHeight); + + // Set current eye view offset to modelview matrix + rlSetMatrixModelview(rlMatrixMultiply(matModelView, RLGL.State.viewOffsetStereo[eye])); + // Set current eye projection matrix + rlSetMatrixProjection(RLGL.State.projectionStereo[eye]); + } + + // Draw buffers + if (RLGL.State.vertexCounter > 0) + { + // Set current shader and upload current MVP matrix + glUseProgram(RLGL.State.currentShaderId); + + // Create modelview-projection matrix and upload to shader + Matrix matMVP = rlMatrixMultiply(RLGL.State.modelview, RLGL.State.projection); + glUniformMatrix4fv(RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_MVP], 1, false, rlMatrixToFloat(matMVP)); + + if (RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_PROJECTION] != -1) + { + glUniformMatrix4fv(RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_PROJECTION], 1, false, rlMatrixToFloat(RLGL.State.projection)); + } + + // WARNING: For the following setup of the view, model, and normal matrices, it is expected that + // transformations and rendering occur between rlPushMatrix() and rlPopMatrix() + + if (RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_VIEW] != -1) + { + glUniformMatrix4fv(RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_VIEW], 1, false, rlMatrixToFloat(RLGL.State.modelview)); + } + + if (RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_MODEL] != -1) + { + glUniformMatrix4fv(RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_MODEL], 1, false, rlMatrixToFloat(RLGL.State.transform)); + } + + if (RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_NORMAL] != -1) + { + glUniformMatrix4fv(RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_NORMAL], 1, false, rlMatrixToFloat(rlMatrixTranspose(rlMatrixInvert(RLGL.State.transform)))); + } + + if (RLGL.ExtSupported.vao) glBindVertexArray(batch->vertexBuffer[batch->currentBuffer].vaoId); + else + { + // Bind vertex attrib: position (shader-location = 0) + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[0]); + glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_POSITION], 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_POSITION]); + + // Bind vertex attrib: texcoord (shader-location = 1) + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[1]); + glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_TEXCOORD01], 2, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_TEXCOORD01]); + + // Bind vertex attrib: normal (shader-location = 2) + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[2]); + glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_NORMAL], 3, GL_FLOAT, 0, 0, 0); + glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_NORMAL]); + + // Bind vertex attrib: color (shader-location = 3) + glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[3]); + glVertexAttribPointer(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_COLOR], 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0); + glEnableVertexAttribArray(RLGL.State.currentShaderLocs[RL_SHADER_LOC_VERTEX_COLOR]); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[4]); + } + + // Setup some default shader values + glUniform4f(RLGL.State.currentShaderLocs[RL_SHADER_LOC_COLOR_DIFFUSE], 1.0f, 1.0f, 1.0f, 1.0f); + glUniform1i(RLGL.State.currentShaderLocs[RL_SHADER_LOC_MAP_DIFFUSE], 0); // Active default sampler2D: texture0 + + // Activate additional sampler textures + // Those additional textures will be common for all draw calls of the batch + for (int i = 0; i < RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS; i++) + { + if (RLGL.State.activeTextureId[i] > 0) + { + glActiveTexture(GL_TEXTURE0 + 1 + i); + glBindTexture(GL_TEXTURE_2D, RLGL.State.activeTextureId[i]); + } + } + + // Activate default sampler2D texture0 (one texture is always active for default batch shader) + // NOTE: Batch system accumulates calls by texture0 changes, additional textures are enabled for all the draw calls + glActiveTexture(GL_TEXTURE0); + + for (int i = 0, vertexOffset = 0; i < batch->drawCounter; i++) + { + // Bind current draw call texture, activated as GL_TEXTURE0 and bound to sampler2D texture0 by default + glBindTexture(GL_TEXTURE_2D, batch->draws[i].textureId); + + if ((batch->draws[i].mode == RL_LINES) || (batch->draws[i].mode == RL_TRIANGLES)) glDrawArrays(batch->draws[i].mode, vertexOffset, batch->draws[i].vertexCount); + else + { + #if defined(GRAPHICS_API_OPENGL_33) + // The number of indices to be processed needs to be defined: elementCount*6 + // NOTE: The final parameter tells the GPU the offset in bytes from the + // start of the index buffer to the location of the first index to process + glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_INT, (GLvoid *)(vertexOffset/4*6*sizeof(GLuint))); + #endif + #if defined(GRAPHICS_API_OPENGL_ES2) + glDrawElements(GL_TRIANGLES, batch->draws[i].vertexCount/4*6, GL_UNSIGNED_SHORT, (GLvoid *)(vertexOffset/4*6*sizeof(GLushort))); + #endif + } + + vertexOffset += (batch->draws[i].vertexCount + batch->draws[i].vertexAlignment); + } + + if (!RLGL.ExtSupported.vao) + { + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures + } + + if (RLGL.ExtSupported.vao) glBindVertexArray(0); // Unbind VAO + + glUseProgram(0); // Unbind shader program + } + + // Restore viewport to default measures + if (eyeCount == 2) rlViewport(0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight); + //------------------------------------------------------------------------------------------------------------ + + // Reset batch buffers + //------------------------------------------------------------------------------------------------------------ + // Reset vertex counter for next frame + RLGL.State.vertexCounter = 0; + + // Reset depth for next draw + batch->currentDepth = -1.0f; + + // Restore projection/modelview matrices + RLGL.State.projection = matProjection; + RLGL.State.modelview = matModelView; + + // Reset RLGL.currentBatch->draws array + for (int i = 0; i < RL_DEFAULT_BATCH_DRAWCALLS; i++) + { + batch->draws[i].mode = RL_QUADS; + batch->draws[i].vertexCount = 0; + batch->draws[i].textureId = RLGL.State.defaultTextureId; + } + + // Reset active texture units for next batch + for (int i = 0; i < RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS; i++) RLGL.State.activeTextureId[i] = 0; + + // Reset draws counter to one draw for the batch + batch->drawCounter = 1; + //------------------------------------------------------------------------------------------------------------ + + // Change to next buffer in the list (in case of multi-buffering) + batch->currentBuffer++; + if (batch->currentBuffer >= batch->bufferCount) batch->currentBuffer = 0; +#endif +} + +// Set the active render batch for rlgl +void rlSetRenderBatchActive(rlRenderBatch *batch) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + rlDrawRenderBatch(RLGL.currentBatch); + + if (batch != NULL) RLGL.currentBatch = batch; + else RLGL.currentBatch = &RLGL.defaultBatch; +#endif +} + +// Update and draw internal render batch +void rlDrawRenderBatchActive(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + rlDrawRenderBatch(RLGL.currentBatch); // NOTE: Stereo rendering is checked inside +#endif +} + +// Check internal buffer overflow for a given number of vertex +// and force a rlRenderBatch draw call if required +bool rlCheckRenderBatchLimit(int vCount) +{ + bool overflow = false; + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if ((RLGL.State.vertexCounter + vCount) >= + (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4)) + { + overflow = true; + + // Store current primitive drawing mode and texture id + int currentMode = RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode; + int currentTexture = RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId; + + rlDrawRenderBatch(RLGL.currentBatch); // NOTE: Stereo rendering is checked inside + + // Restore state of last batch so new vertices can be added + RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode = currentMode; + RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = currentTexture; + } +#endif + + return overflow; +} + +// Textures data management +//----------------------------------------------------------------------------------------- +// Convert image data to OpenGL texture (returns OpenGL valid Id) +unsigned int rlLoadTexture(const void *data, int width, int height, int format, int mipmapCount) +{ + unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } + + glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding + + // Check texture format support by OpenGL 1.1 (compressed textures not supported) +#if defined(GRAPHICS_API_OPENGL_11) + if (format >= RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) + { + // TODO: Support texture data decompression + TRACELOG(RL_LOG_WARNING, "GL: OpenGL 1.1 does not support GPU compressed texture formats"); + return id; + } +#else + if ((!RLGL.ExtSupported.texCompDXT) && ((format == RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) || (format == RL_PIXELFORMAT_COMPRESSED_DXT1_RGBA) || + (format == RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA) || (format == RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA))) + { + TRACELOG(RL_LOG_WARNING, "GL: DXT compressed texture format not supported"); + return id; + } +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if ((!RLGL.ExtSupported.texCompETC1) && (format == RL_PIXELFORMAT_COMPRESSED_ETC1_RGB)) + { + TRACELOG(RL_LOG_WARNING, "GL: ETC1 compressed texture format not supported"); + return id; + } + + if ((!RLGL.ExtSupported.texCompETC2) && ((format == RL_PIXELFORMAT_COMPRESSED_ETC2_RGB) || (format == RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA))) + { + TRACELOG(RL_LOG_WARNING, "GL: ETC2 compressed texture format not supported"); + return id; + } + + if ((!RLGL.ExtSupported.texCompPVRT) && ((format == RL_PIXELFORMAT_COMPRESSED_PVRT_RGB) || (format == RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA))) + { + TRACELOG(RL_LOG_WARNING, "GL: PVRT compressed texture format not supported"); + return id; + } + + if ((!RLGL.ExtSupported.texCompASTC) && ((format == RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA) || (format == RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA))) + { + TRACELOG(RL_LOG_WARNING, "GL: ASTC compressed texture format not supported"); + return id; + } +#endif +#endif // GRAPHICS_API_OPENGL_11 + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glGenTextures(1, &id); // Generate texture id + + glBindTexture(GL_TEXTURE_2D, id); + + int mipWidth = width; + int mipHeight = height; + int mipOffset = 0; // Mipmap data offset, only used for tracelog + (void)mipOffset; // Used to avoid gcc warnings about unused variable + + // NOTE: Added pointer math separately from function to avoid UBSAN complaining + unsigned char *dataPtr = NULL; + if (data != NULL) dataPtr = (unsigned char *)data; + + // Load the different mipmap levels + for (int i = 0; i < mipmapCount; i++) + { + unsigned int mipSize = rlGetPixelDataSize(mipWidth, mipHeight, format); + + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); + + TRACELOG(RL_LOG_DEBUG, "TEXTURE: Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset); + + if (glInternalFormat != 0) + { + if (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) glTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, glFormat, glType, dataPtr); +#if !defined(GRAPHICS_API_OPENGL_11) + else glCompressedTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, mipSize, dataPtr); +#endif + +#if defined(GRAPHICS_API_OPENGL_33) + if (format == RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) + { + GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + else if (format == RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) + { +#if defined(GRAPHICS_API_OPENGL_21) + GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ALPHA }; +#elif defined(GRAPHICS_API_OPENGL_33) + GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN }; +#endif + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } +#endif + } + + mipWidth /= 2; + mipHeight /= 2; + mipOffset += mipSize; // Increment offset position to next mipmap + if (data != NULL) dataPtr += mipSize; // Increment data pointer to next mipmap + + // Security check for NPOT textures + if (mipWidth < 1) mipWidth = 1; + if (mipHeight < 1) mipHeight = 1; + } + + // Texture parameters configuration + // NOTE: glTexParameteri does NOT affect texture uploading +#if defined(GRAPHICS_API_OPENGL_ES2) + // NOTE: OpenGL ES 2.0 with no GL_OES_texture_npot support (i.e. WebGL) has limited NPOT support, so CLAMP_TO_EDGE must be used + if (RLGL.ExtSupported.texNPOT) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repeat on x-axis + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repeat on y-axis + } + else + { + // NOTE: If using negative texture coordinates (LoadOBJ()), it does not work! + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // Set texture to clamp on x-axis + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // Set texture to clamp on y-axis + } +#else + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repeat on x-axis + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repeat on y-axis +#endif + + // Magnification and minification filters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Alternative: GL_LINEAR + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Alternative: GL_LINEAR + +#if defined(GRAPHICS_API_OPENGL_33) + if (mipmapCount > 1) + { + // Activate trilinear filtering if mipmaps are available + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + + // Define the maximum number of mipmap levels to be used, 0 is base texture size + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapCount - 1); + + // Check if the loaded texture with mipmaps is complete, + // uncomplete textures will draw in black if mipmap filtering is required + //GLint complete = 0; + //glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_IMMUTABLE_FORMAT, &complete); + } +#endif + + // At this point texture is loaded in GPU and texture parameters configured + + // NOTE: If mipmaps were not in data, they are not generated automatically + + // Unbind current texture + glBindTexture(GL_TEXTURE_2D, 0); + + if (id > 0) TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Texture loaded successfully (%ix%i | %s | %i mipmaps)", id, width, height, rlGetPixelFormatName(format), mipmapCount); + else TRACELOG(RL_LOG_WARNING, "TEXTURE: Failed to load texture"); + + return id; +} + +// Load depth texture/renderbuffer (to be attached to fbo) +// WARNING: OpenGL ES 2.0 requires GL_OES_depth_texture and WebGL requires WEBGL_depth_texture extensions +unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) +{ + unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // In case depth textures were not supported, force renderbuffer usage + if (!RLGL.ExtSupported.texDepth) useRenderBuffer = true; + + // NOTE: Letting the implementation to choose the best bit-depth + // Possible formats: GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32 and GL_DEPTH_COMPONENT32F + unsigned int glInternalFormat = GL_DEPTH_COMPONENT; + +#if defined(GRAPHICS_API_OPENGL_ES2) + // WARNING: WebGL platform requires unsized internal format definition (GL_DEPTH_COMPONENT) + // while other platforms using OpenGL ES 2.0 require/support sized internal formats depending on the GPU capabilities + if (!RLGL.ExtSupported.texDepthWebGL || useRenderBuffer) + { + if (RLGL.ExtSupported.maxDepthBits == 32) glInternalFormat = GL_DEPTH_COMPONENT32_OES; + else if (RLGL.ExtSupported.maxDepthBits == 24) glInternalFormat = GL_DEPTH_COMPONENT24_OES; + else glInternalFormat = GL_DEPTH_COMPONENT16; + } +#endif +#if defined(GRAPHICS_API_OPENGL_ES3) + // NOTE: This sized internal format should also work for WebGL 2.0 + // WARNING: Specification only allows GL_DEPTH_COMPONENT32F for GL_FLOAT type + // REF: https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml + if (RLGL.ExtSupported.maxDepthBits == 24) glInternalFormat = GL_DEPTH_COMPONENT24; + else glInternalFormat = GL_DEPTH_COMPONENT16; +#endif + + if (!useRenderBuffer && RLGL.ExtSupported.texDepth) + { + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + glTexImage2D(GL_TEXTURE_2D, 0, glInternalFormat, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindTexture(GL_TEXTURE_2D, 0); + + TRACELOG(RL_LOG_INFO, "TEXTURE: Depth texture loaded successfully"); + } + else + { + // Create the renderbuffer that will serve as the depth attachment for the framebuffer + // NOTE: A renderbuffer is simpler than a texture and could offer better performance on embedded devices + glGenRenderbuffers(1, &id); + glBindRenderbuffer(GL_RENDERBUFFER, id); + glRenderbufferStorage(GL_RENDERBUFFER, glInternalFormat, width, height); + + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Depth renderbuffer loaded successfully (%i bits)", id, (RLGL.ExtSupported.maxDepthBits >= 24)? RLGL.ExtSupported.maxDepthBits : 16); + } +#elif defined(GRAPHICS_API_OPENGL_SOFTWARE) + // NOTE: Renderbuffers are the same type of object as textures in rlsw + // WARNING: Ensure that the depth format is the one specified at rlsw compilation + glGenRenderbuffers(1, &id); + glBindRenderbuffer(GL_RENDERBUFFER, id); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); +#endif + + return id; +} + +// Load texture cubemap +// NOTE: Cubemap data is expected to be 6 images in a single data array (one after the other), +// expected the following convention: +X, -X, +Y, -Y, +Z, -Z +unsigned int rlLoadTextureCubemap(const void *data, int size, int format, int mipmapCount) +{ + unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + int mipSize = size; + + // NOTE: Added pointer math separately from function to avoid UBSAN complaining + unsigned char *dataPtr = NULL; + if (data != NULL) dataPtr = (unsigned char *)data; + + unsigned int dataSize = rlGetPixelDataSize(size, size, format); + + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_CUBE_MAP, id); + + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); + + if (glInternalFormat != 0) + { + // Load cubemap faces/mipmaps + for (int i = 0; i < 6*mipmapCount; i++) + { + int mipmapLevel = i/6; + int face = i%6; + + if (data == NULL) + { + if (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) + { + if ((format == RL_PIXELFORMAT_UNCOMPRESSED_R32) || + (format == RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32) || + (format == RL_PIXELFORMAT_UNCOMPRESSED_R16) || + (format == RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16)) TRACELOG(RL_LOG_WARNING, "TEXTURES: Cubemap requested format not supported"); + else glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mipmapLevel, glInternalFormat, mipSize, mipSize, 0, glFormat, glType, NULL); + } + else TRACELOG(RL_LOG_WARNING, "TEXTURES: Empty cubemap creation does not support compressed format"); + } + else + { + if (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mipmapLevel, glInternalFormat, mipSize, mipSize, 0, glFormat, glType, (unsigned char *)dataPtr + face*dataSize); + else glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, mipmapLevel, glInternalFormat, mipSize, mipSize, 0, dataSize, (unsigned char *)dataPtr + face*dataSize); + } + +#if defined(GRAPHICS_API_OPENGL_33) + if (format == RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) + { + GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE }; + glTexParameteriv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } + else if (format == RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) + { +#if defined(GRAPHICS_API_OPENGL_21) + GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ALPHA }; +#elif defined(GRAPHICS_API_OPENGL_33) + GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN }; +#endif + glTexParameteriv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); + } +#endif + if (face == 5) + { + mipSize /= 2; + if (data != NULL) dataPtr += dataSize*6; // Increment data pointer to next mipmap + + // Security check for NPOT textures + if (mipSize < 1) mipSize = 1; + + dataSize = rlGetPixelDataSize(mipSize, mipSize, format); + } + } + } + + // Set cubemap texture sampling parameters + if (mipmapCount > 1) glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + else glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +#if defined(GRAPHICS_API_OPENGL_33) + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); // Flag not supported on OpenGL ES 2.0 +#endif + + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); +#endif + + if (id > 0) TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Cubemap texture loaded successfully (%ix%i)", id, size, size); + else TRACELOG(RL_LOG_WARNING, "TEXTURE: Failed to load cubemap texture"); + + return id; +} + +// Update already loaded texture in GPU with new data +// WARNING: Not possible to know safely if internal texture format is the expected one... +void rlUpdateTexture(unsigned int id, int offsetX, int offsetY, int width, int height, int format, const void *data) +{ + glBindTexture(GL_TEXTURE_2D, id); + + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); + + if ((glInternalFormat != 0) && (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB)) + { + glTexSubImage2D(GL_TEXTURE_2D, 0, offsetX, offsetY, width, height, glFormat, glType, data); + } + else TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] Failed to update for current texture format (%i)", id, format); +} + +// Get OpenGL internal formats and data type from raylib PixelFormat +void rlGetGlTextureFormats(int format, unsigned int *glInternalFormat, unsigned int *glFormat, unsigned int *glType) +{ + *glInternalFormat = 0; + *glFormat = 0; + *glType = 0; + + switch (format) + { + #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_21) || defined(GRAPHICS_API_OPENGL_ES2) + // NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA + case RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_UNSIGNED_BYTE; break; + case RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_LUMINANCE_ALPHA; *glFormat = GL_LUMINANCE_ALPHA; *glType = GL_UNSIGNED_BYTE; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break; + #if !defined(GRAPHICS_API_OPENGL_11) + #if defined(GRAPHICS_API_OPENGL_ES3) + case RL_PIXELFORMAT_UNCOMPRESSED_R32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_R32F_EXT; *glFormat = GL_RED_EXT; *glType = GL_FLOAT; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGB32F_EXT; *glFormat = GL_RGB; *glType = GL_FLOAT; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGBA32F_EXT; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_R16F_EXT; *glFormat = GL_RED_EXT; *glType = GL_HALF_FLOAT; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB16F_EXT; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA16F_EXT; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT; break; + #else + case RL_PIXELFORMAT_UNCOMPRESSED_R32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; // NOTE: Requires extension OES_texture_float + #if defined(GRAPHICS_API_OPENGL_21) + case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_HALF_FLOAT_ARB; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT_ARB; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT_ARB; break; + #else // defined(GRAPHICS_API_OPENGL_ES2) + case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_LUMINANCE; *glFormat = GL_LUMINANCE; *glType = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT_OES; break; // NOTE: Requires extension OES_texture_half_float + #endif + #endif + #endif + #elif defined(GRAPHICS_API_OPENGL_33) + case RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: *glInternalFormat = GL_R8; *glFormat = GL_RED; *glType = GL_UNSIGNED_BYTE; break; + case RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: *glInternalFormat = GL_RG8; *glFormat = GL_RG; *glType = GL_UNSIGNED_BYTE; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R5G6B5: *glInternalFormat = GL_RGB565; *glFormat = GL_RGB; *glType = GL_UNSIGNED_SHORT_5_6_5; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8: *glInternalFormat = GL_RGB8; *glFormat = GL_RGB; *glType = GL_UNSIGNED_BYTE; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: *glInternalFormat = GL_RGB5_A1; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_5_5_5_1; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: *glInternalFormat = GL_RGBA4; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_SHORT_4_4_4_4; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: *glInternalFormat = GL_RGBA8; *glFormat = GL_RGBA; *glType = GL_UNSIGNED_BYTE; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_R32F; *glFormat = GL_RED; *glType = GL_FLOAT; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGB32F; *glFormat = GL_RGB; *glType = GL_FLOAT; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: if (RLGL.ExtSupported.texFloat32) *glInternalFormat = GL_RGBA32F; *glFormat = GL_RGBA; *glType = GL_FLOAT; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_R16F; *glFormat = GL_RED; *glType = GL_HALF_FLOAT; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGB16F; *glFormat = GL_RGB; *glType = GL_HALF_FLOAT; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: if (RLGL.ExtSupported.texFloat16) *glInternalFormat = GL_RGBA16F; *glFormat = GL_RGBA; *glType = GL_HALF_FLOAT; break; + #endif + #if !defined(GRAPHICS_API_OPENGL_11) + case RL_PIXELFORMAT_COMPRESSED_DXT1_RGB: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; + case RL_PIXELFORMAT_COMPRESSED_DXT1_RGBA: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; + case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; + case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA: if (RLGL.ExtSupported.texCompDXT) *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; + case RL_PIXELFORMAT_COMPRESSED_ETC1_RGB: if (RLGL.ExtSupported.texCompETC1) *glInternalFormat = GL_ETC1_RGB8_OES; break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3 + case RL_PIXELFORMAT_COMPRESSED_ETC2_RGB: if (RLGL.ExtSupported.texCompETC2) *glInternalFormat = GL_COMPRESSED_RGB8_ETC2; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 + case RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: if (RLGL.ExtSupported.texCompETC2) *glInternalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 + case RL_PIXELFORMAT_COMPRESSED_PVRT_RGB: if (RLGL.ExtSupported.texCompPVRT) *glInternalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU + case RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA: if (RLGL.ExtSupported.texCompPVRT) *glInternalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break; // NOTE: Requires PowerVR GPU + case RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: if (RLGL.ExtSupported.texCompASTC) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_4x4_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 + case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: if (RLGL.ExtSupported.texCompASTC) *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_8x8_KHR; break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 + #endif + default: TRACELOG(RL_LOG_WARNING, "TEXTURE: Current format not supported (%i)", format); break; + } +} + +// Unload texture from GPU memory +void rlUnloadTexture(unsigned int id) +{ + glDeleteTextures(1, &id); +} + +// Generate mipmap data for selected texture +// NOTE: Only supports GPU mipmap generation +void rlGenTextureMipmaps(unsigned int id, int width, int height, int format, int *mipmaps) +{ + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return; } + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindTexture(GL_TEXTURE_2D, id); + + // Check if texture is power-of-two (POT) + bool texIsPOT = false; + + if (((width > 0) && ((width & (width - 1)) == 0)) && + ((height > 0) && ((height & (height - 1)) == 0))) texIsPOT = true; + + if ((texIsPOT) || (RLGL.ExtSupported.texNPOT)) + { + //glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorithm: GL_FASTEST, GL_NICEST, GL_DONT_CARE + glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically + + #define MIN(a,b) (((a)<(b))? (a):(b)) + #define MAX(a,b) (((a)>(b))? (a):(b)) + + *mipmaps = 1 + (int)floor(log(MAX(width, height))/log(2)); + TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Mipmaps generated automatically, total: %i", id, *mipmaps); + } + else TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] Failed to generate mipmaps", id); + + glBindTexture(GL_TEXTURE_2D, 0); +#else + TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] GPU mipmap generation not supported", id); +#endif +} + +// Read texture pixel data +void *rlReadTexturePixels(unsigned int id, int width, int height, int format) +{ + void *pixels = NULL; + +#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) + glBindTexture(GL_TEXTURE_2D, id); + + // NOTE: Using texture id, some texture info can be retrieved (but not on OpenGL ES 2.0) + // Possible texture info: GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE + //int width, height, format; + //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); + //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); + //glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format); + + // NOTE: Each row written to or read from by OpenGL pixel operations like glGetTexImage are aligned to a 4 byte boundary by default, which may add some padding + // Use glPixelStorei to modify padding with the GL_[UN]PACK_ALIGNMENT setting + // GL_PACK_ALIGNMENT affects operations that read from OpenGL memory (glReadPixels, glGetTexImage, etc.) + // GL_UNPACK_ALIGNMENT affects operations that write to OpenGL memory (glTexImage, etc.) + glPixelStorei(GL_PACK_ALIGNMENT, 1); + + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); + unsigned int size = rlGetPixelDataSize(width, height, format); + + if ((glInternalFormat != 0) && (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB)) + { + pixels = RL_CALLOC(size, 1); + glGetTexImage(GL_TEXTURE_2D, 0, glFormat, glType, pixels); + } + else TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] Data retrieval not suported for pixel format (%i)", id, format); + + glBindTexture(GL_TEXTURE_2D, 0); +#endif + +#if defined(GRAPHICS_API_OPENGL_ES2) + // glGetTexImage() is not available on OpenGL ES 2.0 + // Texture width and height are required on OpenGL ES 2.0, there is no way to get it from texture id + // Two possible Options: + // 1 - Bind texture to color fbo attachment and glReadPixels() + // 2 - Create an fbo, activate it, render quad with texture, glReadPixels() + // Using Option 1, care for texture format on retrieval + // NOTE: This behaviour could be conditioned by graphic driver... + unsigned int fboId = rlLoadFramebuffer(); + + glBindFramebuffer(GL_FRAMEBUFFER, fboId); + glBindTexture(GL_TEXTURE_2D, 0); + + // Attach our texture to FBO + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, 0); + + // Reading data as RGBA because FBO texture is configured as RGBA, despite binding another texture format + pixels = RL_CALLOC(rlGetPixelDataSize(width, height, RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8), 1); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // Clean up temporal fbo + rlUnloadFramebuffer(fboId); +#endif + + return pixels; +} + +// Copy framebuffer pixel data to internal buffer +void rlCopyFramebuffer(int x, int y, int width, int height, int format, void *pixels) +{ +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); // Get OpenGL texture format + swReadPixels(x, y, width, height, glFormat, glType, pixels); +#endif +} + +// Resize internal framebuffer +void rlResizeFramebuffer(int width, int height) +{ +#if defined(GRAPHICS_API_OPENGL_SOFTWARE) + swResize(width, height); +#endif +} + +// Read screen pixel data (color buffer) +unsigned char *rlReadScreenPixels(int width, int height) +{ + unsigned char *imgData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char)); + + // NOTE: glReadPixels() returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer + // WARNING: Getting alpha channel! Be careful, it can be transparent if not cleared properly! + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, imgData); + + // Flip image vertically + // NOTE: Alpha value has already been applied to RGB in framebuffer, not needed anymore + for (int y = height - 1; y >= height/2; y--) + { + for (int x = 0; x < (width*4); x += 4) + { + unsigned int s = ((height - 1) - y)*width*4 + x; + unsigned int e = y*width*4 + x; + + unsigned char r = imgData[s]; + unsigned char g = imgData[s+1]; + unsigned char b = imgData[s+2]; + + imgData[s] = imgData[e]; + imgData[s+1] = imgData[e+1]; + imgData[s+2] = imgData[e+2]; + imgData[s+3] = 255; // Set alpha component value to 255 (no trasparent image retrieval) + + imgData[e] = r; + imgData[e+1] = g; + imgData[e+2] = b; + imgData[e+3] = 255; // Ditto + } + } + + return imgData; // NOTE: image data should be freed +} + +// Framebuffer management (fbo) +//----------------------------------------------------------------------------------------- +// Load a framebuffer to be used for rendering +// NOTE: No textures attached +unsigned int rlLoadFramebuffer(void) +{ + unsigned int fboId = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return fboId; } + +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) + glGenFramebuffers(1, &fboId); // Create the framebuffer object + glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind any framebuffer +#endif + + return fboId; +} + +// Attach color buffer texture to a framebuffer object (unloads previous attachment) +// NOTE: Attach type: 0-Color, 1-Depth renderbuffer, 2-Depth texture +void rlFramebufferAttach(unsigned int id, unsigned int texId, int attachType, int texType, int mipLevel) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) + glBindFramebuffer(GL_FRAMEBUFFER, id); + + switch (attachType) + { + case RL_ATTACHMENT_COLOR_CHANNEL0: + case RL_ATTACHMENT_COLOR_CHANNEL1: + case RL_ATTACHMENT_COLOR_CHANNEL2: + case RL_ATTACHMENT_COLOR_CHANNEL3: + case RL_ATTACHMENT_COLOR_CHANNEL4: + case RL_ATTACHMENT_COLOR_CHANNEL5: + case RL_ATTACHMENT_COLOR_CHANNEL6: + case RL_ATTACHMENT_COLOR_CHANNEL7: + { + if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_2D, texId, mipLevel); + else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_RENDERBUFFER, texId); + else if (texType >= RL_ATTACHMENT_CUBEMAP_POSITIVE_X) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + attachType, GL_TEXTURE_CUBE_MAP_POSITIVE_X + texType, texId, mipLevel); + } break; + case RL_ATTACHMENT_DEPTH: + { + if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel); + else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, texId); + } break; + case RL_ATTACHMENT_STENCIL: + { + if (texType == RL_ATTACHMENT_TEXTURE2D) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, texId, mipLevel); + else if (texType == RL_ATTACHMENT_RENDERBUFFER) glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, texId); + } break; + default: break; + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); +#endif +} + +// Verify render texture is complete +bool rlFramebufferComplete(unsigned int id) +{ + bool result = false; + +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) + glBindFramebuffer(GL_FRAMEBUFFER, id); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) + { + switch (status) + { + case GL_FRAMEBUFFER_UNSUPPORTED: TRACELOG(RL_LOG_WARNING, "FBO: [ID %i] Framebuffer is unsupported", id); break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TRACELOG(RL_LOG_WARNING, "FBO: [ID %i] Framebuffer has incomplete attachment", id); break; +#if defined(GRAPHICS_API_OPENGL_ES2) + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: TRACELOG(RL_LOG_WARNING, "FBO: [ID %i] Framebuffer has incomplete dimensions", id); break; +#endif + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: TRACELOG(RL_LOG_WARNING, "FBO: [ID %i] Framebuffer has a missing attachment", id); break; + default: break; + } + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + result = (status == GL_FRAMEBUFFER_COMPLETE); +#endif + + return result; +} + +// Unload framebuffer from GPU memory +// NOTE: All attached textures/cubemaps/renderbuffers are also deleted +void rlUnloadFramebuffer(unsigned int id) +{ +#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_SOFTWARE)) + // Query depth attachment to automatically delete texture/renderbuffer + int depthType = 0; + glBindFramebuffer(GL_FRAMEBUFFER, id); // Bind framebuffer to query depth texture type + glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &depthType); + + // WARNING: WebGL: INVALID_ENUM: getFramebufferAttachmentParameter: invalid parameter name + // REF: https://registry.khronos.org/webgl/specs/latest/1.0/ + int depthId = 0; + glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &depthId); + + unsigned int depthIdU = (unsigned int)depthId; + if (depthType == GL_RENDERBUFFER) glDeleteRenderbuffers(1, &depthIdU); + else if (depthType == GL_TEXTURE) glDeleteTextures(1, &depthIdU); + + // NOTE: If a texture object is deleted while its image is attached to the *currently bound* framebuffer, + // the texture image is automatically detached from the currently bound framebuffer + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &id); + + TRACELOG(RL_LOG_INFO, "FBO: [ID %i] Unloaded framebuffer from VRAM (GPU)", id); +#endif +} + +// Vertex data management +//----------------------------------------------------------------------------------------- +// Load a new attributes buffer +unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic) +{ + unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glGenBuffers(1, &id); + glBindBuffer(GL_ARRAY_BUFFER, id); + glBufferData(GL_ARRAY_BUFFER, size, buffer, dynamic? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); +#endif + + return id; +} + +// Load a new attributes element buffer +unsigned int rlLoadVertexBufferElement(const void *buffer, int size, bool dynamic) +{ + unsigned int id = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glGenBuffers(1, &id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, buffer, dynamic? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); +#endif + + return id; +} + +// Enable vertex buffer (VBO) +void rlEnableVertexBuffer(unsigned int id) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindBuffer(GL_ARRAY_BUFFER, id); +#endif +} + +// Disable vertex buffer (VBO) +void rlDisableVertexBuffer(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindBuffer(GL_ARRAY_BUFFER, 0); +#endif +} + +// Enable vertex buffer element (VBO element) +void rlEnableVertexBufferElement(unsigned int id) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id); +#endif +} + +// Disable vertex buffer element (VBO element) +void rlDisableVertexBufferElement(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +#endif +} + +// Update vertex buffer with new data +// NOTE: dataSize and offset must be provided in bytes +void rlUpdateVertexBuffer(unsigned int id, const void *data, int dataSize, int offset) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindBuffer(GL_ARRAY_BUFFER, id); + glBufferSubData(GL_ARRAY_BUFFER, offset, dataSize, data); +#endif +} + +// Update vertex buffer elements with new data +// NOTE: dataSize and offset must be provided in bytes +void rlUpdateVertexBufferElements(unsigned int id, const void *data, int dataSize, int offset) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, dataSize, data); +#endif +} + +// Enable vertex array object (VAO) +bool rlEnableVertexArray(unsigned int vaoId) +{ + bool result = false; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if (RLGL.ExtSupported.vao) + { + glBindVertexArray(vaoId); + result = true; + } +#endif + return result; +} + +// Disable vertex array object (VAO) +void rlDisableVertexArray(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if (RLGL.ExtSupported.vao) glBindVertexArray(0); +#endif +} + +// Enable vertex attribute index +void rlEnableVertexAttribute(unsigned int index) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glEnableVertexAttribArray(index); +#endif +} + +// Disable vertex attribute index +void rlDisableVertexAttribute(unsigned int index) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glDisableVertexAttribArray(index); +#endif +} + +// Draw vertex array +void rlDrawVertexArray(int offset, int count) +{ + glDrawArrays(GL_TRIANGLES, offset, count); +} + +// Draw vertex array elements +void rlDrawVertexArrayElements(int offset, int count, const void *buffer) +{ + // NOTE: Added pointer math separately from function to avoid UBSAN complaining + unsigned short *bufferPtr = (unsigned short *)buffer; + if (offset > 0) bufferPtr += offset; + + glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (const unsigned short *)bufferPtr); +} + +// Draw vertex array instanced +void rlDrawVertexArrayInstanced(int offset, int count, int instances) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glDrawArraysInstanced(GL_TRIANGLES, offset, count, instances); +#endif +} + +// Draw vertex array elements instanced +void rlDrawVertexArrayElementsInstanced(int offset, int count, const void *buffer, int instances) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // NOTE: Added pointer math separately from function to avoid UBSAN complaining + unsigned short *bufferPtr = (unsigned short *)buffer; + if (offset > 0) bufferPtr += offset; + + glDrawElementsInstanced(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (const unsigned short *)bufferPtr, instances); +#endif +} + +// Enable vertex state pointer +void rlEnableStatePointer(int vertexAttribType, void *buffer) +{ +#if defined(GRAPHICS_API_OPENGL_11) + if (buffer != NULL) glEnableClientState(vertexAttribType); + switch (vertexAttribType) + { + case GL_VERTEX_ARRAY: glVertexPointer(3, GL_FLOAT, 0, buffer); break; + case GL_TEXTURE_COORD_ARRAY: glTexCoordPointer(2, GL_FLOAT, 0, buffer); break; + case GL_NORMAL_ARRAY: if (buffer != NULL) glNormalPointer(GL_FLOAT, 0, buffer); break; + case GL_COLOR_ARRAY: if (buffer != NULL) glColorPointer(4, GL_UNSIGNED_BYTE, 0, buffer); break; + //case GL_INDEX_ARRAY: if (buffer != NULL) glIndexPointer(GL_SHORT, 0, buffer); break; // Indexed colors + default: break; + } +#endif +} + +// Disable vertex state pointer +void rlDisableStatePointer(int vertexAttribType) +{ +#if defined(GRAPHICS_API_OPENGL_11) + glDisableClientState(vertexAttribType); +#endif +} + +// Load vertex array object (VAO) +unsigned int rlLoadVertexArray(void) +{ + unsigned int vaoId = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return vaoId; } + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if (RLGL.ExtSupported.vao) glGenVertexArrays(1, &vaoId); +#endif + + return vaoId; +} + +// Set vertex attribute +void rlSetVertexAttribute(unsigned int index, int compSize, int type, bool normalized, int stride, int offset) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // NOTE: Data type could be: GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT + // Additional types (depends on OpenGL version or extensions): + // - GL_HALF_FLOAT, GL_FLOAT, GL_DOUBLE, GL_FIXED, + // - GL_INT_2_10_10_10_REV, GL_UNSIGNED_INT_2_10_10_10_REV, GL_UNSIGNED_INT_10F_11F_11F_REV + + size_t offsetNative = offset; + glVertexAttribPointer(index, compSize, type, normalized, stride, (void *)offsetNative); +#endif +} + +// Set vertex attribute divisor +void rlSetVertexAttributeDivisor(unsigned int index, int divisor) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glVertexAttribDivisor(index, divisor); +#endif +} + +// Unload vertex array object (VAO) +void rlUnloadVertexArray(unsigned int vaoId) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if (RLGL.ExtSupported.vao) + { + glBindVertexArray(0); + glDeleteVertexArrays(1, &vaoId); + TRACELOG(RL_LOG_INFO, "VAO: [ID %i] Unloaded vertex array data from VRAM (GPU)", vaoId); + } +#endif +} + +// Unload vertex buffer (VBO) +void rlUnloadVertexBuffer(unsigned int vboId) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glDeleteBuffers(1, &vboId); + //TRACELOG(RL_LOG_INFO, "VBO: Unloaded vertex data from VRAM (GPU)"); +#endif +} + +// Shaders management +//----------------------------------------------------------------------------------------------- +// Load (compile) shader and return shader id +unsigned int rlLoadShader(const char *code, int type) +{ + unsigned int shaderId = 0; + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + shaderId = glCreateShader(type); + glShaderSource(shaderId, 1, &code, NULL); + + GLint success = 0; + glCompileShader(shaderId); + glGetShaderiv(shaderId, GL_COMPILE_STATUS, &success); + + if (success == GL_FALSE) + { + switch (type) + { + case GL_VERTEX_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile vertex shader code", shaderId); break; + case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile fragment shader code", shaderId); break; + //case GL_GEOMETRY_SHADER: + #if defined(GRAPHICS_API_OPENGL_43) + case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile compute shader code", shaderId); break; + #elif defined(GRAPHICS_API_OPENGL_33) + case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shaderId); break; + #endif + default: break; + } + + int maxLength = 0; + glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &maxLength); + + if (maxLength > 0) + { + int length = 0; + char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); + glGetShaderInfoLog(shaderId, maxLength, &length, log); + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Compile error: %s", shaderId, log); + RL_FREE(log); + } + + // Unload object allocated by glCreateShader(), + // despite failing in the compilation process + glDeleteShader(shaderId); + shaderId = 0; + } + else + { + switch (type) + { + case GL_VERTEX_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Vertex shader compiled successfully", shaderId); break; + case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Fragment shader compiled successfully", shaderId); break; + //case GL_GEOMETRY_SHADER: + #if defined(GRAPHICS_API_OPENGL_43) + case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader compiled successfully", shaderId); break; + #elif defined(GRAPHICS_API_OPENGL_33) + case GL_COMPUTE_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not enabled. Define GRAPHICS_API_OPENGL_43", shaderId); break; + #endif + default: break; + } + } +#endif + + return shaderId; +} + +// Load shader program from code strings +// NOTE: If shader string is NULL, using default vertex/fragment shaders +unsigned int rlLoadShaderProgram(const char *vsCode, const char *fsCode) +{ + unsigned int id = 0; // Shader program id + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; } + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + unsigned int vertexShaderId = 0; + unsigned int fragmentShaderId = 0; + + // Compile vertex shader (if provided) + // NOTE: If not vertex shader is provided, use default one + if (vsCode != NULL) vertexShaderId = rlLoadShader(vsCode, GL_VERTEX_SHADER); + else vertexShaderId = RLGL.State.defaultVShaderId; + + // Compile fragment shader (if provided) + // NOTE: If not vertex shader is provided, use default one + if (fsCode != NULL) fragmentShaderId = rlLoadShader(fsCode, GL_FRAGMENT_SHADER); + else fragmentShaderId = RLGL.State.defaultFShaderId; + + // In case vertex and fragment shader are the default ones, no need to recompile, assign the default shader program id + if ((vertexShaderId == RLGL.State.defaultVShaderId) && (fragmentShaderId == RLGL.State.defaultFShaderId)) id = RLGL.State.defaultShaderId; + else if ((vertexShaderId > 0) && (fragmentShaderId > 0)) + { + // One of or both shader are new, a new shader program needs to be compiled + id = rlLoadShaderProgramEx(vertexShaderId, fragmentShaderId); + + // Detaching and deleting vertex/fragment shaders (if not default ones) + // WARNING: Detach shader before deletion to make sure memory is freed + if (vertexShaderId != RLGL.State.defaultVShaderId) + { + // WARNING: Shader program linkage could fail and returned id is 0 + if (id > 0) glDetachShader(id, vertexShaderId); + glDeleteShader(vertexShaderId); + } + if (fragmentShaderId != RLGL.State.defaultFShaderId) + { + // WARNING: Shader program linkage could fail and returned id is 0 + if (id > 0) glDetachShader(id, fragmentShaderId); + glDeleteShader(fragmentShaderId); + } + + // In case shader program loading failed, assign default shader + if (id == 0) + { + // In case shader loading fails, reassigning default shader + TRACELOG(RL_LOG_WARNING, "SHADER: Failed to load custom shader code, using default shader"); + id = RLGL.State.defaultShaderId; + } + /* + else + { + // Get available shader uniforms + // NOTE: This information is useful for debug... + int uniformCount = -1; + glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &uniformCount); + + for (int i = 0; i < uniformCount; i++) + { + int namelen = -1; + int num = -1; + char name[256] = { 0 }; // Assume no variable names longer than 256 + GLenum type = GL_ZERO; + + // Get the name of the uniforms + glGetActiveUniform(id, i, sizeof(name) - 1, &namelen, &num, &type, name); + + name[namelen] = 0; + TRACELOG(RL_LOG_DEBUG, "SHADER: [ID %i] Active uniform (%s) set at location: %i", id, name, glGetUniformLocation(id, name)); + } + } + */ + } +#endif + + return id; +} + +// Load shader program from already loaded shader ids +unsigned int rlLoadShaderProgramEx(unsigned int vsId, unsigned int fsId) +{ + unsigned int programId = 0; + if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return programId; } + +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + GLint success = 0; + programId = glCreateProgram(); + + glAttachShader(programId, vsId); + glAttachShader(programId, fsId); + + // Default attribute shader locations must be bound before linking + // NOTE: There is no problem with binding a generic attribute index to an attribute variable name + // that is never used; if some attrib name is no found on the shader, it locations becomes -1 + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM, RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES); + glBindAttribLocation(programId, RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS, RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS); + + glLinkProgram(programId); + + // NOTE: All uniform variables are intitialised to 0 when a program links + + glGetProgramiv(programId, GL_LINK_STATUS, &success); + + if (success == GL_FALSE) + { + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link shader program", programId); + + int maxLength = 0; + glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &maxLength); + + if (maxLength > 0) + { + int length = 0; + char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); + glGetProgramInfoLog(programId, maxLength, &length, log); + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", programId, log); + RL_FREE(log); + } + + glDeleteProgram(programId); + + programId = 0; + } + else + { + // Get the size of compiled shader program (not available on OpenGL ES 2.0) + // NOTE: If GL_LINK_STATUS is GL_FALSE, program binary length is zero + //GLint binarySize = 0; + //glGetProgramiv(id, GL_PROGRAM_BINARY_LENGTH, &binarySize); + + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Program shader loaded successfully", programId); + } +#endif + return programId; +} + +// Load compute shader program +unsigned int rlLoadShaderProgramCompute(unsigned int csId) +{ + unsigned int programId = 0; + +#if defined(GRAPHICS_API_OPENGL_43) + GLint success = 0; + programId = glCreateProgram(); + + glAttachShader(programId, csId); + + glLinkProgram(programId); + + // NOTE: All uniform variables are intitialised to 0 when a program links + + glGetProgramiv(programId, GL_LINK_STATUS, &success); + + if (success == GL_FALSE) + { + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link compute shader program", programId); + + int maxLength = 0; + glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &maxLength); + + if (maxLength > 0) + { + int length = 0; + char *log = (char *)RL_CALLOC(maxLength, sizeof(char)); + glGetProgramInfoLog(programId, maxLength, &length, log); + TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", programId, log); + RL_FREE(log); + } + + glDeleteProgram(programId); + + programId = 0; + } + else + { + // Get the size of compiled shader program (not available on OpenGL ES 2.0) + // NOTE: If GL_LINK_STATUS is GL_FALSE, program binary length is zero + //GLint binarySize = 0; + //glGetProgramiv(id, GL_PROGRAM_BINARY_LENGTH, &binarySize); + + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Compute shader program loaded successfully", programId); + } +#else + TRACELOG(RL_LOG_WARNING, "SHADER: Compute shaders not supported, enable GRAPHICS_API_OPENGL_43"); +#endif + + return programId; +} + +// Delete shader +void rlUnloadShader(unsigned int id) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glDeleteShader(id); + + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Unloaded shader data from VRAM (GPU)", id); +#endif +} + +// Unload shader program +void rlUnloadShaderProgram(unsigned int id) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glDeleteProgram(id); + + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Unloaded shader program data from VRAM (GPU)", id); +#endif +} + +// Get shader location uniform +// NOTE: First parameter refers to shader program id +int rlGetLocationUniform(unsigned int id, const char *uniformName) +{ + int location = -1; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + location = glGetUniformLocation(id, uniformName); + + //if (location == -1) TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to find shader uniform: %s", shaderId, uniformName); + //else TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Shader uniform (%s) set at location: %i", shaderId, uniformName, location); +#endif + return location; +} + +// Get shader location attribute +// NOTE: First parameter refers to shader program id +int rlGetLocationAttrib(unsigned int id, const char *attribName) +{ + int location = -1; +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + location = glGetAttribLocation(id, attribName); + + //if (location == -1) TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to find shader attribute: %s", shaderId, attribName); + //else TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Shader attribute (%s) set at location: %i", shaderId, attribName, location); +#endif + return location; +} + +// Set shader value uniform +void rlSetUniform(int locIndex, const void *value, int uniformType, int count) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + switch (uniformType) + { + case RL_SHADER_UNIFORM_FLOAT: glUniform1fv(locIndex, count, (float *)value); break; + case RL_SHADER_UNIFORM_VEC2: glUniform2fv(locIndex, count, (float *)value); break; + case RL_SHADER_UNIFORM_VEC3: glUniform3fv(locIndex, count, (float *)value); break; + case RL_SHADER_UNIFORM_VEC4: glUniform4fv(locIndex, count, (float *)value); break; + case RL_SHADER_UNIFORM_INT: glUniform1iv(locIndex, count, (int *)value); break; + case RL_SHADER_UNIFORM_IVEC2: glUniform2iv(locIndex, count, (int *)value); break; + case RL_SHADER_UNIFORM_IVEC3: glUniform3iv(locIndex, count, (int *)value); break; + case RL_SHADER_UNIFORM_IVEC4: glUniform4iv(locIndex, count, (int *)value); break; + #if !defined(GRAPHICS_API_OPENGL_ES2) + case RL_SHADER_UNIFORM_UINT: glUniform1uiv(locIndex, count, (unsigned int *)value); break; + case RL_SHADER_UNIFORM_UIVEC2: glUniform2uiv(locIndex, count, (unsigned int *)value); break; + case RL_SHADER_UNIFORM_UIVEC3: glUniform3uiv(locIndex, count, (unsigned int *)value); break; + case RL_SHADER_UNIFORM_UIVEC4: glUniform4uiv(locIndex, count, (unsigned int *)value); break; + #endif + case RL_SHADER_UNIFORM_SAMPLER2D: glUniform1iv(locIndex, count, (int *)value); break; + default: TRACELOG(RL_LOG_WARNING, "SHADER: Failed to set uniform value, data type not recognized"); + } +#endif +} + +// Set shader value attribute +void rlSetVertexAttributeDefault(int locIndex, const void *value, int attribType, int count) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + switch (attribType) + { + case RL_SHADER_ATTRIB_FLOAT: if (count == 1) glVertexAttrib1fv(locIndex, (float *)value); break; + case RL_SHADER_ATTRIB_VEC2: if (count == 2) glVertexAttrib2fv(locIndex, (float *)value); break; + case RL_SHADER_ATTRIB_VEC3: if (count == 3) glVertexAttrib3fv(locIndex, (float *)value); break; + case RL_SHADER_ATTRIB_VEC4: if (count == 4) glVertexAttrib4fv(locIndex, (float *)value); break; + default: TRACELOG(RL_LOG_WARNING, "SHADER: Failed to set attrib default value, data type not recognized"); + } +#endif +} + +// Set shader value uniform matrix +void rlSetUniformMatrix(int locIndex, Matrix mat) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + glUniformMatrix4fv(locIndex, 1, false, rlMatrixToFloat(mat)); +#endif +} + +// Set shader value uniform matrix +void rlSetUniformMatrices(int locIndex, const Matrix *matrices, int count) +{ +#if defined(GRAPHICS_API_OPENGL_33) + glUniformMatrix4fv(locIndex, count, true, (const float *)matrices); +#elif defined(GRAPHICS_API_OPENGL_ES2) + // WARNING: WebGL does not support Matrix transpose ("true" parameter) + // REF: https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/uniformMatrix + glUniformMatrix4fv(locIndex, count, false, (const float *)matrices); +#endif +} + +// Set shader value uniform sampler +void rlSetUniformSampler(int locIndex, unsigned int textureId) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // Check if texture is already active + for (int i = 0; i < RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS; i++) + { + if (RLGL.State.activeTextureId[i] == textureId) + { + glUniform1i(locIndex, 1 + i); + return; + } + } + + // Register a new active texture for the internal batch system + // NOTE: Default texture is always activated as GL_TEXTURE0 + for (int i = 0; i < RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS; i++) + { + if (RLGL.State.activeTextureId[i] == 0) + { + glUniform1i(locIndex, 1 + i); // Activate new texture unit + RLGL.State.activeTextureId[i] = textureId; // Save texture id for binding on drawing + break; + } + } +#endif +} + +// Set shader currently active (id and locations) +void rlSetShader(unsigned int id, int *locs) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + if (RLGL.State.currentShaderId != id) + { + rlDrawRenderBatch(RLGL.currentBatch); + RLGL.State.currentShaderId = id; + RLGL.State.currentShaderLocs = locs; + } +#endif +} + +// Dispatch compute shader (equivalent to *draw* for graphics pilepine) +void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ) +{ +#if defined(GRAPHICS_API_OPENGL_43) + glDispatchCompute(groupX, groupY, groupZ); +#endif +} + +// Load shader storage buffer object (SSBO) +unsigned int rlLoadShaderBuffer(unsigned int size, const void *data, int usageHint) +{ + unsigned int ssbo = 0; + +#if defined(GRAPHICS_API_OPENGL_43) + glGenBuffers(1, &ssbo); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo); + glBufferData(GL_SHADER_STORAGE_BUFFER, size, data, usageHint? usageHint : RL_STREAM_COPY); + if (data == NULL) glClearBufferData(GL_SHADER_STORAGE_BUFFER, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, NULL); // Clear buffer data to 0 + glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); +#else + TRACELOG(RL_LOG_WARNING, "SSBO: SSBO not enabled. Define GRAPHICS_API_OPENGL_43"); +#endif + + return ssbo; +} + +// Unload shader storage buffer object (SSBO) +void rlUnloadShaderBuffer(unsigned int ssboId) +{ +#if defined(GRAPHICS_API_OPENGL_43) + glDeleteBuffers(1, &ssboId); +#else + TRACELOG(RL_LOG_WARNING, "SSBO: SSBO not enabled. Define GRAPHICS_API_OPENGL_43"); +#endif +} + +// Update SSBO buffer data +void rlUpdateShaderBuffer(unsigned int id, const void *data, unsigned int dataSize, unsigned int offset) +{ +#if defined(GRAPHICS_API_OPENGL_43) + glBindBuffer(GL_SHADER_STORAGE_BUFFER, id); + glBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, dataSize, data); +#endif +} + +// Get SSBO buffer size +unsigned int rlGetShaderBufferSize(unsigned int id) +{ + unsigned int result = 0; +#if defined(GRAPHICS_API_OPENGL_43) + GLint64 size = 0; + glBindBuffer(GL_SHADER_STORAGE_BUFFER, id); + glGetBufferParameteri64v(GL_SHADER_STORAGE_BUFFER, GL_BUFFER_SIZE, &size); + if (size > 0) result = (unsigned int)size; +#endif + return result; +} + +// Read SSBO buffer data (GPU->CPU) +void rlReadShaderBuffer(unsigned int id, void *dest, unsigned int count, unsigned int offset) +{ +#if defined(GRAPHICS_API_OPENGL_43) + glBindBuffer(GL_SHADER_STORAGE_BUFFER, id); + glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, offset, count, dest); +#endif +} + +// Bind SSBO buffer +void rlBindShaderBuffer(unsigned int id, unsigned int index) +{ +#if defined(GRAPHICS_API_OPENGL_43) + glBindBufferBase(GL_SHADER_STORAGE_BUFFER, index, id); +#endif +} + +// Copy SSBO buffer data +void rlCopyShaderBuffer(unsigned int destId, unsigned int srcId, unsigned int destOffset, unsigned int srcOffset, unsigned int count) +{ +#if defined(GRAPHICS_API_OPENGL_43) + glBindBuffer(GL_COPY_READ_BUFFER, srcId); + glBindBuffer(GL_COPY_WRITE_BUFFER, destId); + glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, srcOffset, destOffset, count); +#endif +} + +// Bind image texture +void rlBindImageTexture(unsigned int id, unsigned int index, int format, bool readonly) +{ +#if defined(GRAPHICS_API_OPENGL_43) + unsigned int glInternalFormat = 0, glFormat = 0, glType = 0; + + rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); + glBindImageTexture(index, id, 0, 0, 0, readonly? GL_READ_ONLY : GL_READ_WRITE, glInternalFormat); +#else + TRACELOG(RL_LOG_WARNING, "TEXTURE: Image texture binding not enabled. Define GRAPHICS_API_OPENGL_43"); +#endif +} + +// Matrix state management +//----------------------------------------------------------------------------------------- +// Get internal modelview matrix +Matrix rlGetMatrixModelview(void) +{ + Matrix matrix = rlMatrixIdentity(); +#if defined(GRAPHICS_API_OPENGL_11) + float mat[16]; + glGetFloatv(GL_MODELVIEW_MATRIX, mat); + matrix.m0 = mat[0]; + matrix.m1 = mat[1]; + matrix.m2 = mat[2]; + matrix.m3 = mat[3]; + matrix.m4 = mat[4]; + matrix.m5 = mat[5]; + matrix.m6 = mat[6]; + matrix.m7 = mat[7]; + matrix.m8 = mat[8]; + matrix.m9 = mat[9]; + matrix.m10 = mat[10]; + matrix.m11 = mat[11]; + matrix.m12 = mat[12]; + matrix.m13 = mat[13]; + matrix.m14 = mat[14]; + matrix.m15 = mat[15]; +#else + matrix = RLGL.State.modelview; +#endif + return matrix; +} + +// Get internal projection matrix +Matrix rlGetMatrixProjection(void) +{ +#if defined(GRAPHICS_API_OPENGL_11) + float mat[16]; + glGetFloatv(GL_PROJECTION_MATRIX,mat); + Matrix m; + m.m0 = mat[0]; + m.m1 = mat[1]; + m.m2 = mat[2]; + m.m3 = mat[3]; + m.m4 = mat[4]; + m.m5 = mat[5]; + m.m6 = mat[6]; + m.m7 = mat[7]; + m.m8 = mat[8]; + m.m9 = mat[9]; + m.m10 = mat[10]; + m.m11 = mat[11]; + m.m12 = mat[12]; + m.m13 = mat[13]; + m.m14 = mat[14]; + m.m15 = mat[15]; + return m; +#else + return RLGL.State.projection; +#endif +} + +// Get internal accumulated transform matrix +Matrix rlGetMatrixTransform(void) +{ + Matrix mat = rlMatrixIdentity(); +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + // TODO: Consider possible transform matrices in the RLGL.State.stack + //Matrix matStackTransform = rlMatrixIdentity(); + //for (int i = RLGL.State.stackCounter; i > 0; i--) matStackTransform = rlMatrixMultiply(RLGL.State.stack[i], matStackTransform); + + mat = RLGL.State.transform; +#endif + return mat; +} + +// Get internal projection matrix for stereo render (selected eye) +Matrix rlGetMatrixProjectionStereo(int eye) +{ + Matrix mat = rlMatrixIdentity(); +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + mat = RLGL.State.projectionStereo[eye]; +#endif + return mat; +} + +// Get internal view offset matrix for stereo render (selected eye) +Matrix rlGetMatrixViewOffsetStereo(int eye) +{ + Matrix mat = rlMatrixIdentity(); +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + mat = RLGL.State.viewOffsetStereo[eye]; +#endif + return mat; +} + +// Set a custom modelview matrix (replaces internal modelview matrix) +void rlSetMatrixModelview(Matrix view) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + RLGL.State.modelview = view; +#endif +} + +// Set a custom projection matrix (replaces internal projection matrix) +void rlSetMatrixProjection(Matrix projection) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + RLGL.State.projection = projection; +#endif +} + +// Set eyes projection matrices for stereo rendering +void rlSetMatrixProjectionStereo(Matrix right, Matrix left) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + RLGL.State.projectionStereo[0] = right; + RLGL.State.projectionStereo[1] = left; +#endif +} + +// Set eyes view offsets matrices for stereo rendering +void rlSetMatrixViewOffsetStereo(Matrix right, Matrix left) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + RLGL.State.viewOffsetStereo[0] = right; + RLGL.State.viewOffsetStereo[1] = left; +#endif +} + +// Load and draw a quad in NDC +void rlLoadDrawQuad(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + unsigned int quadVAO = 0; + unsigned int quadVBO = 0; + + float vertices[] = { + // Positions Texcoords + -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, + }; + + // Gen VAO to contain VBO + glGenVertexArrays(1, &quadVAO); + glBindVertexArray(quadVAO); + + // Gen and fill vertex buffer (VBO) + glGenBuffers(1, &quadVBO); + glBindBuffer(GL_ARRAY_BUFFER, quadVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW); + + // Bind vertex attributes (position, texcoords) + glEnableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION); + glVertexAttribPointer(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)0); // Positions + glEnableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD); + glVertexAttribPointer(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)(3*sizeof(float))); // Texcoords + + // Draw quad + glBindVertexArray(quadVAO); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); + + // Delete buffers (VBO and VAO) + glDeleteBuffers(1, &quadVBO); + glDeleteVertexArrays(1, &quadVAO); +#endif +} + +// Load and draw a cube in NDC +void rlLoadDrawCube(void) +{ +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) + unsigned int cubeVAO = 0; + unsigned int cubeVBO = 0; + + float vertices[] = { + // Positions Normals Texcoords + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, + 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f, + -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, + -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, + 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f, + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, + -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f, + -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, + 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, + -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, + -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f + }; + + // Gen VAO to contain VBO + glGenVertexArrays(1, &cubeVAO); + glBindVertexArray(cubeVAO); + + // Gen and fill vertex buffer (VBO) + glGenBuffers(1, &cubeVBO); + glBindBuffer(GL_ARRAY_BUFFER, cubeVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + // Bind vertex attributes (position, normals, texcoords) + glBindVertexArray(cubeVAO); + glEnableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION); + glVertexAttribPointer(RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)0); // Positions + glEnableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL); + glVertexAttribPointer(RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(3*sizeof(float))); // Normals + glEnableVertexAttribArray(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD); + glVertexAttribPointer(RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(6*sizeof(float))); // Texcoords + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + // Draw cube + glBindVertexArray(cubeVAO); + glDrawArrays(GL_TRIANGLES, 0, 36); + glBindVertexArray(0); + + // Delete VBO and VAO + glDeleteBuffers(1, &cubeVBO); + glDeleteVertexArrays(1, &cubeVAO); +#endif +} + +// Get name string for pixel format +const char *rlGetPixelFormatName(unsigned int format) +{ + switch (format) + { + case RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: return "GRAYSCALE"; break; // 8 bit per pixel (no alpha) + case RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: return "GRAY_ALPHA"; break; // 8*2 bpp (2 channels) + case RL_PIXELFORMAT_UNCOMPRESSED_R5G6B5: return "R5G6B5"; break; // 16 bpp + case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8: return "R8G8B8"; break; // 24 bpp + case RL_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: return "R5G5B5A1"; break; // 16 bpp (1 bit alpha) + case RL_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: return "R4G4B4A4"; break; // 16 bpp (4 bit alpha) + case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: return "R8G8B8A8"; break; // 32 bpp + case RL_PIXELFORMAT_UNCOMPRESSED_R32: return "R32"; break; // 32 bpp (1 channel - float) + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32: return "R32G32B32"; break; // 32*3 bpp (3 channels - float) + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: return "R32G32B32A32"; break; // 32*4 bpp (4 channels - float) + case RL_PIXELFORMAT_UNCOMPRESSED_R16: return "R16"; break; // 16 bpp (1 channel - half float) + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: return "R16G16B16"; break; // 16*3 bpp (3 channels - half float) + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: return "R16G16B16A16"; break; // 16*4 bpp (4 channels - half float) + case RL_PIXELFORMAT_COMPRESSED_DXT1_RGB: return "DXT1_RGB"; break; // 4 bpp (no alpha) + case RL_PIXELFORMAT_COMPRESSED_DXT1_RGBA: return "DXT1_RGBA"; break; // 4 bpp (1 bit alpha) + case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA: return "DXT3_RGBA"; break; // 8 bpp + case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA: return "DXT5_RGBA"; break; // 8 bpp + case RL_PIXELFORMAT_COMPRESSED_ETC1_RGB: return "ETC1_RGB"; break; // 4 bpp + case RL_PIXELFORMAT_COMPRESSED_ETC2_RGB: return "ETC2_RGB"; break; // 4 bpp + case RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: return "ETC2_RGBA"; break; // 8 bpp + case RL_PIXELFORMAT_COMPRESSED_PVRT_RGB: return "PVRT_RGB"; break; // 4 bpp + case RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA: return "PVRT_RGBA"; break; // 4 bpp + case RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: return "ASTC_4x4_RGBA"; break; // 8 bpp + case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: return "ASTC_8x8_RGBA"; break; // 2 bpp + default: return "UNKNOWN"; break; + } +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) +// Load default shader (just vertex positioning and texture coloring) +// NOTE: This shader program is used for internal buffers +// NOTE: Loaded: RLGL.State.defaultShaderId, RLGL.State.defaultShaderLocs +static void rlLoadShaderDefault(void) +{ + RLGL.State.defaultShaderLocs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int)); + + // NOTE: All locations must be reseted to -1 (no location) + for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) RLGL.State.defaultShaderLocs[i] = -1; + + // Vertex shader directly defined, no external file required + const char *defaultVShaderCode = +#if defined(GRAPHICS_API_OPENGL_21) + "#version 120 \n" + "attribute vec3 vertexPosition; \n" + "attribute vec2 vertexTexCoord; \n" + "attribute vec4 vertexColor; \n" + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" +#elif defined(GRAPHICS_API_OPENGL_33) + "#version 330 \n" + "in vec3 vertexPosition; \n" + "in vec2 vertexTexCoord; \n" + "in vec4 vertexColor; \n" + "out vec2 fragTexCoord; \n" + "out vec4 fragColor; \n" +#endif + +#if defined(GRAPHICS_API_OPENGL_ES3) + "#version 300 es \n" + "precision mediump float; \n" // Precision required for OpenGL ES3 (WebGL 2) (on some browsers) + "in vec3 vertexPosition; \n" + "in vec2 vertexTexCoord; \n" + "in vec4 vertexColor; \n" + "out vec2 fragTexCoord; \n" + "out vec4 fragColor; \n" +#elif defined(GRAPHICS_API_OPENGL_ES2) + "#version 100 \n" + "precision mediump float; \n" // Precision required for OpenGL ES2 (WebGL) (on some browsers) + "attribute vec3 vertexPosition; \n" + "attribute vec2 vertexTexCoord; \n" + "attribute vec4 vertexColor; \n" + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" +#endif + + "uniform mat4 mvp; \n" + "void main() \n" + "{ \n" + " fragTexCoord = vertexTexCoord; \n" + " fragColor = vertexColor; \n" + " gl_Position = mvp*vec4(vertexPosition, 1.0); \n" + "} \n"; + + // Fragment shader directly defined, no external file required + const char *defaultFShaderCode = +#if defined(GRAPHICS_API_OPENGL_21) + "#version 120 \n" + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" + "uniform sampler2D texture0; \n" + "uniform vec4 colDiffuse; \n" + "void main() \n" + "{ \n" + " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" + " gl_FragColor = texelColor*colDiffuse*fragColor; \n" + "} \n"; +#elif defined(GRAPHICS_API_OPENGL_33) + "#version 330 \n" + "in vec2 fragTexCoord; \n" + "in vec4 fragColor; \n" + "out vec4 finalColor; \n" + "uniform sampler2D texture0; \n" + "uniform vec4 colDiffuse; \n" + "void main() \n" + "{ \n" + " vec4 texelColor = texture(texture0, fragTexCoord); \n" + " finalColor = texelColor*colDiffuse*fragColor; \n" + "} \n"; +#endif + +#if defined(GRAPHICS_API_OPENGL_ES3) + "#version 300 es \n" + "precision mediump float; \n" // Precision required for OpenGL ES3 (WebGL 2) + "in vec2 fragTexCoord; \n" + "in vec4 fragColor; \n" + "out vec4 finalColor; \n" + "uniform sampler2D texture0; \n" + "uniform vec4 colDiffuse; \n" + "void main() \n" + "{ \n" + " vec4 texelColor = texture(texture0, fragTexCoord); \n" + " finalColor = texelColor*colDiffuse*fragColor; \n" + "} \n"; +#elif defined(GRAPHICS_API_OPENGL_ES2) + "#version 100 \n" + "precision mediump float; \n" // Precision required for OpenGL ES2 (WebGL) + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" + "uniform sampler2D texture0; \n" + "uniform vec4 colDiffuse; \n" + "void main() \n" + "{ \n" + " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" + " gl_FragColor = texelColor*colDiffuse*fragColor; \n" + "} \n"; +#endif + + // NOTE: Compiled vertex/fragment shaders are not deleted, + // they are kept for re-use as default shaders in case some shader loading fails + RLGL.State.defaultVShaderId = rlLoadShader(defaultVShaderCode, GL_VERTEX_SHADER); // Compile default vertex shader + RLGL.State.defaultFShaderId = rlLoadShader(defaultFShaderCode, GL_FRAGMENT_SHADER); // Compile default fragment shader + + RLGL.State.defaultShaderId = rlLoadShaderProgramEx(RLGL.State.defaultVShaderId, RLGL.State.defaultFShaderId); + + if (RLGL.State.defaultShaderId > 0) + { + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Default shader loaded successfully", RLGL.State.defaultShaderId); + + // Set default shader locations: attributes locations + RLGL.State.defaultShaderLocs[RL_SHADER_LOC_VERTEX_POSITION] = glGetAttribLocation(RLGL.State.defaultShaderId, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION); + RLGL.State.defaultShaderLocs[RL_SHADER_LOC_VERTEX_TEXCOORD01] = glGetAttribLocation(RLGL.State.defaultShaderId, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); + RLGL.State.defaultShaderLocs[RL_SHADER_LOC_VERTEX_COLOR] = glGetAttribLocation(RLGL.State.defaultShaderId, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR); + + // Set default shader locations: uniform locations + RLGL.State.defaultShaderLocs[RL_SHADER_LOC_MATRIX_MVP] = glGetUniformLocation(RLGL.State.defaultShaderId, RL_DEFAULT_SHADER_UNIFORM_NAME_MVP); + RLGL.State.defaultShaderLocs[RL_SHADER_LOC_COLOR_DIFFUSE] = glGetUniformLocation(RLGL.State.defaultShaderId, RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR); + RLGL.State.defaultShaderLocs[RL_SHADER_LOC_MAP_DIFFUSE] = glGetUniformLocation(RLGL.State.defaultShaderId, RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0); + } + else TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to load default shader", RLGL.State.defaultShaderId); +} + +// Unload default shader +// NOTE: Unloads: RLGL.State.defaultShaderId, RLGL.State.defaultShaderLocs +static void rlUnloadShaderDefault(void) +{ + glUseProgram(0); + + glDetachShader(RLGL.State.defaultShaderId, RLGL.State.defaultVShaderId); + glDetachShader(RLGL.State.defaultShaderId, RLGL.State.defaultFShaderId); + glDeleteShader(RLGL.State.defaultVShaderId); + glDeleteShader(RLGL.State.defaultFShaderId); + + glDeleteProgram(RLGL.State.defaultShaderId); + + RL_FREE(RLGL.State.defaultShaderLocs); + + TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Default shader unloaded successfully", RLGL.State.defaultShaderId); +} + +#if RLGL_SHOW_GL_DETAILS_INFO +// Get compressed format official GL identifier name +static const char *rlGetCompressedFormatName(int format) +{ + switch (format) + { + // GL_EXT_texture_compression_s3tc + case 0x83F0: return "GL_COMPRESSED_RGB_S3TC_DXT1_EXT"; break; + case 0x83F1: return "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT"; break; + case 0x83F2: return "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT"; break; + case 0x83F3: return "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT"; break; + // GL_3DFX_texture_compression_FXT1 + case 0x86B0: return "GL_COMPRESSED_RGB_FXT1_3DFX"; break; + case 0x86B1: return "GL_COMPRESSED_RGBA_FXT1_3DFX"; break; + // GL_IMG_texture_compression_pvrtc + case 0x8C00: return "GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG"; break; + case 0x8C01: return "GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG"; break; + case 0x8C02: return "GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG"; break; + case 0x8C03: return "GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG"; break; + // GL_OES_compressed_ETC1_RGB8_texture + case 0x8D64: return "GL_ETC1_RGB8_OES"; break; + // GL_ARB_texture_compression_rgtc + case 0x8DBB: return "GL_COMPRESSED_RED_RGTC1"; break; + case 0x8DBC: return "GL_COMPRESSED_SIGNED_RED_RGTC1"; break; + case 0x8DBD: return "GL_COMPRESSED_RG_RGTC2"; break; + case 0x8DBE: return "GL_COMPRESSED_SIGNED_RG_RGTC2"; break; + // GL_ARB_texture_compression_bptc + case 0x8E8C: return "GL_COMPRESSED_RGBA_BPTC_UNORM_ARB"; break; + case 0x8E8D: return "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB"; break; + case 0x8E8E: return "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB"; break; + case 0x8E8F: return "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB"; break; + // GL_ARB_ES3_compatibility + case 0x9274: return "GL_COMPRESSED_RGB8_ETC2"; break; + case 0x9275: return "GL_COMPRESSED_SRGB8_ETC2"; break; + case 0x9276: return "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2"; break; + case 0x9277: return "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2"; break; + case 0x9278: return "GL_COMPRESSED_RGBA8_ETC2_EAC"; break; + case 0x9279: return "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC"; break; + case 0x9270: return "GL_COMPRESSED_R11_EAC"; break; + case 0x9271: return "GL_COMPRESSED_SIGNED_R11_EAC"; break; + case 0x9272: return "GL_COMPRESSED_RG11_EAC"; break; + case 0x9273: return "GL_COMPRESSED_SIGNED_RG11_EAC"; break; + // GL_KHR_texture_compression_astc_hdr + case 0x93B0: return "GL_COMPRESSED_RGBA_ASTC_4x4_KHR"; break; + case 0x93B1: return "GL_COMPRESSED_RGBA_ASTC_5x4_KHR"; break; + case 0x93B2: return "GL_COMPRESSED_RGBA_ASTC_5x5_KHR"; break; + case 0x93B3: return "GL_COMPRESSED_RGBA_ASTC_6x5_KHR"; break; + case 0x93B4: return "GL_COMPRESSED_RGBA_ASTC_6x6_KHR"; break; + case 0x93B5: return "GL_COMPRESSED_RGBA_ASTC_8x5_KHR"; break; + case 0x93B6: return "GL_COMPRESSED_RGBA_ASTC_8x6_KHR"; break; + case 0x93B7: return "GL_COMPRESSED_RGBA_ASTC_8x8_KHR"; break; + case 0x93B8: return "GL_COMPRESSED_RGBA_ASTC_10x5_KHR"; break; + case 0x93B9: return "GL_COMPRESSED_RGBA_ASTC_10x6_KHR"; break; + case 0x93BA: return "GL_COMPRESSED_RGBA_ASTC_10x8_KHR"; break; + case 0x93BB: return "GL_COMPRESSED_RGBA_ASTC_10x10_KHR"; break; + case 0x93BC: return "GL_COMPRESSED_RGBA_ASTC_12x10_KHR"; break; + case 0x93BD: return "GL_COMPRESSED_RGBA_ASTC_12x12_KHR"; break; + case 0x93D0: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR"; break; + case 0x93D1: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR"; break; + case 0x93D2: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR"; break; + case 0x93D3: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR"; break; + case 0x93D4: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR"; break; + case 0x93D5: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR"; break; + case 0x93D6: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR"; break; + case 0x93D7: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR"; break; + case 0x93D8: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR"; break; + case 0x93D9: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR"; break; + case 0x93DA: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR"; break; + case 0x93DB: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR"; break; + case 0x93DC: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR"; break; + case 0x93DD: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR"; break; + default: return "GL_COMPRESSED_UNKNOWN"; break; + } +} +#endif + +#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 + +// Get pixel data size in bytes (image or texture) +// NOTE: Size depends on pixel format +static int rlGetPixelDataSize(int width, int height, int format) +{ + int dataSize = 0; // Size in bytes + int bpp = 0; // Bits per pixel + + switch (format) + { + case RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: bpp = 8; break; + case RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA: + case RL_PIXELFORMAT_UNCOMPRESSED_R5G6B5: + case RL_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1: + case RL_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4: bpp = 16; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8: bpp = 32; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8: bpp = 24; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32: bpp = 32; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32: bpp = 32*3; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32: bpp = 32*4; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16: bpp = 16; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16: bpp = 16*3; break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16: bpp = 16*4; break; + case RL_PIXELFORMAT_COMPRESSED_DXT1_RGB: + case RL_PIXELFORMAT_COMPRESSED_DXT1_RGBA: + case RL_PIXELFORMAT_COMPRESSED_ETC1_RGB: + case RL_PIXELFORMAT_COMPRESSED_ETC2_RGB: + case RL_PIXELFORMAT_COMPRESSED_PVRT_RGB: + case RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA: // 8 bytes per each 4x4 block + { + int blockWidth = (width + 3)/4; + int blockHeight = (height + 3)/4; + dataSize = blockWidth*blockHeight*8; + } break; + case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA: + case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA: + case RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA: + case RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA: // 16 bytes per each 4x4 block + { + int blockWidth = (width + 3)/4; + int blockHeight = (height + 3)/4; + dataSize = blockWidth*blockHeight*16; + } break; + case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: // 4 bytes per each 4x4 block + { + int blockWidth = (width + 3)/4; + int blockHeight = (height + 3)/4; + dataSize = blockWidth*blockHeight*4; + } break; + default: break; + } + + // Compute dataSize for uncompressed texture data (no blocks) + if ((format >= RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) && + (format <= RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16)) + { + double bytesPerPixel = (double)bpp/8.0; + dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes + } + + return dataSize; +} + +// Auxiliar math functions +//------------------------------------------------------------------------------- +// Get identity matrix +static Matrix rlMatrixIdentity(void) +{ + Matrix matIdentity = { 0 }; + matIdentity.m0 = 1.0f; + matIdentity.m5 = 1.0f; + matIdentity.m10 = 1.0f; + matIdentity.m15 = 1.0f; + + return matIdentity; +} +#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) +// Get float array of matrix data +// Explicit conversion to column-major memory layout +static rl_float16 rlMatrixToFloatV(Matrix mat) +{ + rl_float16 result = { 0 }; + + result.v[0] = mat.m0; + result.v[1] = mat.m1; + result.v[2] = mat.m2; + result.v[3] = mat.m3; + result.v[4] = mat.m4; + result.v[5] = mat.m5; + result.v[6] = mat.m6; + result.v[7] = mat.m7; + result.v[8] = mat.m8; + result.v[9] = mat.m9; + result.v[10] = mat.m10; + result.v[11] = mat.m11; + result.v[12] = mat.m12; + result.v[13] = mat.m13; + result.v[14] = mat.m14; + result.v[15] = mat.m15; + + return result; +} + +// Get two matrix multiplication +// NOTE: When multiplying matrices... the order matters! +static Matrix rlMatrixMultiply(Matrix left, Matrix right) +{ + Matrix result = { 0 }; + + result.m0 = left.m0*right.m0 + left.m1*right.m4 + left.m2*right.m8 + left.m3*right.m12; + result.m1 = left.m0*right.m1 + left.m1*right.m5 + left.m2*right.m9 + left.m3*right.m13; + result.m2 = left.m0*right.m2 + left.m1*right.m6 + left.m2*right.m10 + left.m3*right.m14; + result.m3 = left.m0*right.m3 + left.m1*right.m7 + left.m2*right.m11 + left.m3*right.m15; + result.m4 = left.m4*right.m0 + left.m5*right.m4 + left.m6*right.m8 + left.m7*right.m12; + result.m5 = left.m4*right.m1 + left.m5*right.m5 + left.m6*right.m9 + left.m7*right.m13; + result.m6 = left.m4*right.m2 + left.m5*right.m6 + left.m6*right.m10 + left.m7*right.m14; + result.m7 = left.m4*right.m3 + left.m5*right.m7 + left.m6*right.m11 + left.m7*right.m15; + result.m8 = left.m8*right.m0 + left.m9*right.m4 + left.m10*right.m8 + left.m11*right.m12; + result.m9 = left.m8*right.m1 + left.m9*right.m5 + left.m10*right.m9 + left.m11*right.m13; + result.m10 = left.m8*right.m2 + left.m9*right.m6 + left.m10*right.m10 + left.m11*right.m14; + result.m11 = left.m8*right.m3 + left.m9*right.m7 + left.m10*right.m11 + left.m11*right.m15; + result.m12 = left.m12*right.m0 + left.m13*right.m4 + left.m14*right.m8 + left.m15*right.m12; + result.m13 = left.m12*right.m1 + left.m13*right.m5 + left.m14*right.m9 + left.m15*right.m13; + result.m14 = left.m12*right.m2 + left.m13*right.m6 + left.m14*right.m10 + left.m15*right.m14; + result.m15 = left.m12*right.m3 + left.m13*right.m7 + left.m14*right.m11 + left.m15*right.m15; + + return result; +} + +// Transposes provided matrix +static Matrix rlMatrixTranspose(Matrix mat) +{ + Matrix result = { 0 }; + + result.m0 = mat.m0; + result.m1 = mat.m4; + result.m2 = mat.m8; + result.m3 = mat.m12; + result.m4 = mat.m1; + result.m5 = mat.m5; + result.m6 = mat.m9; + result.m7 = mat.m13; + result.m8 = mat.m2; + result.m9 = mat.m6; + result.m10 = mat.m10; + result.m11 = mat.m14; + result.m12 = mat.m3; + result.m13 = mat.m7; + result.m14 = mat.m11; + result.m15 = mat.m15; + + return result; +} + +// Invert provided matrix +static Matrix rlMatrixInvert(Matrix mat) +{ + Matrix result = { 0 }; + + // Cache the matrix values (speed optimization) + float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; + float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7; + float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; + float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15; + + float b00 = a00*a11 - a01*a10; + float b01 = a00*a12 - a02*a10; + float b02 = a00*a13 - a03*a10; + float b03 = a01*a12 - a02*a11; + float b04 = a01*a13 - a03*a11; + float b05 = a02*a13 - a03*a12; + float b06 = a20*a31 - a21*a30; + float b07 = a20*a32 - a22*a30; + float b08 = a20*a33 - a23*a30; + float b09 = a21*a32 - a22*a31; + float b10 = a21*a33 - a23*a31; + float b11 = a22*a33 - a23*a32; + + // Calculate the invert determinant (inlined to avoid double-caching) + float invDet = 1.0f/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06); + + result.m0 = (a11*b11 - a12*b10 + a13*b09)*invDet; + result.m1 = (-a01*b11 + a02*b10 - a03*b09)*invDet; + result.m2 = (a31*b05 - a32*b04 + a33*b03)*invDet; + result.m3 = (-a21*b05 + a22*b04 - a23*b03)*invDet; + result.m4 = (-a10*b11 + a12*b08 - a13*b07)*invDet; + result.m5 = (a00*b11 - a02*b08 + a03*b07)*invDet; + result.m6 = (-a30*b05 + a32*b02 - a33*b01)*invDet; + result.m7 = (a20*b05 - a22*b02 + a23*b01)*invDet; + result.m8 = (a10*b10 - a11*b08 + a13*b06)*invDet; + result.m9 = (-a00*b10 + a01*b08 - a03*b06)*invDet; + result.m10 = (a30*b04 - a31*b02 + a33*b00)*invDet; + result.m11 = (-a20*b04 + a21*b02 - a23*b00)*invDet; + result.m12 = (-a10*b09 + a11*b07 - a12*b06)*invDet; + result.m13 = (a00*b09 - a01*b07 + a02*b06)*invDet; + result.m14 = (-a30*b03 + a31*b01 - a32*b00)*invDet; + result.m15 = (a20*b03 - a21*b01 + a22*b00)*invDet; + + return result; +} +#endif + +#endif // RLGL_IMPLEMENTATION diff --git a/raylib-6.0_linux_amd64/lib/libraylib.a b/raylib-6.0_linux_amd64/lib/libraylib.a new file mode 100644 index 0000000000000000000000000000000000000000..f9c84e2d5872f7b29dcadf3bc62efdb727e942f0 GIT binary patch literal 2869420 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

45=C&KrFKN&s+Uk|@C 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

g9Zg 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

  • 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

    _%`EVL@n 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%0Ab!uihjm;{kAkM&>||}ZB&OOpqf6Sl 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�aVqb$(IF7>&=@Bbd1 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