diff --git a/.vscode/tasks.json b/.vscode/tasks.json index b785ef9..de8193c 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -14,6 +14,7 @@ { "value": "-v", "quoting": "strong" }, { "value": "-b", "quoting": "strong" }, { "value": "-Iinclude", "quoting": "strong" }, + { "value": "-Iraylib/src", "quoting": "strong" }, { "value": "-Llib", "quoting": "strong" }, { "value": "-stdc99", "quoting": "strong" }, { "value": "-Wall", "quoting": "strong" }, @@ -42,6 +43,7 @@ { "value": "-bench", "quoting": "strong" }, { "value": "-v", "quoting": "strong" }, { "value": "-Iinclude", "quoting": "strong" }, + { "value": "-Iraylib/src", "quoting": "strong" }, { "value": "-Llib", "quoting": "strong" }, { "value": "-stdc99", "quoting": "strong" }, { "value": "-Wall", "quoting": "strong" }, diff --git a/include/config.h b/include/config.h deleted file mode 100644 index e77d1f8..0000000 --- a/include/config.h +++ /dev/null @@ -1,230 +0,0 @@ -/********************************************************************************************** -* -* raylib configuration flags -* -* This file defines all the configuration flags for the different raylib modules -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2018-2021 Ahmad Fatoum & 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. -* -**********************************************************************************************/ - -//------------------------------------------------------------------------------------ -// Module: core - Configuration Flags -//------------------------------------------------------------------------------------ -// Camera module is included (rcamera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital -#define SUPPORT_CAMERA_SYSTEM 1 -// Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag -#define SUPPORT_GESTURES_SYSTEM 1 -// Mouse gestures are directly mapped like touches and processed by gestures system -#define SUPPORT_MOUSE_GESTURES 1 -// Reconfigure standard input to receive key inputs, works with SSH connection. -#define SUPPORT_SSH_KEYBOARD_RPI 1 -// Draw a mouse pointer on screen -//#define SUPPORT_MOUSE_CURSOR_POINT 1 -// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions. -// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often. -#define SUPPORT_WINMM_HIGHRES_TIMER 1 -// Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used -//#define SUPPORT_BUSY_WAIT_LOOP 1 -// Use a partial-busy wait loop, in this case frame sleeps for most of the time, but then runs a busy loop at the end for accuracy -#define SUPPORT_PARTIALBUSY_WAIT_LOOP -// Wait for events passively (sleeping while no events) instead of polling them actively every frame -//#define SUPPORT_EVENTS_WAITING 1 -// Allow automatic screen capture of current screen pressing F12, defined in KeyCallback() -#define SUPPORT_SCREEN_CAPTURE 1 -// Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback() -#define SUPPORT_GIF_RECORDING 1 -// Support CompressData() and DecompressData() functions -#define SUPPORT_COMPRESSION_API 1 -// Support saving binary data automatically to a generated storage.data file. This file is managed internally. -#define SUPPORT_DATA_STORAGE 1 -// Support automatic generated events, loading and recording of those events when required -#define SUPPORT_EVENTS_AUTOMATION 1 -// Support custom frame control, only for advance users -// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timming + PollInputEvents() -// Enabling this flag allows manual control of the frame processes, use at your own risk -//#define SUPPORT_CUSTOM_FRAME_CONTROL 1 - -// core: Configuration values -//------------------------------------------------------------------------------------ -#if defined(__linux__) - #define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value) -#else - #define MAX_FILEPATH_LENGTH 512 // Maximum length supported for filepaths -#endif - -#define MAX_GAMEPADS 4 // Max number of gamepads supported -#define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad) -#define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad) -#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported -#define MAX_KEY_PRESSED_QUEUE 16 // Max number of characters in the key input queue - -#define STORAGE_DATA_FILE "storage.data" // Automatic storage filename - -#define MAX_DECOMPRESSION_SIZE 64 // Max size allocated for decompression in MB - - -//------------------------------------------------------------------------------------ -// Module: rlgl - Configuration values -//------------------------------------------------------------------------------------ - -// Enable OpenGL Debug Context (only available on OpenGL 4.3) -//#define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT 1 - -// Show OpenGL extensions and capabilities detailed logs on init -//#define RLGL_SHOW_GL_DETAILS_INFO 1 - -//#define RL_DEFAULT_BATCH_BUFFER_ELEMENTS 4096 // 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 textures 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.01 // Default projection matrix near cull distance -#define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance - -// Default shader vertex attribute names to set location points -// NOTE: When a new shader is loaded, the following locations are tried to be set for convenience -#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Binded by default to shader location: 0 -#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1 -#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2 -#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3 -#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4 -#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5 - -#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_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) - - -//------------------------------------------------------------------------------------ -// Module: shapes - Configuration Flags -//------------------------------------------------------------------------------------ -// Use QUADS instead of TRIANGLES for drawing when possible -// Some lines-based shapes could still use lines -#define SUPPORT_QUADS_DRAW_MODE 1 - - -//------------------------------------------------------------------------------------ -// Module: textures - Configuration Flags -//------------------------------------------------------------------------------------ -// Selecte desired fileformats to be supported for image data loading -#define SUPPORT_FILEFORMAT_PNG 1 -//#define SUPPORT_FILEFORMAT_BMP 1 -//#define SUPPORT_FILEFORMAT_TGA 1 -#define SUPPORT_FILEFORMAT_JPG 1 -#define SUPPORT_FILEFORMAT_GIF 1 -//#define SUPPORT_FILEFORMAT_PSD 1 -//#define SUPPORT_FILEFORMAT_DDS 1 -//#define SUPPORT_FILEFORMAT_HDR 1 -//#define SUPPORT_FILEFORMAT_KTX 1 -//#define SUPPORT_FILEFORMAT_ASTC 1 -//#define SUPPORT_FILEFORMAT_PKM 1 -//#define SUPPORT_FILEFORMAT_PVR 1 - -// Support image export functionality (.png, .bmp, .tga, .jpg) -#define SUPPORT_IMAGE_EXPORT 1 -// Support procedural image generation functionality (gradient, spot, perlin-noise, cellular) -#define SUPPORT_IMAGE_GENERATION 1 -// Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop... -// If not defined, still some functions are supported: ImageFormat(), ImageCrop(), ImageToPOT() -#define SUPPORT_IMAGE_MANIPULATION 1 - - -//------------------------------------------------------------------------------------ -// Module: text - Configuration Flags -//------------------------------------------------------------------------------------ -// Default font is loaded on window initialization to be available for the user to render simple text -// NOTE: If enabled, uses external module functions to load default raylib font -#define SUPPORT_DEFAULT_FONT 1 -// Selected desired font fileformats to be supported for loading -#define SUPPORT_FILEFORMAT_FNT 1 -#define SUPPORT_FILEFORMAT_TTF 1 - -// Support text management functions -// If not defined, still some functions are supported: TextLength(), TextFormat() -#define SUPPORT_TEXT_MANIPULATION 1 - -// text: Configuration values -//------------------------------------------------------------------------------------ -#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions: - // TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit() -#define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit() - - -//------------------------------------------------------------------------------------ -// Module: models - Configuration Flags -//------------------------------------------------------------------------------------ -// Selected desired model fileformats to be supported for loading -#define SUPPORT_FILEFORMAT_OBJ 1 -#define SUPPORT_FILEFORMAT_MTL 1 -#define SUPPORT_FILEFORMAT_IQM 1 -#define SUPPORT_FILEFORMAT_GLTF 1 -#define SUPPORT_FILEFORMAT_VOX 1 -// Support procedural mesh generation functions, uses external par_shapes.h library -// NOTE: Some generated meshes DO NOT include generated texture coordinates -#define SUPPORT_MESH_GENERATION 1 - -// models: Configuration values -//------------------------------------------------------------------------------------ -#define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported -#define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh - -//------------------------------------------------------------------------------------ -// Module: audio - Configuration Flags -//------------------------------------------------------------------------------------ -// Desired audio fileformats to be supported for loading -#define SUPPORT_FILEFORMAT_WAV 1 -#define SUPPORT_FILEFORMAT_OGG 1 -#define SUPPORT_FILEFORMAT_XM 1 -#define SUPPORT_FILEFORMAT_MOD 1 -#define SUPPORT_FILEFORMAT_MP3 1 -//#define SUPPORT_FILEFORMAT_FLAC 1 - -// audio: Configuration values -//------------------------------------------------------------------------------------ -#define AUDIO_DEVICE_FORMAT ma_format_f32 // Device output format (miniaudio: float-32bit) -#define AUDIO_DEVICE_CHANNELS 2 // Device output channels: stereo -#define AUDIO_DEVICE_SAMPLE_RATE 0 // Device sample rate (device default) - -#define MAX_AUDIO_BUFFER_POOL_CHANNELS 16 // Maximum number of audio pool channels - -//------------------------------------------------------------------------------------ -// Module: utils - Configuration Flags -//------------------------------------------------------------------------------------ -// Standard file io library (stdio.h) included -#define SUPPORT_STANDARD_FILEIO -// Show TRACELOG() output messages -// NOTE: By default LOG_DEBUG traces not shown -#define SUPPORT_TRACELOG 1 -//#define SUPPORT_TRACELOG_DEBUG 1 - -// utils: Configuration values -//------------------------------------------------------------------------------------ -#define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message diff --git a/include/easings.h b/include/easings.h deleted file mode 100644 index 3441305..0000000 --- a/include/easings.h +++ /dev/null @@ -1,263 +0,0 @@ -/******************************************************************************************* -* -* raylib easings (header only file) -* -* Useful easing functions for values animation -* -* This header uses: -* #define EASINGS_STATIC_INLINE // Inlines all functions code, so it runs faster. -* // This requires lots of memory on system. -* How to use: -* The four inputs t,b,c,d are defined as follows: -* t = current time (in any unit measure, but same unit as duration) -* b = starting value to interpolate -* c = the total change in value of b that needs to occur -* d = total time it should take to complete (duration) -* -* Example: -* -* int currentTime = 0; -* int duration = 100; -* float startPositionX = 0.0f; -* float finalPositionX = 30.0f; -* float currentPositionX = startPositionX; -* -* while (currentPositionX < finalPositionX) -* { -* currentPositionX = EaseSineIn(currentTime, startPositionX, finalPositionX - startPositionX, duration); -* currentTime++; -* } -* -* A port of Robert Penner's easing equations to C (http://robertpenner.com/easing/) -* -* Robert Penner License -* --------------------------------------------------------------------------------- -* Open source under the BSD License. -* -* Copyright (c) 2001 Robert Penner. All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, -* are permitted provided that the following conditions are met: -* -* - Redistributions of source code must retain the above copyright notice, -* this list of conditions and the following disclaimer. -* - Redistributions in binary form must reproduce the above copyright notice, -* this list of conditions and the following disclaimer in the documentation -* and/or other materials provided with the distribution. -* - Neither the name of the author nor the names of contributors may be used -* to endorse or promote products derived from this software without specific -* prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -* OF THE POSSIBILITY OF SUCH DAMAGE. -* --------------------------------------------------------------------------------- -* -* Copyright (c) 2015 Ramon Santamaria -* -* 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 EASINGS_H -#define EASINGS_H - -#define EASINGS_STATIC_INLINE // NOTE: By default, compile functions as static inline - -#if defined(EASINGS_STATIC_INLINE) - #define EASEDEF static inline -#else - #define EASEDEF extern -#endif - -#include // Required for: sinf(), cosf(), sqrtf(), powf() - -#ifndef PI - #define PI 3.14159265358979323846f //Required as PI is not always defined in math.h -#endif - -#ifdef __cplusplus -extern "C" { // Prevents name mangling of functions -#endif - -// Linear Easing functions -EASEDEF float EaseLinearNone(float t, float b, float c, float d) { return (c*t/d + b); } -EASEDEF float EaseLinearIn(float t, float b, float c, float d) { return (c*t/d + b); } -EASEDEF float EaseLinearOut(float t, float b, float c, float d) { return (c*t/d + b); } -EASEDEF float EaseLinearInOut(float t,float b, float c, float d) { return (c*t/d + b); } - -// Sine Easing functions -EASEDEF float EaseSineIn(float t, float b, float c, float d) { return (-c*cosf(t/d*(PI/2.0f)) + c + b); } -EASEDEF float EaseSineOut(float t, float b, float c, float d) { return (c*sinf(t/d*(PI/2.0f)) + b); } -EASEDEF float EaseSineInOut(float t, float b, float c, float d) { return (-c/2.0f*(cosf(PI*t/d) - 1.0f) + b); } - -// Circular Easing functions -EASEDEF float EaseCircIn(float t, float b, float c, float d) { t /= d; return (-c*(sqrtf(1.0f - t*t) - 1.0f) + b); } -EASEDEF float EaseCircOut(float t, float b, float c, float d) { t = t/d - 1.0f; return (c*sqrtf(1.0f - t*t) + b); } -EASEDEF float EaseCircInOut(float t, float b, float c, float d) -{ - if ((t/=d/2.0f) < 1.0f) return (-c/2.0f*(sqrtf(1.0f - t*t) - 1.0f) + b); - t -= 2.0f; return (c/2.0f*(sqrtf(1.0f - t*t) + 1.0f) + b); -} - -// Cubic Easing functions -EASEDEF float EaseCubicIn(float t, float b, float c, float d) { t /= d; return (c*t*t*t + b); } -EASEDEF float EaseCubicOut(float t, float b, float c, float d) { t = t/d - 1.0f; return (c*(t*t*t + 1.0f) + b); } -EASEDEF float EaseCubicInOut(float t, float b, float c, float d) -{ - if ((t/=d/2.0f) < 1.0f) return (c/2.0f*t*t*t + b); - t -= 2.0f; return (c/2.0f*(t*t*t + 2.0f) + b); -} - -// Quadratic Easing functions -EASEDEF float EaseQuadIn(float t, float b, float c, float d) { t /= d; return (c*t*t + b); } -EASEDEF float EaseQuadOut(float t, float b, float c, float d) { t /= d; return (-c*t*(t - 2.0f) + b); } -EASEDEF float EaseQuadInOut(float t, float b, float c, float d) -{ - if ((t/=d/2) < 1) return (((c/2)*(t*t)) + b); - return (-c/2.0f*(((t - 1.0f)*(t - 3.0f)) - 1.0f) + b); -} - -// Exponential Easing functions -EASEDEF float EaseExpoIn(float t, float b, float c, float d) { return (t == 0.0f) ? b : (c*powf(2.0f, 10.0f*(t/d - 1.0f)) + b); } -EASEDEF float EaseExpoOut(float t, float b, float c, float d) { return (t == d) ? (b + c) : (c*(-powf(2.0f, -10.0f*t/d) + 1.0f) + b); } -EASEDEF float EaseExpoInOut(float t, float b, float c, float d) -{ - if (t == 0.0f) return b; - if (t == d) return (b + c); - if ((t/=d/2.0f) < 1.0f) return (c/2.0f*powf(2.0f, 10.0f*(t - 1.0f)) + b); - - return (c/2.0f*(-powf(2.0f, -10.0f*(t - 1.0f)) + 2.0f) + b); -} - -// Back Easing functions -EASEDEF float EaseBackIn(float t, float b, float c, float d) -{ - float s = 1.70158f; - float postFix = t/=d; - return (c*(postFix)*t*((s + 1.0f)*t - s) + b); -} - -EASEDEF float EaseBackOut(float t, float b, float c, float d) -{ - float s = 1.70158f; - t = t/d - 1.0f; - return (c*(t*t*((s + 1.0f)*t + s) + 1.0f) + b); -} - -EASEDEF float EaseBackInOut(float t, float b, float c, float d) -{ - float s = 1.70158f; - if ((t/=d/2.0f) < 1.0f) - { - s *= 1.525f; - return (c/2.0f*(t*t*((s + 1.0f)*t - s)) + b); - } - - float postFix = t-=2.0f; - s *= 1.525f; - return (c/2.0f*((postFix)*t*((s + 1.0f)*t + s) + 2.0f) + b); -} - -// Bounce Easing functions -EASEDEF float EaseBounceOut(float t, float b, float c, float d) -{ - if ((t/=d) < (1.0f/2.75f)) - { - return (c*(7.5625f*t*t) + b); - } - else if (t < (2.0f/2.75f)) - { - float postFix = t-=(1.5f/2.75f); - return (c*(7.5625f*(postFix)*t + 0.75f) + b); - } - else if (t < (2.5/2.75)) - { - float postFix = t-=(2.25f/2.75f); - return (c*(7.5625f*(postFix)*t + 0.9375f) + b); - } - else - { - float postFix = t-=(2.625f/2.75f); - return (c*(7.5625f*(postFix)*t + 0.984375f) + b); - } -} - -EASEDEF float EaseBounceIn(float t, float b, float c, float d) { return (c - EaseBounceOut(d - t, 0.0f, c, d) + b); } -EASEDEF float EaseBounceInOut(float t, float b, float c, float d) -{ - if (t < d/2.0f) return (EaseBounceIn(t*2.0f, 0.0f, c, d)*0.5f + b); - else return (EaseBounceOut(t*2.0f - d, 0.0f, c, d)*0.5f + c*0.5f + b); -} - -// Elastic Easing functions -EASEDEF float EaseElasticIn(float t, float b, float c, float d) -{ - if (t == 0.0f) return b; - if ((t/=d) == 1.0f) return (b + c); - - float p = d*0.3f; - float a = c; - float s = p/4.0f; - float postFix = a*powf(2.0f, 10.0f*(t-=1.0f)); - - return (-(postFix*sinf((t*d-s)*(2.0f*PI)/p )) + b); -} - -EASEDEF float EaseElasticOut(float t, float b, float c, float d) -{ - if (t == 0.0f) return b; - if ((t/=d) == 1.0f) return (b + c); - - float p = d*0.3f; - float a = c; - float s = p/4.0f; - - return (a*powf(2.0f,-10.0f*t)*sinf((t*d-s)*(2.0f*PI)/p) + c + b); -} - -EASEDEF float EaseElasticInOut(float t, float b, float c, float d) -{ - if (t == 0.0f) return b; - if ((t/=d/2.0f) == 2.0f) return (b + c); - - float p = d*(0.3f*1.5f); - float a = c; - float s = p/4.0f; - - if (t < 1.0f) - { - float postFix = a*powf(2.0f, 10.0f*(t-=1.0f)); - return -0.5f*(postFix*sinf((t*d-s)*(2.0f*PI)/p)) + b; - } - - float postFix = a*powf(2.0f, -10.0f*(t-=1.0f)); - - return (postFix*sinf((t*d-s)*(2.0f*PI)/p)*0.5f + c + b); -} - -#ifdef __cplusplus -} -#endif - -#endif // EASINGS_H diff --git a/include/physac.h b/include/physac.h deleted file mode 100644 index 642c25a..0000000 --- a/include/physac.h +++ /dev/null @@ -1,1977 +0,0 @@ -/********************************************************************************************** -* -* Physac v1.1 - 2D Physics library for videogames -* -* DESCRIPTION: -* -* Physac is a small 2D physics engine written in pure C. The engine uses a fixed time-step thread loop -* to simluate physics. A physics step contains the following phases: get collision information, -* apply dynamics, collision solving and position correction. It uses a very simple struct for physic -* bodies with a position vector to be used in any 3D rendering API. -* -* CONFIGURATION: -* -* #define PHYSAC_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 PHYSAC_DEBUG -* Show debug traces log messages about physic bodies creation/destruction, physic system errors, -* some calculations results and NULL reference exceptions. -* -* #define PHYSAC_AVOID_TIMMING_SYSTEM -* Disables internal timming system, used by UpdatePhysics() to launch timmed physic steps, -* it allows just running UpdatePhysics() automatically on a separate thread at a desired time step. -* In case physics steps update needs to be controlled by user with a custom timming mechanism, -* just define this flag and the internal timming mechanism will be avoided, in that case, -* timming libraries are neither required by the module. -* -* #define PHYSAC_MALLOC() -* #define PHYSAC_CALLOC() -* #define PHYSAC_FREE() -* You can define your own malloc/free implementation replacing stdlib.h malloc()/free() functions. -* Otherwise it will include stdlib.h and use the C standard library malloc()/free() function. -* -* COMPILATION: -* -* Use the following code to compile with GCC: -* gcc -o $(NAME_PART).exe $(FILE_NAME) -s -static -lraylib -lopengl32 -lgdi32 -lwinmm -std=c99 -* -* VERSIONS HISTORY: -* 1.1 (20-Jan-2021) @raysan5: Library general revision -* Removed threading system (up to the user) -* Support MSVC C++ compilation using CLITERAL() -* Review DEBUG mechanism for TRACELOG() and all TRACELOG() messages -* Review internal variables/functions naming for consistency -* Allow option to avoid internal timming system, to allow app manage the steps -* 1.0 (12-Jun-2017) First release of the library -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2016-2021 Victor Fisac (@victorfisac) and 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. -* -**********************************************************************************************/ - -#if !defined(PHYSAC_H) -#define PHYSAC_H - -#ifndef PHYSACDEF - #define PHYSACDEF // We are building or using physac as a static library -#endif - -// Allow custom memory allocators -#ifndef PHYSAC_MALLOC - #define PHYSAC_MALLOC(size) malloc(size) -#endif -#ifndef PHYSAC_CALLOC - #define PHYSAC_CALLOC(size, n) calloc(size, n) -#endif -#ifndef PHYSAC_FREE - #define PHYSAC_FREE(ptr) free(ptr) -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define PHYSAC_MAX_BODIES 64 // Maximum number of physic bodies supported -#define PHYSAC_MAX_MANIFOLDS 4096 // Maximum number of physic bodies interactions (64x64) -#define PHYSAC_MAX_VERTICES 24 // Maximum number of vertex for polygons shapes -#define PHYSAC_DEFAULT_CIRCLE_VERTICES 24 // Default number of vertices for circle shapes - -#define PHYSAC_COLLISION_ITERATIONS 100 -#define PHYSAC_PENETRATION_ALLOWANCE 0.05f -#define PHYSAC_PENETRATION_CORRECTION 0.4f - -#define PHYSAC_PI 3.14159265358979323846f -#define PHYSAC_DEG2RAD (PHYSAC_PI/180.0f) - -//---------------------------------------------------------------------------------- -// Data Types Structure Definition -//---------------------------------------------------------------------------------- -#if defined(__STDC__) && __STDC_VERSION__ >= 199901L - #include -#endif - -typedef enum PhysicsShapeType { PHYSICS_CIRCLE = 0, PHYSICS_POLYGON } PhysicsShapeType; - -// Previously defined to be used in PhysicsShape struct as circular dependencies -typedef struct PhysicsBodyData *PhysicsBody; - -#if !defined(RL_VECTOR2_TYPE) -// Vector2 type -typedef struct Vector2 { - float x; - float y; -} Vector2; -#endif - -// Matrix2x2 type (used for polygon shape rotation matrix) -typedef struct Matrix2x2 { - float m00; - float m01; - float m10; - float m11; -} Matrix2x2; - -typedef struct PhysicsVertexData { - unsigned int vertexCount; // Vertex count (positions and normals) - Vector2 positions[PHYSAC_MAX_VERTICES]; // Vertex positions vectors - Vector2 normals[PHYSAC_MAX_VERTICES]; // Vertex normals vectors -} PhysicsVertexData; - -typedef struct PhysicsShape { - PhysicsShapeType type; // Shape type (circle or polygon) - PhysicsBody body; // Shape physics body data pointer - PhysicsVertexData vertexData; // Shape vertices data (used for polygon shapes) - float radius; // Shape radius (used for circle shapes) - Matrix2x2 transform; // Vertices transform matrix 2x2 -} PhysicsShape; - -typedef struct PhysicsBodyData { - unsigned int id; // Unique identifier - bool enabled; // Enabled dynamics state (collisions are calculated anyway) - Vector2 position; // Physics body shape pivot - Vector2 velocity; // Current linear velocity applied to position - Vector2 force; // Current linear force (reset to 0 every step) - float angularVelocity; // Current angular velocity applied to orient - float torque; // Current angular force (reset to 0 every step) - float orient; // Rotation in radians - float inertia; // Moment of inertia - float inverseInertia; // Inverse value of inertia - float mass; // Physics body mass - float inverseMass; // Inverse value of mass - float staticFriction; // Friction when the body has not movement (0 to 1) - float dynamicFriction; // Friction when the body has movement (0 to 1) - float restitution; // Restitution coefficient of the body (0 to 1) - bool useGravity; // Apply gravity force to dynamics - bool isGrounded; // Physics grounded on other body state - bool freezeOrient; // Physics rotation constraint - PhysicsShape shape; // Physics body shape information (type, radius, vertices, transform) -} PhysicsBodyData; - -typedef struct PhysicsManifoldData { - unsigned int id; // Unique identifier - PhysicsBody bodyA; // Manifold first physics body reference - PhysicsBody bodyB; // Manifold second physics body reference - float penetration; // Depth of penetration from collision - Vector2 normal; // Normal direction vector from 'a' to 'b' - Vector2 contacts[2]; // Points of contact during collision - unsigned int contactsCount; // Current collision number of contacts - float restitution; // Mixed restitution during collision - float dynamicFriction; // Mixed dynamic friction during collision - float staticFriction; // Mixed static friction during collision -} PhysicsManifoldData, *PhysicsManifold; - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- - -#if defined(__cplusplus) -extern "C" { // Prevents name mangling of functions -#endif -// Physics system management -PHYSACDEF void InitPhysics(void); // Initializes physics system -PHYSACDEF void UpdatePhysics(void); // Update physics system -PHYSACDEF void ResetPhysics(void); // Reset physics system (global variables) -PHYSACDEF void ClosePhysics(void); // Close physics system and unload used memory -PHYSACDEF void SetPhysicsTimeStep(double delta); // Sets physics fixed time step in milliseconds. 1.666666 by default -PHYSACDEF void SetPhysicsGravity(float x, float y); // Sets physics global gravity force - -// Physic body creation/destroy -PHYSACDEF PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density); // Creates a new circle physics body with generic parameters -PHYSACDEF PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float height, float density); // Creates a new rectangle physics body with generic parameters -PHYSACDEF PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int sides, float density); // Creates a new polygon physics body with generic parameters -PHYSACDEF void DestroyPhysicsBody(PhysicsBody body); // Destroy a physics body - -// Physic body forces -PHYSACDEF void PhysicsAddForce(PhysicsBody body, Vector2 force); // Adds a force to a physics body -PHYSACDEF void PhysicsAddTorque(PhysicsBody body, float amount); // Adds an angular force to a physics body -PHYSACDEF void PhysicsShatter(PhysicsBody body, Vector2 position, float force); // Shatters a polygon shape physics body to little physics bodies with explosion force -PHYSACDEF void SetPhysicsBodyRotation(PhysicsBody body, float radians); // Sets physics body shape transform based on radians parameter - -// Query physics info -PHYSACDEF PhysicsBody GetPhysicsBody(int index); // Returns a physics body of the bodies pool at a specific index -PHYSACDEF int GetPhysicsBodiesCount(void); // Returns the current amount of created physics bodies -PHYSACDEF int GetPhysicsShapeType(int index); // Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON) -PHYSACDEF int GetPhysicsShapeVerticesCount(int index); // Returns the amount of vertices of a physics body shape -PHYSACDEF Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex); // Returns transformed position of a body shape (body position + vertex transformed position) -#if defined(__cplusplus) -} -#endif - -#endif // PHYSAC_H - -/*********************************************************************************** -* -* PHYSAC IMPLEMENTATION -* -************************************************************************************/ - -#if defined(PHYSAC_IMPLEMENTATION) - -// Support TRACELOG macros -#if defined(PHYSAC_DEBUG) - #include // Required for: printf() - #define TRACELOG(...) printf(__VA_ARGS__) -#else - #define TRACELOG(...) (void)0; -#endif - -#include // Required for: malloc(), calloc(), free() -#include // Required for: cosf(), sinf(), fabs(), sqrtf() - -#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) - // Time management functionality - #include // Required for: time(), clock_gettime() - #if defined(_WIN32) - #if defined(__cplusplus) - extern "C" { // Prevents name mangling of functions - #endif - // Functions required to query time on Windows - int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); - int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); - #if defined(__cplusplus) - } - #endif - #endif - #if defined(__linux__) || defined(__FreeBSD__) - #if _POSIX_C_SOURCE < 199309L - #undef _POSIX_C_SOURCE - #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. - #endif - #include // Required for: timespec - #endif - #if defined(__APPLE__) // macOS also defines __MACH__ - #include // Required for: mach_absolute_time() - #endif -#endif - -// NOTE: MSVC C++ compiler does not support compound literals (C99 feature) -// Plain structures in C++ (without constructors) can be initialized from { } initializers. -#if defined(__cplusplus) - #define CLITERAL(type) type -#else - #define CLITERAL(type) (type) -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define PHYSAC_MIN(a,b) (((a)<(b))?(a):(b)) -#define PHYSAC_MAX(a,b) (((a)>(b))?(a):(b)) -#define PHYSAC_FLT_MAX 3.402823466e+38f -#define PHYSAC_EPSILON 0.000001f -#define PHYSAC_K 1.0f/3.0f -#define PHYSAC_VECTOR_ZERO CLITERAL(Vector2){ 0.0f, 0.0f } - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -static double deltaTime = 1.0/60.0/10.0 * 1000; // Delta time in milliseconds used for physics steps - -#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) -// Time measure variables -static double baseClockTicks = 0.0; // Offset clock ticks for MONOTONIC clock -static unsigned long long int frequency = 0; // Hi-res clock frequency -static double startTime = 0.0; // Start time in milliseconds -static double currentTime = 0.0; // Current time in milliseconds -#endif - -// Physics system configuration -static PhysicsBody bodies[PHYSAC_MAX_BODIES]; // Physics bodies pointers array -static unsigned int physicsBodiesCount = 0; // Physics world current bodies counter -static PhysicsManifold contacts[PHYSAC_MAX_MANIFOLDS]; // Physics bodies pointers array -static unsigned int physicsManifoldsCount = 0; // Physics world current manifolds counter - -static Vector2 gravityForce = { 0.0f, 9.81f }; // Physics world gravity force - -// Utilities variables -static unsigned int usedMemory = 0; // Total allocated dynamic memory - -//---------------------------------------------------------------------------------- -// Module Internal Functions Declaration -//---------------------------------------------------------------------------------- -#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) -// Timming measure functions -static void InitTimerHiRes(void); // Initializes hi-resolution MONOTONIC timer -static unsigned long long int GetClockTicks(void); // Get hi-res MONOTONIC time measure in mseconds -static double GetCurrentTime(void); // Get current time measure in milliseconds -#endif - -static void UpdatePhysicsStep(void); // Update physics step (dynamics, collisions and position corrections) - -static int FindAvailableBodyIndex(); // Finds a valid index for a new physics body initialization -static int FindAvailableManifoldIndex(); // Finds a valid index for a new manifold initialization -static PhysicsVertexData CreateDefaultPolygon(float radius, int sides); // Creates a random polygon shape with max vertex distance from polygon pivot -static PhysicsVertexData CreateRectanglePolygon(Vector2 pos, Vector2 size); // Creates a rectangle polygon shape based on a min and max positions - -static void InitializePhysicsManifolds(PhysicsManifold manifold); // Initializes physics manifolds to solve collisions -static PhysicsManifold CreatePhysicsManifold(PhysicsBody a, PhysicsBody b); // Creates a new physics manifold to solve collision -static void DestroyPhysicsManifold(PhysicsManifold manifold); // Unitializes and destroys a physics manifold - -static void SolvePhysicsManifold(PhysicsManifold manifold); // Solves a created physics manifold between two physics bodies -static void SolveCircleToCircle(PhysicsManifold manifold); // Solves collision between two circle shape physics bodies -static void SolveCircleToPolygon(PhysicsManifold manifold); // Solves collision between a circle to a polygon shape physics bodies -static void SolvePolygonToCircle(PhysicsManifold manifold); // Solves collision between a polygon to a circle shape physics bodies -static void SolvePolygonToPolygon(PhysicsManifold manifold); // Solves collision between two polygons shape physics bodies -static void IntegratePhysicsForces(PhysicsBody body); // Integrates physics forces into velocity -static void IntegratePhysicsVelocity(PhysicsBody body); // Integrates physics velocity into position and forces -static void IntegratePhysicsImpulses(PhysicsManifold manifold); // Integrates physics collisions impulses to solve collisions -static void CorrectPhysicsPositions(PhysicsManifold manifold); // Corrects physics bodies positions based on manifolds collision information -static void FindIncidentFace(Vector2 *v0, Vector2 *v1, PhysicsShape ref, PhysicsShape inc, int index); // Finds two polygon shapes incident face -static float FindAxisLeastPenetration(int *faceIndex, PhysicsShape shapeA, PhysicsShape shapeB); // Finds polygon shapes axis least penetration - -// Math required functions -static Vector2 MathVector2Product(Vector2 vector, float value); // Returns the product of a vector and a value -static float MathVector2CrossProduct(Vector2 v1, Vector2 v2); // Returns the cross product of two vectors -static float MathVector2SqrLen(Vector2 vector); // Returns the len square root of a vector -static float MathVector2DotProduct(Vector2 v1, Vector2 v2); // Returns the dot product of two vectors -static inline float MathVector2SqrDistance(Vector2 v1, Vector2 v2); // Returns the square root of distance between two vectors -static void MathVector2Normalize(Vector2 *vector); // Returns the normalized values of a vector -static Vector2 MathVector2Add(Vector2 v1, Vector2 v2); // Returns the sum of two given vectors -static Vector2 MathVector2Subtract(Vector2 v1, Vector2 v2); // Returns the subtract of two given vectors -static Matrix2x2 MathMatFromRadians(float radians); // Returns a matrix 2x2 from a given radians value -static inline Matrix2x2 MathMatTranspose(Matrix2x2 matrix); // Returns the transpose of a given matrix 2x2 -static inline Vector2 MathMatVector2Product(Matrix2x2 matrix, Vector2 vector); // Returns product between matrix 2x2 and vector -static int MathVector2Clip(Vector2 normal, Vector2 *faceA, Vector2 *faceB, float clip); // Returns clipping value based on a normal and two faces -static Vector2 MathTriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3); // Returns the barycenter of a triangle given by 3 points - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- - -// Initializes physics values, pointers and creates physics loop thread -void InitPhysics(void) -{ -#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) - // Initialize high resolution timer - InitTimerHiRes(); -#endif - - TRACELOG("[PHYSAC] Physics module initialized successfully\n"); -} - -// Sets physics global gravity force -void SetPhysicsGravity(float x, float y) -{ - gravityForce.x = x; - gravityForce.y = y; -} - -// Creates a new circle physics body with generic parameters -PhysicsBody CreatePhysicsBodyCircle(Vector2 pos, float radius, float density) -{ - PhysicsBody body = CreatePhysicsBodyPolygon(pos, radius, PHYSAC_DEFAULT_CIRCLE_VERTICES, density); - return body; -} - -// Creates a new rectangle physics body with generic parameters -PhysicsBody CreatePhysicsBodyRectangle(Vector2 pos, float width, float height, float density) -{ - // NOTE: Make sure body data is initialized to 0 - PhysicsBody body = (PhysicsBody)PHYSAC_CALLOC(sizeof(PhysicsBodyData), 1); - usedMemory += sizeof(PhysicsBodyData); - - int id = FindAvailableBodyIndex(); - if (id != -1) - { - // Initialize new body with generic values - body->id = id; - body->enabled = true; - body->position = pos; - body->shape.type = PHYSICS_POLYGON; - body->shape.body = body; - body->shape.transform = MathMatFromRadians(0.0f); - body->shape.vertexData = CreateRectanglePolygon(pos, CLITERAL(Vector2){ width, height }); - - // Calculate centroid and moment of inertia - Vector2 center = { 0.0f, 0.0f }; - float area = 0.0f; - float inertia = 0.0f; - - for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++) - { - // Triangle vertices, third vertex implied as (0, 0) - Vector2 p1 = body->shape.vertexData.positions[i]; - unsigned int nextIndex = (((i + 1) < body->shape.vertexData.vertexCount) ? (i + 1) : 0); - Vector2 p2 = body->shape.vertexData.positions[nextIndex]; - - float D = MathVector2CrossProduct(p1, p2); - float triangleArea = D/2; - - area += triangleArea; - - // Use area to weight the centroid average, not just vertex position - center.x += triangleArea*PHYSAC_K*(p1.x + p2.x); - center.y += triangleArea*PHYSAC_K*(p1.y + p2.y); - - float intx2 = p1.x*p1.x + p2.x*p1.x + p2.x*p2.x; - float inty2 = p1.y*p1.y + p2.y*p1.y + p2.y*p2.y; - inertia += (0.25f*PHYSAC_K*D)*(intx2 + inty2); - } - - center.x *= 1.0f/area; - center.y *= 1.0f/area; - - // Translate vertices to centroid (make the centroid (0, 0) for the polygon in model space) - // Note: this is not really necessary - for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++) - { - body->shape.vertexData.positions[i].x -= center.x; - body->shape.vertexData.positions[i].y -= center.y; - } - - body->mass = density*area; - body->inverseMass = ((body->mass != 0.0f) ? 1.0f/body->mass : 0.0f); - body->inertia = density*inertia; - body->inverseInertia = ((body->inertia != 0.0f) ? 1.0f/body->inertia : 0.0f); - body->staticFriction = 0.4f; - body->dynamicFriction = 0.2f; - body->restitution = 0.0f; - body->useGravity = true; - body->isGrounded = false; - body->freezeOrient = false; - - // Add new body to bodies pointers array and update bodies count - bodies[physicsBodiesCount] = body; - physicsBodiesCount++; - - TRACELOG("[PHYSAC] Physic body created successfully (id: %i)\n", body->id); - } - else TRACELOG("[PHYSAC] Physic body could not be created, PHYSAC_MAX_BODIES reached\n"); - - return body; -} - -// Creates a new polygon physics body with generic parameters -PhysicsBody CreatePhysicsBodyPolygon(Vector2 pos, float radius, int sides, float density) -{ - PhysicsBody body = (PhysicsBody)PHYSAC_MALLOC(sizeof(PhysicsBodyData)); - usedMemory += sizeof(PhysicsBodyData); - - int id = FindAvailableBodyIndex(); - if (id != -1) - { - // Initialize new body with generic values - body->id = id; - body->enabled = true; - body->position = pos; - body->velocity = PHYSAC_VECTOR_ZERO; - body->force = PHYSAC_VECTOR_ZERO; - body->angularVelocity = 0.0f; - body->torque = 0.0f; - body->orient = 0.0f; - body->shape.type = PHYSICS_POLYGON; - body->shape.body = body; - body->shape.transform = MathMatFromRadians(0.0f); - body->shape.vertexData = CreateDefaultPolygon(radius, sides); - - // Calculate centroid and moment of inertia - Vector2 center = { 0.0f, 0.0f }; - float area = 0.0f; - float inertia = 0.0f; - - for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++) - { - // Triangle vertices, third vertex implied as (0, 0) - Vector2 position1 = body->shape.vertexData.positions[i]; - unsigned int nextIndex = (((i + 1) < body->shape.vertexData.vertexCount) ? (i + 1) : 0); - Vector2 position2 = body->shape.vertexData.positions[nextIndex]; - - float cross = MathVector2CrossProduct(position1, position2); - float triangleArea = cross/2; - - area += triangleArea; - - // Use area to weight the centroid average, not just vertex position - center.x += triangleArea*PHYSAC_K*(position1.x + position2.x); - center.y += triangleArea*PHYSAC_K*(position1.y + position2.y); - - float intx2 = position1.x*position1.x + position2.x*position1.x + position2.x*position2.x; - float inty2 = position1.y*position1.y + position2.y*position1.y + position2.y*position2.y; - inertia += (0.25f*PHYSAC_K*cross)*(intx2 + inty2); - } - - center.x *= 1.0f/area; - center.y *= 1.0f/area; - - // Translate vertices to centroid (make the centroid (0, 0) for the polygon in model space) - // Note: this is not really necessary - for (unsigned int i = 0; i < body->shape.vertexData.vertexCount; i++) - { - body->shape.vertexData.positions[i].x -= center.x; - body->shape.vertexData.positions[i].y -= center.y; - } - - body->mass = density*area; - body->inverseMass = ((body->mass != 0.0f) ? 1.0f/body->mass : 0.0f); - body->inertia = density*inertia; - body->inverseInertia = ((body->inertia != 0.0f) ? 1.0f/body->inertia : 0.0f); - body->staticFriction = 0.4f; - body->dynamicFriction = 0.2f; - body->restitution = 0.0f; - body->useGravity = true; - body->isGrounded = false; - body->freezeOrient = false; - - // Add new body to bodies pointers array and update bodies count - bodies[physicsBodiesCount] = body; - physicsBodiesCount++; - - TRACELOG("[PHYSAC] Physic body created successfully (id: %i)\n", body->id); - } - else TRACELOG("[PHYSAC] Physics body could not be created, PHYSAC_MAX_BODIES reached\n"); - - return body; -} - -// Adds a force to a physics body -void PhysicsAddForce(PhysicsBody body, Vector2 force) -{ - if (body != NULL) body->force = MathVector2Add(body->force, force); -} - -// Adds an angular force to a physics body -void PhysicsAddTorque(PhysicsBody body, float amount) -{ - if (body != NULL) body->torque += amount; -} - -// Shatters a polygon shape physics body to little physics bodies with explosion force -void PhysicsShatter(PhysicsBody body, Vector2 position, float force) -{ - if (body != NULL) - { - if (body->shape.type == PHYSICS_POLYGON) - { - PhysicsVertexData vertexData = body->shape.vertexData; - bool collision = false; - - for (unsigned int i = 0; i < vertexData.vertexCount; i++) - { - Vector2 positionA = body->position; - Vector2 positionB = MathMatVector2Product(body->shape.transform, MathVector2Add(body->position, vertexData.positions[i])); - unsigned int nextIndex = (((i + 1) < vertexData.vertexCount) ? (i + 1) : 0); - Vector2 positionC = MathMatVector2Product(body->shape.transform, MathVector2Add(body->position, vertexData.positions[nextIndex])); - - // Check collision between each triangle - float alpha = ((positionB.y - positionC.y)*(position.x - positionC.x) + (positionC.x - positionB.x)*(position.y - positionC.y))/ - ((positionB.y - positionC.y)*(positionA.x - positionC.x) + (positionC.x - positionB.x)*(positionA.y - positionC.y)); - - float beta = ((positionC.y - positionA.y)*(position.x - positionC.x) + (positionA.x - positionC.x)*(position.y - positionC.y))/ - ((positionB.y - positionC.y)*(positionA.x - positionC.x) + (positionC.x - positionB.x)*(positionA.y - positionC.y)); - - float gamma = 1.0f - alpha - beta; - - if ((alpha > 0.0f) && (beta > 0.0f) & (gamma > 0.0f)) - { - collision = true; - break; - } - } - - if (collision) - { - int count = vertexData.vertexCount; - Vector2 bodyPos = body->position; - Vector2 *vertices = (Vector2 *)PHYSAC_MALLOC(sizeof(Vector2)*count); - Matrix2x2 trans = body->shape.transform; - for (int i = 0; i < count; i++) vertices[i] = vertexData.positions[i]; - - // Destroy shattered physics body - DestroyPhysicsBody(body); - - for (int i = 0; i < count; i++) - { - int nextIndex = (((i + 1) < count) ? (i + 1) : 0); - Vector2 center = MathTriangleBarycenter(vertices[i], vertices[nextIndex], PHYSAC_VECTOR_ZERO); - center = MathVector2Add(bodyPos, center); - Vector2 offset = MathVector2Subtract(center, bodyPos); - - PhysicsBody body = CreatePhysicsBodyPolygon(center, 10, 3, 10); // Create polygon physics body with relevant values - - PhysicsVertexData vertexData = { 0 }; - vertexData.vertexCount = 3; - - vertexData.positions[0] = MathVector2Subtract(vertices[i], offset); - vertexData.positions[1] = MathVector2Subtract(vertices[nextIndex], offset); - vertexData.positions[2] = MathVector2Subtract(position, center); - - // Separate vertices to avoid unnecessary physics collisions - vertexData.positions[0].x *= 0.95f; - vertexData.positions[0].y *= 0.95f; - vertexData.positions[1].x *= 0.95f; - vertexData.positions[1].y *= 0.95f; - vertexData.positions[2].x *= 0.95f; - vertexData.positions[2].y *= 0.95f; - - // Calculate polygon faces normals - for (unsigned int j = 0; j < vertexData.vertexCount; j++) - { - unsigned int nextVertex = (((j + 1) < vertexData.vertexCount) ? (j + 1) : 0); - Vector2 face = MathVector2Subtract(vertexData.positions[nextVertex], vertexData.positions[j]); - - vertexData.normals[j] = CLITERAL(Vector2){ face.y, -face.x }; - MathVector2Normalize(&vertexData.normals[j]); - } - - // Apply computed vertex data to new physics body shape - body->shape.vertexData = vertexData; - body->shape.transform = trans; - - // Calculate centroid and moment of inertia - center = PHYSAC_VECTOR_ZERO; - float area = 0.0f; - float inertia = 0.0f; - - for (unsigned int j = 0; j < body->shape.vertexData.vertexCount; j++) - { - // Triangle vertices, third vertex implied as (0, 0) - Vector2 p1 = body->shape.vertexData.positions[j]; - unsigned int nextVertex = (((j + 1) < body->shape.vertexData.vertexCount) ? (j + 1) : 0); - Vector2 p2 = body->shape.vertexData.positions[nextVertex]; - - float D = MathVector2CrossProduct(p1, p2); - float triangleArea = D/2; - - area += triangleArea; - - // Use area to weight the centroid average, not just vertex position - center.x += triangleArea*PHYSAC_K*(p1.x + p2.x); - center.y += triangleArea*PHYSAC_K*(p1.y + p2.y); - - float intx2 = p1.x*p1.x + p2.x*p1.x + p2.x*p2.x; - float inty2 = p1.y*p1.y + p2.y*p1.y + p2.y*p2.y; - inertia += (0.25f*PHYSAC_K*D)*(intx2 + inty2); - } - - center.x *= 1.0f/area; - center.y *= 1.0f/area; - - body->mass = area; - body->inverseMass = ((body->mass != 0.0f) ? 1.0f/body->mass : 0.0f); - body->inertia = inertia; - body->inverseInertia = ((body->inertia != 0.0f) ? 1.0f/body->inertia : 0.0f); - - // Calculate explosion force direction - Vector2 pointA = body->position; - Vector2 pointB = MathVector2Subtract(vertexData.positions[1], vertexData.positions[0]); - pointB.x /= 2.0f; - pointB.y /= 2.0f; - Vector2 forceDirection = MathVector2Subtract(MathVector2Add(pointA, MathVector2Add(vertexData.positions[0], pointB)), body->position); - MathVector2Normalize(&forceDirection); - forceDirection.x *= force; - forceDirection.y *= force; - - // Apply force to new physics body - PhysicsAddForce(body, forceDirection); - } - - PHYSAC_FREE(vertices); - } - } - } - else TRACELOG("[PHYSAC] WARNING: PhysicsShatter: NULL physic body\n"); -} - -// Returns the current amount of created physics bodies -int GetPhysicsBodiesCount(void) -{ - return physicsBodiesCount; -} - -// Returns a physics body of the bodies pool at a specific index -PhysicsBody GetPhysicsBody(int index) -{ - PhysicsBody body = NULL; - - if (index < (int)physicsBodiesCount) - { - body = bodies[index]; - - if (body == NULL) TRACELOG("[PHYSAC] WARNING: GetPhysicsBody: NULL physic body\n"); - } - else TRACELOG("[PHYSAC] WARNING: Physic body index is out of bounds\n"); - - return body; -} - -// Returns the physics body shape type (PHYSICS_CIRCLE or PHYSICS_POLYGON) -int GetPhysicsShapeType(int index) -{ - int result = -1; - - if (index < (int)physicsBodiesCount) - { - PhysicsBody body = bodies[index]; - - if (body != NULL) result = body->shape.type; - else TRACELOG("[PHYSAC] WARNING: GetPhysicsShapeType: NULL physic body\n"); - } - else TRACELOG("[PHYSAC] WARNING: Physic body index is out of bounds\n"); - - return result; -} - -// Returns the amount of vertices of a physics body shape -int GetPhysicsShapeVerticesCount(int index) -{ - int result = 0; - - if (index < (int)physicsBodiesCount) - { - PhysicsBody body = bodies[index]; - - if (body != NULL) - { - switch (body->shape.type) - { - case PHYSICS_CIRCLE: result = PHYSAC_DEFAULT_CIRCLE_VERTICES; break; - case PHYSICS_POLYGON: result = body->shape.vertexData.vertexCount; break; - default: break; - } - } - else TRACELOG("[PHYSAC] WARNING: GetPhysicsShapeVerticesCount: NULL physic body\n"); - } - else TRACELOG("[PHYSAC] WARNING: Physic body index is out of bounds\n"); - - return result; -} - -// Returns transformed position of a body shape (body position + vertex transformed position) -Vector2 GetPhysicsShapeVertex(PhysicsBody body, int vertex) -{ - Vector2 position = { 0.0f, 0.0f }; - - if (body != NULL) - { - switch (body->shape.type) - { - case PHYSICS_CIRCLE: - { - position.x = body->position.x + cosf(360.0f/PHYSAC_DEFAULT_CIRCLE_VERTICES*vertex*PHYSAC_DEG2RAD)*body->shape.radius; - position.y = body->position.y + sinf(360.0f/PHYSAC_DEFAULT_CIRCLE_VERTICES*vertex*PHYSAC_DEG2RAD)*body->shape.radius; - } break; - case PHYSICS_POLYGON: - { - PhysicsVertexData vertexData = body->shape.vertexData; - position = MathVector2Add(body->position, MathMatVector2Product(body->shape.transform, vertexData.positions[vertex])); - } break; - default: break; - } - } - else TRACELOG("[PHYSAC] WARNING: GetPhysicsShapeVertex: NULL physic body\n"); - - return position; -} - -// Sets physics body shape transform based on radians parameter -void SetPhysicsBodyRotation(PhysicsBody body, float radians) -{ - if (body != NULL) - { - body->orient = radians; - - if (body->shape.type == PHYSICS_POLYGON) body->shape.transform = MathMatFromRadians(radians); - } -} - -// Unitializes and destroys a physics body -void DestroyPhysicsBody(PhysicsBody body) -{ - if (body != NULL) - { - int id = body->id; - int index = -1; - - for (unsigned int i = 0; i < physicsBodiesCount; i++) - { - if (bodies[i]->id == id) - { - index = i; - break; - } - } - - if (index == -1) - { - TRACELOG("[PHYSAC] WARNING: Requested body (id: %i) can not be found\n", id); - return; // Prevent access to index -1 - } - - // Free body allocated memory - PHYSAC_FREE(body); - usedMemory -= sizeof(PhysicsBodyData); - bodies[index] = NULL; - - // Reorder physics bodies pointers array and its catched index - for (unsigned int i = index; i < physicsBodiesCount; i++) - { - if ((i + 1) < physicsBodiesCount) bodies[i] = bodies[i + 1]; - } - - // Update physics bodies count - physicsBodiesCount--; - - TRACELOG("[PHYSAC] Physic body destroyed successfully (id: %i)\n", id); - } - else TRACELOG("[PHYSAC] WARNING: DestroyPhysicsBody: NULL physic body\n"); -} - -// Destroys created physics bodies and manifolds and resets global values -void ResetPhysics(void) -{ - if (physicsBodiesCount > 0) - { - // Unitialize physics bodies dynamic memory allocations - for (int i = physicsBodiesCount - 1; i >= 0; i--) - { - PhysicsBody body = bodies[i]; - - if (body != NULL) - { - PHYSAC_FREE(body); - bodies[i] = NULL; - usedMemory -= sizeof(PhysicsBodyData); - } - } - - physicsBodiesCount = 0; - } - - if (physicsManifoldsCount > 0) - { - // Unitialize physics manifolds dynamic memory allocations - for (int i = physicsManifoldsCount - 1; i >= 0; i--) - { - PhysicsManifold manifold = contacts[i]; - - if (manifold != NULL) - { - PHYSAC_FREE(manifold); - contacts[i] = NULL; - usedMemory -= sizeof(PhysicsManifoldData); - } - } - - physicsManifoldsCount = 0; - } - - TRACELOG("[PHYSAC] Physics module reseted successfully\n"); -} - -// Unitializes physics pointers and exits physics loop thread -void ClosePhysics(void) -{ - // Unitialize physics manifolds dynamic memory allocations - if (physicsManifoldsCount > 0) - { - for (int i = physicsManifoldsCount - 1; i >= 0; i--) DestroyPhysicsManifold(contacts[i]); - } - - // Unitialize physics bodies dynamic memory allocations - if (physicsBodiesCount > 0) - { - for (int i = physicsBodiesCount - 1; i >= 0; i--) DestroyPhysicsBody(bodies[i]); - } - - // Trace log info - if ((physicsBodiesCount > 0) || (usedMemory != 0)) - { - TRACELOG("[PHYSAC] WARNING: Physics module closed with unallocated bodies (BODIES: %i, MEMORY: %i bytes)\n", physicsBodiesCount, usedMemory); - } - else if ((physicsManifoldsCount > 0) || (usedMemory != 0)) - { - TRACELOG("[PHYSAC] WARNING: Pysics module closed with unallocated manifolds (MANIFOLDS: %i, MEMORY: %i bytes)\n", physicsManifoldsCount, usedMemory); - } - else TRACELOG("[PHYSAC] Physics module closed successfully\n"); -} - -// Update physics system -// Physics steps are launched at a fixed time step if enabled -void UpdatePhysics(void) -{ -#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) - static double deltaTimeAccumulator = 0.0; - - // Calculate current time (ms) - currentTime = GetCurrentTime(); - - // Calculate current delta time (ms) - const double delta = currentTime - startTime; - - // Store the time elapsed since the last frame began - deltaTimeAccumulator += delta; - - // Fixed time stepping loop - while (deltaTimeAccumulator >= deltaTime) - { - UpdatePhysicsStep(); - deltaTimeAccumulator -= deltaTime; - } - - // Record the starting of this frame - startTime = currentTime; -#else - UpdatePhysicsStep(); -#endif -} - -void SetPhysicsTimeStep(double delta) -{ - deltaTime = delta; -} - -//---------------------------------------------------------------------------------- -// Module Internal Functions Definition -//---------------------------------------------------------------------------------- -#if !defined(PHYSAC_AVOID_TIMMING_SYSTEM) -// Initializes hi-resolution MONOTONIC timer -static void InitTimerHiRes(void) -{ -#if defined(_WIN32) - QueryPerformanceFrequency((unsigned long long int *) &frequency); -#endif - -#if defined(__EMSCRIPTEN__) || defined(__linux__) - struct timespec now; - if (clock_gettime(CLOCK_MONOTONIC, &now) == 0) frequency = 1000000000; -#endif - -#if defined(__APPLE__) - mach_timebase_info_data_t timebase; - mach_timebase_info(&timebase); - frequency = (timebase.denom*1e9)/timebase.numer; -#endif - - baseClockTicks = (double)GetClockTicks(); // Get MONOTONIC clock time offset - startTime = GetCurrentTime(); // Get current time in milliseconds -} - -// Get hi-res MONOTONIC time measure in clock ticks -static unsigned long long int GetClockTicks(void) -{ - unsigned long long int value = 0; - -#if defined(_WIN32) - QueryPerformanceCounter((unsigned long long int *) &value); -#endif - -#if defined(__linux__) - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - value = (unsigned long long int)now.tv_sec*(unsigned long long int)1000000000 + (unsigned long long int)now.tv_nsec; -#endif - -#if defined(__APPLE__) - value = mach_absolute_time(); -#endif - - return value; -} - -// Get current time in milliseconds -static double GetCurrentTime(void) -{ - return (double)(GetClockTicks() - baseClockTicks)/frequency*1000; -} -#endif // !PHYSAC_AVOID_TIMMING_SYSTEM - -// Update physics step (dynamics, collisions and position corrections) -static void UpdatePhysicsStep(void) -{ - // Clear previous generated collisions information - for (int i = (int)physicsManifoldsCount - 1; i >= 0; i--) - { - PhysicsManifold manifold = contacts[i]; - if (manifold != NULL) DestroyPhysicsManifold(manifold); - } - - // Reset physics bodies grounded state - for (unsigned int i = 0; i < physicsBodiesCount; i++) - { - PhysicsBody body = bodies[i]; - body->isGrounded = false; - } - - // Generate new collision information - for (unsigned int i = 0; i < physicsBodiesCount; i++) - { - PhysicsBody bodyA = bodies[i]; - - if (bodyA != NULL) - { - for (unsigned int j = i + 1; j < physicsBodiesCount; j++) - { - PhysicsBody bodyB = bodies[j]; - - if (bodyB != NULL) - { - if ((bodyA->inverseMass == 0) && (bodyB->inverseMass == 0)) continue; - - PhysicsManifold manifold = CreatePhysicsManifold(bodyA, bodyB); - SolvePhysicsManifold(manifold); - - if (manifold->contactsCount > 0) - { - // Create a new manifold with same information as previously solved manifold and add it to the manifolds pool last slot - PhysicsManifold manifold = CreatePhysicsManifold(bodyA, bodyB); - manifold->penetration = manifold->penetration; - manifold->normal = manifold->normal; - manifold->contacts[0] = manifold->contacts[0]; - manifold->contacts[1] = manifold->contacts[1]; - manifold->contactsCount = manifold->contactsCount; - manifold->restitution = manifold->restitution; - manifold->dynamicFriction = manifold->dynamicFriction; - manifold->staticFriction = manifold->staticFriction; - } - } - } - } - } - - // Integrate forces to physics bodies - for (unsigned int i = 0; i < physicsBodiesCount; i++) - { - PhysicsBody body = bodies[i]; - if (body != NULL) IntegratePhysicsForces(body); - } - - // Initialize physics manifolds to solve collisions - for (unsigned int i = 0; i < physicsManifoldsCount; i++) - { - PhysicsManifold manifold = contacts[i]; - if (manifold != NULL) InitializePhysicsManifolds(manifold); - } - - // Integrate physics collisions impulses to solve collisions - for (unsigned int i = 0; i < PHYSAC_COLLISION_ITERATIONS; i++) - { - for (unsigned int j = 0; j < physicsManifoldsCount; j++) - { - PhysicsManifold manifold = contacts[i]; - if (manifold != NULL) IntegratePhysicsImpulses(manifold); - } - } - - // Integrate velocity to physics bodies - for (unsigned int i = 0; i < physicsBodiesCount; i++) - { - PhysicsBody body = bodies[i]; - if (body != NULL) IntegratePhysicsVelocity(body); - } - - // Correct physics bodies positions based on manifolds collision information - for (unsigned int i = 0; i < physicsManifoldsCount; i++) - { - PhysicsManifold manifold = contacts[i]; - if (manifold != NULL) CorrectPhysicsPositions(manifold); - } - - // Clear physics bodies forces - for (unsigned int i = 0; i < physicsBodiesCount; i++) - { - PhysicsBody body = bodies[i]; - if (body != NULL) - { - body->force = PHYSAC_VECTOR_ZERO; - body->torque = 0.0f; - } - } -} - -// Finds a valid index for a new physics body initialization -static int FindAvailableBodyIndex() -{ - int index = -1; - for (int i = 0; i < PHYSAC_MAX_BODIES; i++) - { - int currentId = i; - - // Check if current id already exist in other physics body - for (unsigned int k = 0; k < physicsBodiesCount; k++) - { - if (bodies[k]->id == currentId) - { - currentId++; - break; - } - } - - // If it is not used, use it as new physics body id - if (currentId == (int)i) - { - index = (int)i; - break; - } - } - - return index; -} - -// Creates a default polygon shape with max vertex distance from polygon pivot -static PhysicsVertexData CreateDefaultPolygon(float radius, int sides) -{ - PhysicsVertexData data = { 0 }; - data.vertexCount = sides; - - // Calculate polygon vertices positions - for (unsigned int i = 0; i < data.vertexCount; i++) - { - data.positions[i].x = (float)cosf(360.0f/sides*i*PHYSAC_DEG2RAD)*radius; - data.positions[i].y = (float)sinf(360.0f/sides*i*PHYSAC_DEG2RAD)*radius; - } - - // Calculate polygon faces normals - for (int i = 0; i < (int)data.vertexCount; i++) - { - int nextIndex = (((i + 1) < sides) ? (i + 1) : 0); - Vector2 face = MathVector2Subtract(data.positions[nextIndex], data.positions[i]); - - data.normals[i] = CLITERAL(Vector2){ face.y, -face.x }; - MathVector2Normalize(&data.normals[i]); - } - - return data; -} - -// Creates a rectangle polygon shape based on a min and max positions -static PhysicsVertexData CreateRectanglePolygon(Vector2 pos, Vector2 size) -{ - PhysicsVertexData data = { 0 }; - data.vertexCount = 4; - - // Calculate polygon vertices positions - data.positions[0] = CLITERAL(Vector2){ pos.x + size.x/2, pos.y - size.y/2 }; - data.positions[1] = CLITERAL(Vector2){ pos.x + size.x/2, pos.y + size.y/2 }; - data.positions[2] = CLITERAL(Vector2){ pos.x - size.x/2, pos.y + size.y/2 }; - data.positions[3] = CLITERAL(Vector2){ pos.x - size.x/2, pos.y - size.y/2 }; - - // Calculate polygon faces normals - for (unsigned int i = 0; i < data.vertexCount; i++) - { - int nextIndex = (((i + 1) < data.vertexCount) ? (i + 1) : 0); - Vector2 face = MathVector2Subtract(data.positions[nextIndex], data.positions[i]); - - data.normals[i] = CLITERAL(Vector2){ face.y, -face.x }; - MathVector2Normalize(&data.normals[i]); - } - - return data; -} - -// Finds a valid index for a new manifold initialization -static int FindAvailableManifoldIndex() -{ - int index = -1; - for (int i = 0; i < PHYSAC_MAX_MANIFOLDS; i++) - { - int currentId = i; - - // Check if current id already exist in other physics body - for (unsigned int k = 0; k < physicsManifoldsCount; k++) - { - if (contacts[k]->id == currentId) - { - currentId++; - break; - } - } - - // If it is not used, use it as new physics body id - if (currentId == i) - { - index = i; - break; - } - } - - return index; -} - -// Creates a new physics manifold to solve collision -static PhysicsManifold CreatePhysicsManifold(PhysicsBody a, PhysicsBody b) -{ - PhysicsManifold manifold = (PhysicsManifold)PHYSAC_MALLOC(sizeof(PhysicsManifoldData)); - usedMemory += sizeof(PhysicsManifoldData); - - int id = FindAvailableManifoldIndex(); - if (id != -1) - { - // Initialize new manifold with generic values - manifold->id = id; - manifold->bodyA = a; - manifold->bodyB = b; - manifold->penetration = 0; - manifold->normal = PHYSAC_VECTOR_ZERO; - manifold->contacts[0] = PHYSAC_VECTOR_ZERO; - manifold->contacts[1] = PHYSAC_VECTOR_ZERO; - manifold->contactsCount = 0; - manifold->restitution = 0.0f; - manifold->dynamicFriction = 0.0f; - manifold->staticFriction = 0.0f; - - // Add new body to bodies pointers array and update bodies count - contacts[physicsManifoldsCount] = manifold; - physicsManifoldsCount++; - } - else TRACELOG("[PHYSAC] Physic manifold could not be created, PHYSAC_MAX_MANIFOLDS reached\n"); - - return manifold; -} - -// Unitializes and destroys a physics manifold -static void DestroyPhysicsManifold(PhysicsManifold manifold) -{ - if (manifold != NULL) - { - int id = manifold->id; - int index = -1; - - for (unsigned int i = 0; i < physicsManifoldsCount; i++) - { - if (contacts[i]->id == id) - { - index = i; - break; - } - } - - if (index == -1) return; // Prevent access to index -1 - - // Free manifold allocated memory - PHYSAC_FREE(manifold); - usedMemory -= sizeof(PhysicsManifoldData); - contacts[index] = NULL; - - // Reorder physics manifolds pointers array and its catched index - for (unsigned int i = index; i < physicsManifoldsCount; i++) - { - if ((i + 1) < physicsManifoldsCount) contacts[i] = contacts[i + 1]; - } - - // Update physics manifolds count - physicsManifoldsCount--; - } - else TRACELOG("[PHYSAC] WARNING: DestroyPhysicsManifold: NULL physic manifold\n"); -} - -// Solves a created physics manifold between two physics bodies -static void SolvePhysicsManifold(PhysicsManifold manifold) -{ - switch (manifold->bodyA->shape.type) - { - case PHYSICS_CIRCLE: - { - switch (manifold->bodyB->shape.type) - { - case PHYSICS_CIRCLE: SolveCircleToCircle(manifold); break; - case PHYSICS_POLYGON: SolveCircleToPolygon(manifold); break; - default: break; - } - } break; - case PHYSICS_POLYGON: - { - switch (manifold->bodyB->shape.type) - { - case PHYSICS_CIRCLE: SolvePolygonToCircle(manifold); break; - case PHYSICS_POLYGON: SolvePolygonToPolygon(manifold); break; - default: break; - } - } break; - default: break; - } - - // Update physics body grounded state if normal direction is down and grounded state is not set yet in previous manifolds - if (!manifold->bodyB->isGrounded) manifold->bodyB->isGrounded = (manifold->normal.y < 0); -} - -// Solves collision between two circle shape physics bodies -static void SolveCircleToCircle(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - // Calculate translational vector, which is normal - Vector2 normal = MathVector2Subtract(bodyB->position, bodyA->position); - - float distSqr = MathVector2SqrLen(normal); - float radius = bodyA->shape.radius + bodyB->shape.radius; - - // Check if circles are not in contact - if (distSqr >= radius*radius) - { - manifold->contactsCount = 0; - return; - } - - float distance = sqrtf(distSqr); - manifold->contactsCount = 1; - - if (distance == 0.0f) - { - manifold->penetration = bodyA->shape.radius; - manifold->normal = CLITERAL(Vector2){ 1.0f, 0.0f }; - manifold->contacts[0] = bodyA->position; - } - else - { - manifold->penetration = radius - distance; - manifold->normal = CLITERAL(Vector2){ normal.x/distance, normal.y/distance }; // Faster than using MathVector2Normalize() due to sqrt is already performed - manifold->contacts[0] = CLITERAL(Vector2){ manifold->normal.x*bodyA->shape.radius + bodyA->position.x, manifold->normal.y*bodyA->shape.radius + bodyA->position.y }; - } - - // Update physics body grounded state if normal direction is down - if (!bodyA->isGrounded) bodyA->isGrounded = (manifold->normal.y < 0); -} - -// Solves collision between a circle to a polygon shape physics bodies -static void SolveCircleToPolygon(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - manifold->contactsCount = 0; - - // Transform circle center to polygon transform space - Vector2 center = bodyA->position; - center = MathMatVector2Product(MathMatTranspose(bodyB->shape.transform), MathVector2Subtract(center, bodyB->position)); - - // Find edge with minimum penetration - // It is the same concept as using support points in SolvePolygonToPolygon - float separation = -PHYSAC_FLT_MAX; - int faceNormal = 0; - PhysicsVertexData vertexData = bodyB->shape.vertexData; - - for (unsigned int i = 0; i < vertexData.vertexCount; i++) - { - float currentSeparation = MathVector2DotProduct(vertexData.normals[i], MathVector2Subtract(center, vertexData.positions[i])); - - if (currentSeparation > bodyA->shape.radius) return; - - if (currentSeparation > separation) - { - separation = currentSeparation; - faceNormal = i; - } - } - - // Grab face's vertices - Vector2 v1 = vertexData.positions[faceNormal]; - int nextIndex = (((faceNormal + 1) < (int)vertexData.vertexCount) ? (faceNormal + 1) : 0); - Vector2 v2 = vertexData.positions[nextIndex]; - - // Check to see if center is within polygon - if (separation < PHYSAC_EPSILON) - { - manifold->contactsCount = 1; - Vector2 normal = MathMatVector2Product(bodyB->shape.transform, vertexData.normals[faceNormal]); - manifold->normal = CLITERAL(Vector2){ -normal.x, -normal.y }; - manifold->contacts[0] = CLITERAL(Vector2){ manifold->normal.x*bodyA->shape.radius + bodyA->position.x, manifold->normal.y*bodyA->shape.radius + bodyA->position.y }; - manifold->penetration = bodyA->shape.radius; - return; - } - - // Determine which voronoi region of the edge center of circle lies within - float dot1 = MathVector2DotProduct(MathVector2Subtract(center, v1), MathVector2Subtract(v2, v1)); - float dot2 = MathVector2DotProduct(MathVector2Subtract(center, v2), MathVector2Subtract(v1, v2)); - manifold->penetration = bodyA->shape.radius - separation; - - if (dot1 <= 0.0f) // Closest to v1 - { - if (MathVector2SqrDistance(center, v1) > bodyA->shape.radius*bodyA->shape.radius) return; - - manifold->contactsCount = 1; - Vector2 normal = MathVector2Subtract(v1, center); - normal = MathMatVector2Product(bodyB->shape.transform, normal); - MathVector2Normalize(&normal); - manifold->normal = normal; - v1 = MathMatVector2Product(bodyB->shape.transform, v1); - v1 = MathVector2Add(v1, bodyB->position); - manifold->contacts[0] = v1; - } - else if (dot2 <= 0.0f) // Closest to v2 - { - if (MathVector2SqrDistance(center, v2) > bodyA->shape.radius*bodyA->shape.radius) return; - - manifold->contactsCount = 1; - Vector2 normal = MathVector2Subtract(v2, center); - v2 = MathMatVector2Product(bodyB->shape.transform, v2); - v2 = MathVector2Add(v2, bodyB->position); - manifold->contacts[0] = v2; - normal = MathMatVector2Product(bodyB->shape.transform, normal); - MathVector2Normalize(&normal); - manifold->normal = normal; - } - else // Closest to face - { - Vector2 normal = vertexData.normals[faceNormal]; - - if (MathVector2DotProduct(MathVector2Subtract(center, v1), normal) > bodyA->shape.radius) return; - - normal = MathMatVector2Product(bodyB->shape.transform, normal); - manifold->normal = CLITERAL(Vector2){ -normal.x, -normal.y }; - manifold->contacts[0] = CLITERAL(Vector2){ manifold->normal.x*bodyA->shape.radius + bodyA->position.x, manifold->normal.y*bodyA->shape.radius + bodyA->position.y }; - manifold->contactsCount = 1; - } -} - -// Solves collision between a polygon to a circle shape physics bodies -static void SolvePolygonToCircle(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - manifold->bodyA = bodyB; - manifold->bodyB = bodyA; - SolveCircleToPolygon(manifold); - - manifold->normal.x *= -1.0f; - manifold->normal.y *= -1.0f; -} - -// Solves collision between two polygons shape physics bodies -static void SolvePolygonToPolygon(PhysicsManifold manifold) -{ - if ((manifold->bodyA == NULL) || (manifold->bodyB == NULL)) return; - - PhysicsShape bodyA = manifold->bodyA->shape; - PhysicsShape bodyB = manifold->bodyB->shape; - manifold->contactsCount = 0; - - // Check for separating axis with A shape's face planes - int faceA = 0; - float penetrationA = FindAxisLeastPenetration(&faceA, bodyA, bodyB); - if (penetrationA >= 0.0f) return; - - // Check for separating axis with B shape's face planes - int faceB = 0; - float penetrationB = FindAxisLeastPenetration(&faceB, bodyB, bodyA); - if (penetrationB >= 0.0f) return; - - int referenceIndex = 0; - bool flip = false; // Always point from A shape to B shape - - PhysicsShape refPoly; // Reference - PhysicsShape incPoly; // Incident - - // Determine which shape contains reference face - // Checking bias range for penetration - if (penetrationA >= (penetrationB*0.95f + penetrationA*0.01f)) - { - refPoly = bodyA; - incPoly = bodyB; - referenceIndex = faceA; - } - else - { - refPoly = bodyB; - incPoly = bodyA; - referenceIndex = faceB; - flip = true; - } - - // World space incident face - Vector2 incidentFace[2]; - FindIncidentFace(&incidentFace[0], &incidentFace[1], refPoly, incPoly, referenceIndex); - - // Setup reference face vertices - PhysicsVertexData refData = refPoly.vertexData; - Vector2 v1 = refData.positions[referenceIndex]; - referenceIndex = (((referenceIndex + 1) < (int)refData.vertexCount) ? (referenceIndex + 1) : 0); - Vector2 v2 = refData.positions[referenceIndex]; - - // Transform vertices to world space - v1 = MathMatVector2Product(refPoly.transform, v1); - v1 = MathVector2Add(v1, refPoly.body->position); - v2 = MathMatVector2Product(refPoly.transform, v2); - v2 = MathVector2Add(v2, refPoly.body->position); - - // Calculate reference face side normal in world space - Vector2 sidePlaneNormal = MathVector2Subtract(v2, v1); - MathVector2Normalize(&sidePlaneNormal); - - // Orthogonalize - Vector2 refFaceNormal = { sidePlaneNormal.y, -sidePlaneNormal.x }; - float refC = MathVector2DotProduct(refFaceNormal, v1); - float negSide = MathVector2DotProduct(sidePlaneNormal, v1)*-1; - float posSide = MathVector2DotProduct(sidePlaneNormal, v2); - - // MathVector2Clip incident face to reference face side planes (due to floating point error, possible to not have required points - if (MathVector2Clip(CLITERAL(Vector2){ -sidePlaneNormal.x, -sidePlaneNormal.y }, &incidentFace[0], &incidentFace[1], negSide) < 2) return; - if (MathVector2Clip(sidePlaneNormal, &incidentFace[0], &incidentFace[1], posSide) < 2) return; - - // Flip normal if required - manifold->normal = (flip ? CLITERAL(Vector2){ -refFaceNormal.x, -refFaceNormal.y } : refFaceNormal); - - // Keep points behind reference face - int currentPoint = 0; // MathVector2Clipped points behind reference face - float separation = MathVector2DotProduct(refFaceNormal, incidentFace[0]) - refC; - if (separation <= 0.0f) - { - manifold->contacts[currentPoint] = incidentFace[0]; - manifold->penetration = -separation; - currentPoint++; - } - else manifold->penetration = 0.0f; - - separation = MathVector2DotProduct(refFaceNormal, incidentFace[1]) - refC; - - if (separation <= 0.0f) - { - manifold->contacts[currentPoint] = incidentFace[1]; - manifold->penetration += -separation; - currentPoint++; - - // Calculate total penetration average - manifold->penetration /= currentPoint; - } - - manifold->contactsCount = currentPoint; -} - -// Integrates physics forces into velocity -static void IntegratePhysicsForces(PhysicsBody body) -{ - if ((body == NULL) || (body->inverseMass == 0.0f) || !body->enabled) return; - - body->velocity.x += (float)((body->force.x*body->inverseMass)*(deltaTime/2.0)); - body->velocity.y += (float)((body->force.y*body->inverseMass)*(deltaTime/2.0)); - - if (body->useGravity) - { - body->velocity.x += (float)(gravityForce.x*(deltaTime/1000/2.0)); - body->velocity.y += (float)(gravityForce.y*(deltaTime/1000/2.0)); - } - - if (!body->freezeOrient) body->angularVelocity += (float)(body->torque*body->inverseInertia*(deltaTime/2.0)); -} - -// Initializes physics manifolds to solve collisions -static void InitializePhysicsManifolds(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - // Calculate average restitution, static and dynamic friction - manifold->restitution = sqrtf(bodyA->restitution*bodyB->restitution); - manifold->staticFriction = sqrtf(bodyA->staticFriction*bodyB->staticFriction); - manifold->dynamicFriction = sqrtf(bodyA->dynamicFriction*bodyB->dynamicFriction); - - for (unsigned int i = 0; i < manifold->contactsCount; i++) - { - // Caculate radius from center of mass to contact - Vector2 radiusA = MathVector2Subtract(manifold->contacts[i], bodyA->position); - Vector2 radiusB = MathVector2Subtract(manifold->contacts[i], bodyB->position); - - Vector2 crossA = MathVector2Product(radiusA, bodyA->angularVelocity); - Vector2 crossB = MathVector2Product(radiusB, bodyB->angularVelocity); - - Vector2 radiusV = { 0.0f, 0.0f }; - radiusV.x = bodyB->velocity.x + crossB.x - bodyA->velocity.x - crossA.x; - radiusV.y = bodyB->velocity.y + crossB.y - bodyA->velocity.y - crossA.y; - - // Determine if we should perform a resting collision or not; - // The idea is if the only thing moving this object is gravity, then the collision should be performed without any restitution - if (MathVector2SqrLen(radiusV) < (MathVector2SqrLen(CLITERAL(Vector2){ (float)(gravityForce.x*deltaTime/1000), (float)(gravityForce.y*deltaTime/1000) }) + PHYSAC_EPSILON)) manifold->restitution = 0; - } -} - -// Integrates physics collisions impulses to solve collisions -static void IntegratePhysicsImpulses(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - // Early out and positional correct if both objects have infinite mass - if (fabs(bodyA->inverseMass + bodyB->inverseMass) <= PHYSAC_EPSILON) - { - bodyA->velocity = PHYSAC_VECTOR_ZERO; - bodyB->velocity = PHYSAC_VECTOR_ZERO; - return; - } - - for (unsigned int i = 0; i < manifold->contactsCount; i++) - { - // Calculate radius from center of mass to contact - Vector2 radiusA = MathVector2Subtract(manifold->contacts[i], bodyA->position); - Vector2 radiusB = MathVector2Subtract(manifold->contacts[i], bodyB->position); - - // Calculate relative velocity - Vector2 radiusV = { 0.0f, 0.0f }; - radiusV.x = bodyB->velocity.x + MathVector2Product(radiusB, bodyB->angularVelocity).x - bodyA->velocity.x - MathVector2Product(radiusA, bodyA->angularVelocity).x; - radiusV.y = bodyB->velocity.y + MathVector2Product(radiusB, bodyB->angularVelocity).y - bodyA->velocity.y - MathVector2Product(radiusA, bodyA->angularVelocity).y; - - // Relative velocity along the normal - float contactVelocity = MathVector2DotProduct(radiusV, manifold->normal); - - // Do not resolve if velocities are separating - if (contactVelocity > 0.0f) return; - - float raCrossN = MathVector2CrossProduct(radiusA, manifold->normal); - float rbCrossN = MathVector2CrossProduct(radiusB, manifold->normal); - - float inverseMassSum = bodyA->inverseMass + bodyB->inverseMass + (raCrossN*raCrossN)*bodyA->inverseInertia + (rbCrossN*rbCrossN)*bodyB->inverseInertia; - - // Calculate impulse scalar value - float impulse = -(1.0f + manifold->restitution)*contactVelocity; - impulse /= inverseMassSum; - impulse /= (float)manifold->contactsCount; - - // Apply impulse to each physics body - Vector2 impulseV = { manifold->normal.x*impulse, manifold->normal.y*impulse }; - - if (bodyA->enabled) - { - bodyA->velocity.x += bodyA->inverseMass*(-impulseV.x); - bodyA->velocity.y += bodyA->inverseMass*(-impulseV.y); - if (!bodyA->freezeOrient) bodyA->angularVelocity += bodyA->inverseInertia*MathVector2CrossProduct(radiusA, CLITERAL(Vector2){ -impulseV.x, -impulseV.y }); - } - - if (bodyB->enabled) - { - bodyB->velocity.x += bodyB->inverseMass*(impulseV.x); - bodyB->velocity.y += bodyB->inverseMass*(impulseV.y); - if (!bodyB->freezeOrient) bodyB->angularVelocity += bodyB->inverseInertia*MathVector2CrossProduct(radiusB, impulseV); - } - - // Apply friction impulse to each physics body - radiusV.x = bodyB->velocity.x + MathVector2Product(radiusB, bodyB->angularVelocity).x - bodyA->velocity.x - MathVector2Product(radiusA, bodyA->angularVelocity).x; - radiusV.y = bodyB->velocity.y + MathVector2Product(radiusB, bodyB->angularVelocity).y - bodyA->velocity.y - MathVector2Product(radiusA, bodyA->angularVelocity).y; - - Vector2 tangent = { radiusV.x - (manifold->normal.x*MathVector2DotProduct(radiusV, manifold->normal)), radiusV.y - (manifold->normal.y*MathVector2DotProduct(radiusV, manifold->normal)) }; - MathVector2Normalize(&tangent); - - // Calculate impulse tangent magnitude - float impulseTangent = -MathVector2DotProduct(radiusV, tangent); - impulseTangent /= inverseMassSum; - impulseTangent /= (float)manifold->contactsCount; - - float absImpulseTangent = (float)fabs(impulseTangent); - - // Don't apply tiny friction impulses - if (absImpulseTangent <= PHYSAC_EPSILON) return; - - // Apply coulumb's law - Vector2 tangentImpulse = { 0.0f, 0.0f }; - if (absImpulseTangent < impulse*manifold->staticFriction) tangentImpulse = CLITERAL(Vector2){ tangent.x*impulseTangent, tangent.y*impulseTangent }; - else tangentImpulse = CLITERAL(Vector2){ tangent.x*-impulse*manifold->dynamicFriction, tangent.y*-impulse*manifold->dynamicFriction }; - - // Apply friction impulse - if (bodyA->enabled) - { - bodyA->velocity.x += bodyA->inverseMass*(-tangentImpulse.x); - bodyA->velocity.y += bodyA->inverseMass*(-tangentImpulse.y); - - if (!bodyA->freezeOrient) bodyA->angularVelocity += bodyA->inverseInertia*MathVector2CrossProduct(radiusA, CLITERAL(Vector2){ -tangentImpulse.x, -tangentImpulse.y }); - } - - if (bodyB->enabled) - { - bodyB->velocity.x += bodyB->inverseMass*(tangentImpulse.x); - bodyB->velocity.y += bodyB->inverseMass*(tangentImpulse.y); - - if (!bodyB->freezeOrient) bodyB->angularVelocity += bodyB->inverseInertia*MathVector2CrossProduct(radiusB, tangentImpulse); - } - } -} - -// Integrates physics velocity into position and forces -static void IntegratePhysicsVelocity(PhysicsBody body) -{ - if ((body == NULL) ||!body->enabled) return; - - body->position.x += (float)(body->velocity.x*deltaTime); - body->position.y += (float)(body->velocity.y*deltaTime); - - if (!body->freezeOrient) body->orient += (float)(body->angularVelocity*deltaTime); - body->shape.transform = MathMatFromRadians(body->orient); - - IntegratePhysicsForces(body); -} - -// Corrects physics bodies positions based on manifolds collision information -static void CorrectPhysicsPositions(PhysicsManifold manifold) -{ - PhysicsBody bodyA = manifold->bodyA; - PhysicsBody bodyB = manifold->bodyB; - - if ((bodyA == NULL) || (bodyB == NULL)) return; - - Vector2 correction = { 0.0f, 0.0f }; - correction.x = (PHYSAC_MAX(manifold->penetration - PHYSAC_PENETRATION_ALLOWANCE, 0.0f)/(bodyA->inverseMass + bodyB->inverseMass))*manifold->normal.x*PHYSAC_PENETRATION_CORRECTION; - correction.y = (PHYSAC_MAX(manifold->penetration - PHYSAC_PENETRATION_ALLOWANCE, 0.0f)/(bodyA->inverseMass + bodyB->inverseMass))*manifold->normal.y*PHYSAC_PENETRATION_CORRECTION; - - if (bodyA->enabled) - { - bodyA->position.x -= correction.x*bodyA->inverseMass; - bodyA->position.y -= correction.y*bodyA->inverseMass; - } - - if (bodyB->enabled) - { - bodyB->position.x += correction.x*bodyB->inverseMass; - bodyB->position.y += correction.y*bodyB->inverseMass; - } -} - -// Returns the extreme point along a direction within a polygon -static Vector2 GetSupport(PhysicsShape shape, Vector2 dir) -{ - float bestProjection = -PHYSAC_FLT_MAX; - Vector2 bestVertex = { 0.0f, 0.0f }; - PhysicsVertexData data = shape.vertexData; - - for (unsigned int i = 0; i < data.vertexCount; i++) - { - Vector2 vertex = data.positions[i]; - float projection = MathVector2DotProduct(vertex, dir); - - if (projection > bestProjection) - { - bestVertex = vertex; - bestProjection = projection; - } - } - - return bestVertex; -} - -// Finds polygon shapes axis least penetration -static float FindAxisLeastPenetration(int *faceIndex, PhysicsShape shapeA, PhysicsShape shapeB) -{ - float bestDistance = -PHYSAC_FLT_MAX; - int bestIndex = 0; - - PhysicsVertexData dataA = shapeA.vertexData; - //PhysicsVertexData dataB = shapeB.vertexData; - - for (unsigned int i = 0; i < dataA.vertexCount; i++) - { - // Retrieve a face normal from A shape - Vector2 normal = dataA.normals[i]; - Vector2 transNormal = MathMatVector2Product(shapeA.transform, normal); - - // Transform face normal into B shape's model space - Matrix2x2 buT = MathMatTranspose(shapeB.transform); - normal = MathMatVector2Product(buT, transNormal); - - // Retrieve support point from B shape along -n - Vector2 support = GetSupport(shapeB, CLITERAL(Vector2){ -normal.x, -normal.y }); - - // Retrieve vertex on face from A shape, transform into B shape's model space - Vector2 vertex = dataA.positions[i]; - vertex = MathMatVector2Product(shapeA.transform, vertex); - vertex = MathVector2Add(vertex, shapeA.body->position); - vertex = MathVector2Subtract(vertex, shapeB.body->position); - vertex = MathMatVector2Product(buT, vertex); - - // Compute penetration distance in B shape's model space - float distance = MathVector2DotProduct(normal, MathVector2Subtract(support, vertex)); - - // Store greatest distance - if (distance > bestDistance) - { - bestDistance = distance; - bestIndex = i; - } - } - - *faceIndex = bestIndex; - return bestDistance; -} - -// Finds two polygon shapes incident face -static void FindIncidentFace(Vector2 *v0, Vector2 *v1, PhysicsShape ref, PhysicsShape inc, int index) -{ - PhysicsVertexData refData = ref.vertexData; - PhysicsVertexData incData = inc.vertexData; - - Vector2 referenceNormal = refData.normals[index]; - - // Calculate normal in incident's frame of reference - referenceNormal = MathMatVector2Product(ref.transform, referenceNormal); // To world space - referenceNormal = MathMatVector2Product(MathMatTranspose(inc.transform), referenceNormal); // To incident's model space - - // Find most anti-normal face on polygon - int incidentFace = 0; - float minDot = PHYSAC_FLT_MAX; - - for (unsigned int i = 0; i < incData.vertexCount; i++) - { - float dot = MathVector2DotProduct(referenceNormal, incData.normals[i]); - - if (dot < minDot) - { - minDot = dot; - incidentFace = i; - } - } - - // Assign face vertices for incident face - *v0 = MathMatVector2Product(inc.transform, incData.positions[incidentFace]); - *v0 = MathVector2Add(*v0, inc.body->position); - incidentFace = (((incidentFace + 1) < (int)incData.vertexCount) ? (incidentFace + 1) : 0); - *v1 = MathMatVector2Product(inc.transform, incData.positions[incidentFace]); - *v1 = MathVector2Add(*v1, inc.body->position); -} - -// Returns clipping value based on a normal and two faces -static int MathVector2Clip(Vector2 normal, Vector2 *faceA, Vector2 *faceB, float clip) -{ - int sp = 0; - Vector2 out[2] = { *faceA, *faceB }; - - // Retrieve distances from each endpoint to the line - float distanceA = MathVector2DotProduct(normal, *faceA) - clip; - float distanceB = MathVector2DotProduct(normal, *faceB) - clip; - - // If negative (behind plane) - if (distanceA <= 0.0f) out[sp++] = *faceA; - if (distanceB <= 0.0f) out[sp++] = *faceB; - - // If the points are on different sides of the plane - if ((distanceA*distanceB) < 0.0f) - { - // Push intersection point - float alpha = distanceA/(distanceA - distanceB); - out[sp] = *faceA; - Vector2 delta = MathVector2Subtract(*faceB, *faceA); - delta.x *= alpha; - delta.y *= alpha; - out[sp] = MathVector2Add(out[sp], delta); - sp++; - } - - // Assign the new converted values - *faceA = out[0]; - *faceB = out[1]; - - return sp; -} - -// Returns the barycenter of a triangle given by 3 points -static Vector2 MathTriangleBarycenter(Vector2 v1, Vector2 v2, Vector2 v3) -{ - Vector2 result = { 0.0f, 0.0f }; - - result.x = (v1.x + v2.x + v3.x)/3; - result.y = (v1.y + v2.y + v3.y)/3; - - return result; -} - -// Returns the cross product of a vector and a value -static inline Vector2 MathVector2Product(Vector2 vector, float value) -{ - Vector2 result = { -value*vector.y, value*vector.x }; - return result; -} - -// Returns the cross product of two vectors -static inline float MathVector2CrossProduct(Vector2 v1, Vector2 v2) -{ - return (v1.x*v2.y - v1.y*v2.x); -} - -// Returns the len square root of a vector -static inline float MathVector2SqrLen(Vector2 vector) -{ - return (vector.x*vector.x + vector.y*vector.y); -} - -// Returns the dot product of two vectors -static inline float MathVector2DotProduct(Vector2 v1, Vector2 v2) -{ - return (v1.x*v2.x + v1.y*v2.y); -} - -// Returns the square root of distance between two vectors -static inline float MathVector2SqrDistance(Vector2 v1, Vector2 v2) -{ - Vector2 dir = MathVector2Subtract(v1, v2); - return MathVector2DotProduct(dir, dir); -} - -// Returns the normalized values of a vector -static void MathVector2Normalize(Vector2 *vector) -{ - float length, ilength; - - Vector2 aux = *vector; - length = sqrtf(aux.x*aux.x + aux.y*aux.y); - - if (length == 0) length = 1.0f; - - ilength = 1.0f/length; - - vector->x *= ilength; - vector->y *= ilength; -} - -// Returns the sum of two given vectors -static inline Vector2 MathVector2Add(Vector2 v1, Vector2 v2) -{ - Vector2 result = { v1.x + v2.x, v1.y + v2.y }; - return result; -} - -// Returns the subtract of two given vectors -static inline Vector2 MathVector2Subtract(Vector2 v1, Vector2 v2) -{ - Vector2 result = { v1.x - v2.x, v1.y - v2.y }; - return result; -} - -// Creates a matrix 2x2 from a given radians value -static Matrix2x2 MathMatFromRadians(float radians) -{ - float cos = cosf(radians); - float sin = sinf(radians); - - Matrix2x2 result = { cos, -sin, sin, cos }; - return result; -} - -// Returns the transpose of a given matrix 2x2 -static inline Matrix2x2 MathMatTranspose(Matrix2x2 matrix) -{ - Matrix2x2 result = { matrix.m00, matrix.m10, matrix.m01, matrix.m11 }; - return result; -} - -// Multiplies a vector by a matrix 2x2 -static inline Vector2 MathMatVector2Product(Matrix2x2 matrix, Vector2 vector) -{ - Vector2 result = { matrix.m00*vector.x + matrix.m01*vector.y, matrix.m10*vector.x + matrix.m11*vector.y }; - return result; -} - -#endif // PHYSAC_IMPLEMENTATION diff --git a/include/raudio.h b/include/raudio.h deleted file mode 100644 index 7e3c42f..0000000 --- a/include/raudio.h +++ /dev/null @@ -1,198 +0,0 @@ -/********************************************************************************************** -* -* raudio v1.0 - A simple and easy-to-use audio library based on miniaudio -* -* FEATURES: -* - Manage audio device (init/close) -* - Load and unload audio files -* - Format wave data (sample rate, size, channels) -* - Play/Stop/Pause/Resume loaded audio -* - Manage mixing channels -* - Manage raw audio context -* -* DEPENDENCIES: -* miniaudio.h - Audio device management lib (https://github.com/dr-soft/miniaudio) -* stb_vorbis.h - Ogg audio files loading (http://www.nothings.org/stb_vorbis/) -* dr_mp3.h - MP3 audio file loading (https://github.com/mackron/dr_libs) -* dr_flac.h - FLAC audio file loading (https://github.com/mackron/dr_libs) -* jar_xm.h - XM module file loading -* jar_mod.h - MOD audio file loading -* -* CONTRIBUTORS: -* David Reid (github: @mackron) (Nov. 2017): -* - Complete port to miniaudio library -* -* Joshua Reisenauer (github: @kd7tck) (2015) -* - XM audio module support (jar_xm) -* - MOD audio module support (jar_mod) -* - Mixing channels support -* - Raw audio context support -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2014-2021 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 RAUDIO_H -#define RAUDIO_H - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -// 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_FREE - #define RL_FREE(p) free(p) -#endif - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -#ifndef __cplusplus -// Boolean type - #if !defined(_STDBOOL_H) - typedef enum { false, true } bool; - #define _STDBOOL_H - #endif -#endif - -// 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; - -typedef struct rAudioBuffer rAudioBuffer; - -// AudioStream, custom audio stream -typedef struct AudioStream { - rAudioBuffer *buffer; // Pointer to internal data used by the audio system - - 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; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- - -#ifdef __cplusplus -extern "C" { // Prevents name mangling of functions -#endif - -// Audio device management functions -void InitAudioDevice(void); // Initialize audio device and context -void CloseAudioDevice(void); // Close the audio device and context -bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully -void SetMasterVolume(float volume); // Set master volume (listener) - -// Wave/Sound loading/unloading functions -Wave LoadWave(const char *fileName); // Load wave data from file -Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. ".wav" -Sound LoadSound(const char *fileName); // Load sound from file -Sound LoadSoundFromWave(Wave wave); // Load sound from wave data -void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new data -void UnloadWave(Wave wave); // Unload wave data -void UnloadSound(Sound sound); // Unload sound -bool ExportWave(Wave wave, const char *fileName); // Export wave data to file, returns true on success -bool ExportWaveAsCode(Wave wave, const char *fileName); // Export wave sample data to code (.h), returns true on success - -// Wave/Sound management functions -void PlaySound(Sound sound); // Play a sound -void StopSound(Sound sound); // Stop playing a sound -void PauseSound(Sound sound); // Pause a sound -void ResumeSound(Sound sound); // Resume a paused sound -void PlaySoundMulti(Sound sound); // Play a sound (using multichannel buffer pool) -void StopSoundMulti(void); // Stop any sound playing (using multichannel buffer pool) -int GetSoundsPlaying(void); // Get number of sounds playing in the multichannel -bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing -void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level) -void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) -void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format -Wave WaveCopy(Wave wave); // Copy a wave to a new wave -void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range -float *LoadWaveSamples(Wave wave); // Load samples data from wave as a floats array -void UnloadWaveSamples(float *samples); // Unload samples data loaded with LoadWaveSamples() - -// Music management functions -Music LoadMusicStream(const char *fileName); // Load music stream from file -Music LoadMusicStreamFromMemory(const char *fileType, unsigned char* data, int dataSize); // Load music stream from data -void UnloadMusicStream(Music music); // Unload music stream -void PlayMusicStream(Music music); // Start music playing -bool IsMusicStreamPlaying(Music music); // Check if music is playing -void UpdateMusicStream(Music music); // Updates buffers for music streaming -void StopMusicStream(Music music); // Stop music playing -void PauseMusicStream(Music music); // Pause music playing -void ResumeMusicStream(Music music); // Resume playing paused music -void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds) -void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) -void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) -float GetMusicTimeLength(Music music); // Get music time length (in seconds) -float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) - -// AudioStream management functions -AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Load audio stream (to stream raw audio pcm data) -void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data -void UnloadAudioStream(AudioStream stream); // Unload audio stream and free memory -bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill -void PlayAudioStream(AudioStream stream); // Play audio stream -void PauseAudioStream(AudioStream stream); // Pause audio stream -void ResumeAudioStream(AudioStream stream); // Resume audio stream -bool IsAudioStreamPlaying(AudioStream stream); // Check if audio stream is playing -void StopAudioStream(AudioStream stream); // Stop audio stream -void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level) -void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level) -void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams - -#ifdef __cplusplus -} -#endif - -#endif // RAUDIO_H diff --git a/include/raygui.h b/include/raygui.h deleted file mode 100644 index dfb7792..0000000 --- a/include/raygui.h +++ /dev/null @@ -1,4342 +0,0 @@ -/******************************************************************************************* -* -* raygui v3.0 - A simple and easy-to-use immediate-mode gui library -* -* DESCRIPTION: -* -* raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also -* available as a standalone library, as long as input and drawing functions are provided. -* -* Controls provided: -* -* # Container/separators Controls -* - WindowBox -* - GroupBox -* - Line -* - Panel -* -* # Basic Controls -* - Label -* - Button -* - LabelButton --> Label -* - Toggle -* - ToggleGroup --> Toggle -* - CheckBox -* - ComboBox -* - DropdownBox -* - TextBox -* - TextBoxMulti -* - ValueBox --> TextBox -* - Spinner --> Button, ValueBox -* - Slider -* - SliderBar --> Slider -* - ProgressBar -* - StatusBar -* - ScrollBar -* - ScrollPanel -* - DummyRec -* - Grid -* -* # Advance Controls -* - ListView -* - ColorPicker --> ColorPanel, ColorBarHue -* - MessageBox --> Window, Label, Button -* - TextInputBox --> Window, Label, TextBox, Button -* -* It also provides a set of functions for styling the controls based on its properties (size, color). -* -* -* GUI STYLE (guiStyle): -* -* raygui uses a global data array for all gui style properties (allocated on data segment by default), -* when a new style is loaded, it is loaded over the global style... but a default gui style could always be -* recovered with GuiLoadStyleDefault() function, that overwrites the current style to the default one -* -* The global style array size is fixed and depends on the number of controls and properties: -* -* static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)]; -* -* guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB -* -* Note that the first set of BASE properties (by default guiStyle[0..15]) belong to the generic style -* used for all controls, when any of those base values is set, it is automatically populated to all -* controls, so, specific control values overwriting generic style should be set after base values. -* -* After the first BASE set we have the EXTENDED properties (by default guiStyle[16..23]), those -* properties are actually common to all controls and can not be overwritten individually (like BASE ones) -* Some of those properties are: TEXT_SIZE, TEXT_SPACING, LINE_COLOR, BACKGROUND_COLOR -* -* Custom control properties can be defined using the EXTENDED properties for each independent control. -* -* TOOL: rGuiStyler is a visual tool to customize raygui style. -* -* -* GUI ICONS (guiIcons): -* -* raygui could use a global array containing icons data (allocated on data segment by default), -* a custom icons set could be loaded over this array using GuiLoadIcons(), but loaded icons set -* must be same RICON_SIZE and no more than RICON_MAX_ICONS will be loaded -* -* Every icon is codified in binary form, using 1 bit per pixel, so, every 16x16 icon -* requires 8 integers (16*16/32) to be stored in memory. -* -* When the icon is draw, actually one quad per pixel is drawn if the bit for that pixel is set. -* -* The global icons array size is fixed and depends on the number of icons and size: -* -* static unsigned int guiIcons[RICON_MAX_ICONS*RICON_DATA_ELEMENTS]; -* -* guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB -* -* TOOL: rGuiIcons is a visual tool to customize raygui icons. -* -* -* CONFIGURATION: -* -* #define RAYGUI_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 RAYGUI_STANDALONE -* Avoid raylib.h header inclusion in this file. Data types defined on raylib are defined -* internally in the library and input management and drawing functions must be provided by -* the user (check library implementation for further details). -* -* #define RAYGUI_NO_RICONS -* Avoid including embedded ricons data (256 icons, 16x16 pixels, 1-bit per pixel, 2KB) -* -* #define RAYGUI_CUSTOM_RICONS -* Includes custom ricons.h header defining a set of custom icons, -* this file can be generated using rGuiIcons tool -* -* -* VERSIONS HISTORY: -* -* 3.0 (xx-Sep-2021) Integrated ricons data to avoid external file -* REDESIGNED: GuiTextBoxMulti() -* REMOVED: GuiImageButton*() -* Multiple minor tweaks and bugs corrected -* 2.9 (17-Mar-2021) REMOVED: Tooltip API -* 2.8 (03-May-2020) Centralized rectangles drawing to GuiDrawRectangle() -* 2.7 (20-Feb-2020) ADDED: Possible tooltips API -* 2.6 (09-Sep-2019) ADDED: GuiTextInputBox() -* REDESIGNED: GuiListView*(), GuiDropdownBox(), GuiSlider*(), GuiProgressBar(), GuiMessageBox() -* REVIEWED: GuiTextBox(), GuiSpinner(), GuiValueBox(), GuiLoadStyle() -* Replaced property INNER_PADDING by TEXT_PADDING, renamed some properties -* ADDED: 8 new custom styles ready to use -* Multiple minor tweaks and bugs corrected -* 2.5 (28-May-2019) Implemented extended GuiTextBox(), GuiValueBox(), GuiSpinner() -* 2.3 (29-Apr-2019) ADDED: rIcons auxiliar library and support for it, multiple controls reviewed -* Refactor all controls drawing mechanism to use control state -* 2.2 (05-Feb-2019) ADDED: GuiScrollBar(), GuiScrollPanel(), reviewed GuiListView(), removed Gui*Ex() controls -* 2.1 (26-Dec-2018) REDESIGNED: GuiCheckBox(), GuiComboBox(), GuiDropdownBox(), GuiToggleGroup() > Use combined text string -* REDESIGNED: Style system (breaking change) -* 2.0 (08-Nov-2018) ADDED: Support controls guiLock and custom fonts -* REVIEWED: GuiComboBox(), GuiListView()... -* 1.9 (09-Oct-2018) REVIEWED: GuiGrid(), GuiTextBox(), GuiTextBoxMulti(), GuiValueBox()... -* 1.8 (01-May-2018) Lot of rework and redesign to align with rGuiStyler and rGuiLayout -* 1.5 (21-Jun-2017) Working in an improved styles system -* 1.4 (15-Jun-2017) Rewritten all GUI functions (removed useless ones) -* 1.3 (12-Jun-2017) Complete redesign of style system -* 1.1 (01-Jun-2017) Complete review of the library -* 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria. -* 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria. -* 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria. -* -* -* CONTRIBUTORS: -* -* Ramon Santamaria: Supervision, review, redesign, update and maintenance -* Vlad Adrian: Complete rewrite of GuiTextBox() to support extended features (2019) -* Sergio Martinez: Review, testing (2015) and redesign of multiple controls (2018) -* Adria Arranz: Testing and Implementation of additional controls (2018) -* Jordi Jorba: Testing and Implementation of additional controls (2018) -* Albert Martos: Review and testing of the library (2015) -* Ian Eito: Review and testing of the library (2015) -* Kevin Gato: Initial implementation of basic components (2014) -* Daniel Nicolas: Initial implementation of basic components (2014) -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2014-2021 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 RAYGUI_H -#define RAYGUI_H - -#define RAYGUI_VERSION "3.0" - -#if !defined(RAYGUI_STANDALONE) - #include "raylib.h" -#endif - -// Function specifiers in case library is build/used as a shared library (Windows) -// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll -#if defined(_WIN32) - #if defined(BUILD_LIBTYPE_SHARED) - #define RAYGUIAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) - #elif defined(USE_LIBTYPE_SHARED) - #define RAYGUIAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) - #endif -#endif - -// Function specifiers definition -#ifndef RAYGUIAPI - #define RAYGUIAPI // Functions defined as 'extern' by default (implicit specifiers) -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- - -// Allow custom memory allocators -#ifndef RAYGUI_MALLOC - #define RAYGUI_MALLOC(sz) malloc(sz) -#endif -#ifndef RAYGUI_CALLOC - #define RAYGUI_CALLOC(n,sz) calloc(n,sz) -#endif -#ifndef RAYGUI_FREE - #define RAYGUI_FREE(p) free(p) -#endif - -// TODO: Implement custom TraceLog() -#define TRACELOG(level, ...) (void)0 - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -// NOTE: Some types are required for RAYGUI_STANDALONE usage -//---------------------------------------------------------------------------------- -#if defined(RAYGUI_STANDALONE) - #ifndef __cplusplus - // Boolean type - #ifndef true - typedef enum { false, true } bool; - #endif - #endif - - // Vector2 type - typedef struct Vector2 { - float x; - float y; - } Vector2; - - // Vector3 type // -- ConvertHSVtoRGB(), ConvertRGBtoHSV() - typedef struct Vector3 { - float x; - float y; - float z; - } Vector3; - - // Color type, RGBA (32bit) - typedef struct Color { - unsigned char r; - unsigned char g; - unsigned char b; - unsigned char a; - } Color; - - // Rectangle type - typedef struct Rectangle { - float x; - float y; - float width; - float height; - } Rectangle; - - // TODO: Texture2D type is very coupled to raylib, required by Font type - // It should be redesigned to be provided by user - typedef struct Texture2D { - 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) - } Texture2D; - - // 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; - - // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle() - // It should be redesigned to be provided by user - typedef struct Font { - int baseSize; // Base size (default chars height) - int glyphCount; // Number of characters - Texture2D texture; // Characters texture atlas - Rectangle *recs; // Characters rectangles in texture - GlyphInfo *chars; // Characters info data - } Font; -#endif - -// Style property -typedef struct GuiStyleProp { - unsigned short controlId; - unsigned short propertyId; - int propertyValue; -} GuiStyleProp; - -// Gui control state -typedef enum { - GUI_STATE_NORMAL = 0, - GUI_STATE_FOCUSED, - GUI_STATE_PRESSED, - GUI_STATE_DISABLED, -} GuiControlState; - -// Gui control text alignment -typedef enum { - GUI_TEXT_ALIGN_LEFT = 0, - GUI_TEXT_ALIGN_CENTER, - GUI_TEXT_ALIGN_RIGHT, -} GuiTextAlignment; - -// Gui controls -typedef enum { - DEFAULT = 0, // Generic control -> populates to all controls when set - LABEL, // Used also for: LABELBUTTON - BUTTON, - TOGGLE, // Used also for: TOGGLEGROUP - SLIDER, // Used also for: SLIDERBAR - PROGRESSBAR, - CHECKBOX, - COMBOBOX, - DROPDOWNBOX, - TEXTBOX, // Used also for: TEXTBOXMULTI - VALUEBOX, - SPINNER, - LISTVIEW, - COLORPICKER, - SCROLLBAR, - STATUSBAR -} GuiControl; - -// Gui base properties for every control -// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties) -typedef enum { - BORDER_COLOR_NORMAL = 0, - BASE_COLOR_NORMAL, - TEXT_COLOR_NORMAL, - BORDER_COLOR_FOCUSED, - BASE_COLOR_FOCUSED, - TEXT_COLOR_FOCUSED, - BORDER_COLOR_PRESSED, - BASE_COLOR_PRESSED, - TEXT_COLOR_PRESSED, - BORDER_COLOR_DISABLED, - BASE_COLOR_DISABLED, - TEXT_COLOR_DISABLED, - BORDER_WIDTH, - TEXT_PADDING, - TEXT_ALIGNMENT, - RESERVED -} GuiControlProperty; - -// Gui extended properties depend on control -// NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default 8 properties) - -// DEFAULT extended properties -// NOTE: Those properties are actually common to all controls -typedef enum { - TEXT_SIZE = 16, - TEXT_SPACING, - LINE_COLOR, - BACKGROUND_COLOR, -} GuiDefaultProperty; - -// Label -//typedef enum { } GuiLabelProperty; - -// Button -//typedef enum { } GuiButtonProperty; - -// Toggle/ToggleGroup -typedef enum { - GROUP_PADDING = 16, -} GuiToggleProperty; - -// Slider/SliderBar -typedef enum { - SLIDER_WIDTH = 16, - SLIDER_PADDING -} GuiSliderProperty; - -// ProgressBar -typedef enum { - PROGRESS_PADDING = 16, -} GuiProgressBarProperty; - -// CheckBox -typedef enum { - CHECK_PADDING = 16 -} GuiCheckBoxProperty; - -// ComboBox -typedef enum { - COMBO_BUTTON_WIDTH = 16, - COMBO_BUTTON_PADDING -} GuiComboBoxProperty; - -// DropdownBox -typedef enum { - ARROW_PADDING = 16, - DROPDOWN_ITEMS_PADDING -} GuiDropdownBoxProperty; - -// TextBox/TextBoxMulti/ValueBox/Spinner -typedef enum { - TEXT_INNER_PADDING = 16, - TEXT_LINES_PADDING, - COLOR_SELECTED_FG, - COLOR_SELECTED_BG -} GuiTextBoxProperty; - -// Spinner -typedef enum { - SPIN_BUTTON_WIDTH = 16, - SPIN_BUTTON_PADDING, -} GuiSpinnerProperty; - -// ScrollBar -typedef enum { - ARROWS_SIZE = 16, - ARROWS_VISIBLE, - SCROLL_SLIDER_PADDING, - SCROLL_SLIDER_SIZE, - SCROLL_PADDING, - SCROLL_SPEED, -} GuiScrollBarProperty; - -// ScrollBar side -typedef enum { - SCROLLBAR_LEFT_SIDE = 0, - SCROLLBAR_RIGHT_SIDE -} GuiScrollBarSide; - -// ListView -typedef enum { - LIST_ITEMS_HEIGHT = 16, - LIST_ITEMS_PADDING, - SCROLLBAR_WIDTH, - SCROLLBAR_SIDE, -} GuiListViewProperty; - -// ColorPicker -typedef enum { - COLOR_SELECTOR_SIZE = 16, - HUEBAR_WIDTH, // Right hue bar width - HUEBAR_PADDING, // Right hue bar separation from panel - HUEBAR_SELECTOR_HEIGHT, // Right hue bar selector height - HUEBAR_SELECTOR_OVERFLOW // Right hue bar selector overflow -} GuiColorPickerProperty; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- - -#if defined(__cplusplus) -extern "C" { // Prevents name mangling of functions -#endif - -// Global gui state control functions -RAYGUIAPI void GuiEnable(void); // Enable gui controls (global state) -RAYGUIAPI void GuiDisable(void); // Disable gui controls (global state) -RAYGUIAPI void GuiLock(void); // Lock gui controls (global state) -RAYGUIAPI void GuiUnlock(void); // Unlock gui controls (global state) -RAYGUIAPI bool GuiIsLocked(void); // Check if gui is locked (global state) -RAYGUIAPI void GuiFade(float alpha); // Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f -RAYGUIAPI void GuiSetState(int state); // Set gui state (global state) -RAYGUIAPI int GuiGetState(void); // Get gui state (global state) - -// Font set/get functions -RAYGUIAPI void GuiSetFont(Font font); // Set gui custom font (global state) -RAYGUIAPI Font GuiGetFont(void); // Get gui custom font (global state) - -// Style set/get functions -RAYGUIAPI void GuiSetStyle(int control, int property, int value); // Set one style property -RAYGUIAPI int GuiGetStyle(int control, int property); // Get one style property - -// Container/separator controls, useful for controls organization -RAYGUIAPI bool GuiWindowBox(Rectangle bounds, const char *title); // Window Box control, shows a window that can be closed -RAYGUIAPI void GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name -RAYGUIAPI void GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text -RAYGUIAPI void GuiPanel(Rectangle bounds); // Panel control, useful to group controls -RAYGUIAPI Rectangle GuiScrollPanel(Rectangle bounds, Rectangle content, Vector2 *scroll); // Scroll Panel control - -// Basic controls set -RAYGUIAPI void GuiLabel(Rectangle bounds, const char *text); // Label control, shows text -RAYGUIAPI bool GuiButton(Rectangle bounds, const char *text); // Button control, returns true when clicked -RAYGUIAPI bool GuiLabelButton(Rectangle bounds, const char *text); // Label button control, show true when clicked -RAYGUIAPI bool GuiToggle(Rectangle bounds, const char *text, bool active); // Toggle Button control, returns true when active -RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int active); // Toggle Group control, returns active toggle index -RAYGUIAPI bool GuiCheckBox(Rectangle bounds, const char *text, bool checked); // Check Box control, returns true when active -RAYGUIAPI int GuiComboBox(Rectangle bounds, const char *text, int active); // Combo Box control, returns selected item index -RAYGUIAPI bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control, returns selected item -RAYGUIAPI bool GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Spinner control, returns selected value -RAYGUIAPI bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Value Box control, updates input text with numbers -RAYGUIAPI bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control, updates input text -RAYGUIAPI bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control with multiple lines -RAYGUIAPI float GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue); // Slider control, returns selected value -RAYGUIAPI float GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue); // Slider Bar control, returns selected value -RAYGUIAPI float GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue); // Progress Bar control, shows current progress value -RAYGUIAPI void GuiStatusBar(Rectangle bounds, const char *text); // Status Bar control, shows info text -RAYGUIAPI void GuiDummyRec(Rectangle bounds, const char *text); // Dummy control for placeholders -RAYGUIAPI int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll Bar control -RAYGUIAPI Vector2 GuiGrid(Rectangle bounds, float spacing, int subdivs); // Grid control - - -// Advance controls set -RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int active); // List View control, returns selected list item index -RAYGUIAPI int GuiListViewEx(Rectangle bounds, const char **text, int count, int *focus, int *scrollIndex, int active); // List View with extended parameters -RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons); // Message Box control, displays a message -RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text); // Text Input Box control, ask for text -RAYGUIAPI Color GuiColorPicker(Rectangle bounds, Color color); // Color Picker control (multiple color controls) -RAYGUIAPI Color GuiColorPanel(Rectangle bounds, Color color); // Color Panel control -RAYGUIAPI float GuiColorBarAlpha(Rectangle bounds, float alpha); // Color Bar Alpha control -RAYGUIAPI float GuiColorBarHue(Rectangle bounds, float value); // Color Bar Hue control - -// Styles loading functions -RAYGUIAPI void GuiLoadStyle(const char *fileName); // Load style file over global style variable (.rgs) -RAYGUIAPI void GuiLoadStyleDefault(void); // Load style default over global style - -/* -typedef GuiStyle (unsigned int *) -RAYGUIAPI GuiStyle LoadGuiStyle(const char *fileName); // Load style from file (.rgs) -RAYGUIAPI void UnloadGuiStyle(GuiStyle style); // Unload style -*/ - -RAYGUIAPI const char *GuiIconText(int iconId, const char *text); // Get text with icon id prepended (if supported) - -#if !defined(RAYGUI_NO_RICONS) -// Gui icons functionality -RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); - -RAYGUIAPI unsigned int *GuiGetIcons(void); // Get full icons data pointer -RAYGUIAPI unsigned int *GuiGetIconData(int iconId); // Get icon bit data -RAYGUIAPI void GuiSetIconData(int iconId, unsigned int *data); // Set icon bit data - -RAYGUIAPI void GuiSetIconPixel(int iconId, int x, int y); // Set icon pixel value -RAYGUIAPI void GuiClearIconPixel(int iconId, int x, int y); // Clear icon pixel value -RAYGUIAPI bool GuiCheckIconPixel(int iconId, int x, int y); // Check icon pixel value -#endif - -#if defined(__cplusplus) -} // Prevents name mangling of functions -#endif - -#endif // RAYGUI_H - -/*********************************************************************************** -* -* RAYGUI IMPLEMENTATION -* -************************************************************************************/ - -#if defined(RAYGUI_IMPLEMENTATION) - -#include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()] -#include // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()] -#include // Required for: strlen() [GuiTextBox(), GuiTextBoxMulti(), GuiValueBox()], memset(), memcpy() -#include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()] -#include // Required for: roundf() [GuiColorPicker()] - -#ifdef __cplusplus - #define RAYGUI_CLITERAL(name) name -#else - #define RAYGUI_CLITERAL(name) (name) -#endif - -#if !defined(RAYGUI_NO_RICONS) - -#if defined(RAYGUI_CUSTOM_RICONS) - -#define RICONS_IMPLEMENTATION -#include "ricons.h" // External icons data provided, it can be generated with rGuiIcons tool - -#else // Embedded raygui icons, no external file provided - -#define RICON_SIZE 16 // Size of icons (squared) -#define RICON_MAX_ICONS 256 // Maximum number of icons -#define RICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id - -// Icons data is defined by bit array (every bit represents one pixel) -// Those arrays are stored as unsigned int data arrays, so every array -// element defines 32 pixels (bits) of information -// Number of elemens depend on RICON_SIZE (by default 16x16 pixels) -#define RICON_DATA_ELEMENTS (RICON_SIZE*RICON_SIZE/32) - -//---------------------------------------------------------------------------------- -// Icons enumeration -//---------------------------------------------------------------------------------- -typedef enum { - RICON_NONE = 0, - RICON_FOLDER_FILE_OPEN = 1, - RICON_FILE_SAVE_CLASSIC = 2, - RICON_FOLDER_OPEN = 3, - RICON_FOLDER_SAVE = 4, - RICON_FILE_OPEN = 5, - RICON_FILE_SAVE = 6, - RICON_FILE_EXPORT = 7, - RICON_FILE_NEW = 8, - RICON_FILE_DELETE = 9, - RICON_FILETYPE_TEXT = 10, - RICON_FILETYPE_AUDIO = 11, - RICON_FILETYPE_IMAGE = 12, - RICON_FILETYPE_PLAY = 13, - RICON_FILETYPE_VIDEO = 14, - RICON_FILETYPE_INFO = 15, - RICON_FILE_COPY = 16, - RICON_FILE_CUT = 17, - RICON_FILE_PASTE = 18, - RICON_CURSOR_HAND = 19, - RICON_CURSOR_POINTER = 20, - RICON_CURSOR_CLASSIC = 21, - RICON_PENCIL = 22, - RICON_PENCIL_BIG = 23, - RICON_BRUSH_CLASSIC = 24, - RICON_BRUSH_PAINTER = 25, - RICON_WATER_DROP = 26, - RICON_COLOR_PICKER = 27, - RICON_RUBBER = 28, - RICON_COLOR_BUCKET = 29, - RICON_TEXT_T = 30, - RICON_TEXT_A = 31, - RICON_SCALE = 32, - RICON_RESIZE = 33, - RICON_FILTER_POINT = 34, - RICON_FILTER_BILINEAR = 35, - RICON_CROP = 36, - RICON_CROP_ALPHA = 37, - RICON_SQUARE_TOGGLE = 38, - RICON_SYMMETRY = 39, - RICON_SYMMETRY_HORIZONTAL = 40, - RICON_SYMMETRY_VERTICAL = 41, - RICON_LENS = 42, - RICON_LENS_BIG = 43, - RICON_EYE_ON = 44, - RICON_EYE_OFF = 45, - RICON_FILTER_TOP = 46, - RICON_FILTER = 47, - RICON_TARGET_POINT = 48, - RICON_TARGET_SMALL = 49, - RICON_TARGET_BIG = 50, - RICON_TARGET_MOVE = 51, - RICON_CURSOR_MOVE = 52, - RICON_CURSOR_SCALE = 53, - RICON_CURSOR_SCALE_RIGHT = 54, - RICON_CURSOR_SCALE_LEFT = 55, - RICON_UNDO = 56, - RICON_REDO = 57, - RICON_REREDO = 58, - RICON_MUTATE = 59, - RICON_ROTATE = 60, - RICON_REPEAT = 61, - RICON_SHUFFLE = 62, - RICON_EMPTYBOX = 63, - RICON_TARGET = 64, - RICON_TARGET_SMALL_FILL = 65, - RICON_TARGET_BIG_FILL = 66, - RICON_TARGET_MOVE_FILL = 67, - RICON_CURSOR_MOVE_FILL = 68, - RICON_CURSOR_SCALE_FILL = 69, - RICON_CURSOR_SCALE_RIGHT_FILL = 70, - RICON_CURSOR_SCALE_LEFT_FILL = 71, - RICON_UNDO_FILL = 72, - RICON_REDO_FILL = 73, - RICON_REREDO_FILL = 74, - RICON_MUTATE_FILL = 75, - RICON_ROTATE_FILL = 76, - RICON_REPEAT_FILL = 77, - RICON_SHUFFLE_FILL = 78, - RICON_EMPTYBOX_SMALL = 79, - RICON_BOX = 80, - RICON_BOX_TOP = 81, - RICON_BOX_TOP_RIGHT = 82, - RICON_BOX_RIGHT = 83, - RICON_BOX_BOTTOM_RIGHT = 84, - RICON_BOX_BOTTOM = 85, - RICON_BOX_BOTTOM_LEFT = 86, - RICON_BOX_LEFT = 87, - RICON_BOX_TOP_LEFT = 88, - RICON_BOX_CENTER = 89, - RICON_BOX_CIRCLE_MASK = 90, - RICON_POT = 91, - RICON_ALPHA_MULTIPLY = 92, - RICON_ALPHA_CLEAR = 93, - RICON_DITHERING = 94, - RICON_MIPMAPS = 95, - RICON_BOX_GRID = 96, - RICON_GRID = 97, - RICON_BOX_CORNERS_SMALL = 98, - RICON_BOX_CORNERS_BIG = 99, - RICON_FOUR_BOXES = 100, - RICON_GRID_FILL = 101, - RICON_BOX_MULTISIZE = 102, - RICON_ZOOM_SMALL = 103, - RICON_ZOOM_MEDIUM = 104, - RICON_ZOOM_BIG = 105, - RICON_ZOOM_ALL = 106, - RICON_ZOOM_CENTER = 107, - RICON_BOX_DOTS_SMALL = 108, - RICON_BOX_DOTS_BIG = 109, - RICON_BOX_CONCENTRIC = 110, - RICON_BOX_GRID_BIG = 111, - RICON_OK_TICK = 112, - RICON_CROSS = 113, - RICON_ARROW_LEFT = 114, - RICON_ARROW_RIGHT = 115, - RICON_ARROW_DOWN = 116, - RICON_ARROW_UP = 117, - RICON_ARROW_LEFT_FILL = 118, - RICON_ARROW_RIGHT_FILL = 119, - RICON_ARROW_DOWN_FILL = 120, - RICON_ARROW_UP_FILL = 121, - RICON_AUDIO = 122, - RICON_FX = 123, - RICON_WAVE = 124, - RICON_WAVE_SINUS = 125, - RICON_WAVE_SQUARE = 126, - RICON_WAVE_TRIANGULAR = 127, - RICON_CROSS_SMALL = 128, - RICON_PLAYER_PREVIOUS = 129, - RICON_PLAYER_PLAY_BACK = 130, - RICON_PLAYER_PLAY = 131, - RICON_PLAYER_PAUSE = 132, - RICON_PLAYER_STOP = 133, - RICON_PLAYER_NEXT = 134, - RICON_PLAYER_RECORD = 135, - RICON_MAGNET = 136, - RICON_LOCK_CLOSE = 137, - RICON_LOCK_OPEN = 138, - RICON_CLOCK = 139, - RICON_TOOLS = 140, - RICON_GEAR = 141, - RICON_GEAR_BIG = 142, - RICON_BIN = 143, - RICON_HAND_POINTER = 144, - RICON_LASER = 145, - RICON_COIN = 146, - RICON_EXPLOSION = 147, - RICON_1UP = 148, - RICON_PLAYER = 149, - RICON_PLAYER_JUMP = 150, - RICON_KEY = 151, - RICON_DEMON = 152, - RICON_TEXT_POPUP = 153, - RICON_GEAR_EX = 154, - RICON_CRACK = 155, - RICON_CRACK_POINTS = 156, - RICON_STAR = 157, - RICON_DOOR = 158, - RICON_EXIT = 159, - RICON_MODE_2D = 160, - RICON_MODE_3D = 161, - RICON_CUBE = 162, - RICON_CUBE_FACE_TOP = 163, - RICON_CUBE_FACE_LEFT = 164, - RICON_CUBE_FACE_FRONT = 165, - RICON_CUBE_FACE_BOTTOM = 166, - RICON_CUBE_FACE_RIGHT = 167, - RICON_CUBE_FACE_BACK = 168, - RICON_CAMERA = 169, - RICON_SPECIAL = 170, - RICON_LINK_NET = 171, - RICON_LINK_BOXES = 172, - RICON_LINK_MULTI = 173, - RICON_LINK = 174, - RICON_LINK_BROKE = 175, - RICON_TEXT_NOTES = 176, - RICON_NOTEBOOK = 177, - RICON_SUITCASE = 178, - RICON_SUITCASE_ZIP = 179, - RICON_MAILBOX = 180, - RICON_MONITOR = 181, - RICON_PRINTER = 182, - RICON_PHOTO_CAMERA = 183, - RICON_PHOTO_CAMERA_FLASH = 184, - RICON_HOUSE = 185, - RICON_HEART = 186, - RICON_CORNER = 187, - RICON_VERTICAL_BARS = 188, - RICON_VERTICAL_BARS_FILL = 189, - RICON_LIFE_BARS = 190, - RICON_INFO = 191, - RICON_CROSSLINE = 192, - RICON_HELP = 193, - RICON_FILETYPE_ALPHA = 194, - RICON_FILETYPE_HOME = 195, - RICON_LAYERS_VISIBLE = 196, - RICON_LAYERS = 197, - RICON_WINDOW = 198, - RICON_HIDPI = 199, - RICON_200 = 200, - RICON_201 = 201, - RICON_202 = 202, - RICON_203 = 203, - RICON_204 = 204, - RICON_205 = 205, - RICON_206 = 206, - RICON_207 = 207, - RICON_208 = 208, - RICON_209 = 209, - RICON_210 = 210, - RICON_211 = 211, - RICON_212 = 212, - RICON_213 = 213, - RICON_214 = 214, - RICON_215 = 215, - RICON_216 = 216, - RICON_217 = 217, - RICON_218 = 218, - RICON_219 = 219, - RICON_220 = 220, - RICON_221 = 221, - RICON_222 = 222, - RICON_223 = 223, - RICON_224 = 224, - RICON_225 = 225, - RICON_226 = 226, - RICON_227 = 227, - RICON_228 = 228, - RICON_229 = 229, - RICON_230 = 230, - RICON_231 = 231, - RICON_232 = 232, - RICON_233 = 233, - RICON_234 = 234, - RICON_235 = 235, - RICON_236 = 236, - RICON_237 = 237, - RICON_238 = 238, - RICON_239 = 239, - RICON_240 = 240, - RICON_241 = 241, - RICON_242 = 242, - RICON_243 = 243, - RICON_244 = 244, - RICON_245 = 245, - RICON_246 = 246, - RICON_247 = 247, - RICON_248 = 248, - RICON_249 = 249, - RICON_250 = 250, - RICON_251 = 251, - RICON_252 = 252, - RICON_253 = 253, - RICON_254 = 254, - RICON_255 = 255, -} guiIconName; - -//---------------------------------------------------------------------------------- -// Icons data for all gui possible icons (allocated on data segment by default) -// -// NOTE 1: Every icon is codified in binary form, using 1 bit per pixel, so, -// every 16x16 icon requires 8 integers (16*16/32) to be stored -// -// NOTE 2: A new icon set could be loaded over this array using GuiLoadIcons(), -// but loaded icons set must be same RICON_SIZE and no more than RICON_MAX_ICONS -// -// guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB -//---------------------------------------------------------------------------------- -static unsigned int guiIcons[RICON_MAX_ICONS*RICON_DATA_ELEMENTS] = { - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_NONE - 0x3ff80000, 0x2f082008, 0x2042207e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x00007ffe, // RICON_FOLDER_FILE_OPEN - 0x3ffe0000, 0x44226422, 0x400247e2, 0x5ffa4002, 0x57ea500a, 0x500a500a, 0x40025ffa, 0x00007ffe, // RICON_FILE_SAVE_CLASSIC - 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024002, 0x44424282, 0x793e4102, 0x00000100, // RICON_FOLDER_OPEN - 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024102, 0x44424102, 0x793e4282, 0x00000000, // RICON_FOLDER_SAVE - 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x24442284, 0x21042104, 0x20042104, 0x00003ffc, // RICON_FILE_OPEN - 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x21042104, 0x22842444, 0x20042104, 0x00003ffc, // RICON_FILE_SAVE - 0x3ff00000, 0x201c2010, 0x00042004, 0x20041004, 0x20844784, 0x00841384, 0x20042784, 0x00003ffc, // RICON_FILE_EXPORT - 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22042204, 0x22042f84, 0x20042204, 0x00003ffc, // RICON_FILE_NEW - 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x25042884, 0x25042204, 0x20042884, 0x00003ffc, // RICON_FILE_DELETE - 0x3ff00000, 0x201c2010, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // RICON_FILETYPE_TEXT - 0x3ff00000, 0x201c2010, 0x27042004, 0x244424c4, 0x26442444, 0x20642664, 0x20042004, 0x00003ffc, // RICON_FILETYPE_AUDIO - 0x3ff00000, 0x201c2010, 0x26042604, 0x20042004, 0x35442884, 0x2414222c, 0x20042004, 0x00003ffc, // RICON_FILETYPE_IMAGE - 0x3ff00000, 0x201c2010, 0x20c42004, 0x22442144, 0x22442444, 0x20c42144, 0x20042004, 0x00003ffc, // RICON_FILETYPE_PLAY - 0x3ff00000, 0x3ffc2ff0, 0x3f3c2ff4, 0x3dbc2eb4, 0x3dbc2bb4, 0x3f3c2eb4, 0x3ffc2ff4, 0x00002ff4, // RICON_FILETYPE_VIDEO - 0x3ff00000, 0x201c2010, 0x21842184, 0x21842004, 0x21842184, 0x21842184, 0x20042184, 0x00003ffc, // RICON_FILETYPE_INFO - 0x0ff00000, 0x381c0810, 0x28042804, 0x28042804, 0x28042804, 0x28042804, 0x20102ffc, 0x00003ff0, // RICON_FILE_COPY - 0x00000000, 0x701c0000, 0x079c1e14, 0x55a000f0, 0x079c00f0, 0x701c1e14, 0x00000000, 0x00000000, // RICON_FILE_CUT - 0x01c00000, 0x13e41bec, 0x3f841004, 0x204420c4, 0x20442044, 0x20442044, 0x207c2044, 0x00003fc0, // RICON_FILE_PASTE - 0x00000000, 0x3aa00fe0, 0x2abc2aa0, 0x2aa42aa4, 0x20042aa4, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_CURSOR_HAND - 0x00000000, 0x003c000c, 0x030800c8, 0x30100c10, 0x10202020, 0x04400840, 0x01800280, 0x00000000, // RICON_CURSOR_POINTER - 0x00000000, 0x00180000, 0x01f00078, 0x03e007f0, 0x07c003e0, 0x04000e40, 0x00000000, 0x00000000, // RICON_CURSOR_CLASSIC - 0x00000000, 0x04000000, 0x11000a00, 0x04400a80, 0x01100220, 0x00580088, 0x00000038, 0x00000000, // RICON_PENCIL - 0x04000000, 0x15000a00, 0x50402880, 0x14102820, 0x05040a08, 0x015c028c, 0x007c00bc, 0x00000000, // RICON_PENCIL_BIG - 0x01c00000, 0x01400140, 0x01400140, 0x0ff80140, 0x0ff80808, 0x0aa80808, 0x0aa80aa8, 0x00000ff8, // RICON_BRUSH_CLASSIC - 0x1ffc0000, 0x5ffc7ffe, 0x40004000, 0x00807f80, 0x01c001c0, 0x01c001c0, 0x01c001c0, 0x00000080, // RICON_BRUSH_PAINTER - 0x00000000, 0x00800000, 0x01c00080, 0x03e001c0, 0x07f003e0, 0x036006f0, 0x000001c0, 0x00000000, // RICON_WATER_DROP - 0x00000000, 0x3e003800, 0x1f803f80, 0x0c201e40, 0x02080c10, 0x00840104, 0x00380044, 0x00000000, // RICON_COLOR_PICKER - 0x00000000, 0x07800300, 0x1fe00fc0, 0x3f883fd0, 0x0e021f04, 0x02040402, 0x00f00108, 0x00000000, // RICON_RUBBER - 0x00c00000, 0x02800140, 0x08200440, 0x20081010, 0x2ffe3004, 0x03f807fc, 0x00e001f0, 0x00000040, // RICON_COLOR_BUCKET - 0x00000000, 0x21843ffc, 0x01800180, 0x01800180, 0x01800180, 0x01800180, 0x03c00180, 0x00000000, // RICON_TEXT_T - 0x00800000, 0x01400180, 0x06200340, 0x0c100620, 0x1ff80c10, 0x380c1808, 0x70067004, 0x0000f80f, // RICON_TEXT_A - 0x78000000, 0x50004000, 0x00004800, 0x03c003c0, 0x03c003c0, 0x00100000, 0x0002000a, 0x0000000e, // RICON_SCALE - 0x75560000, 0x5e004002, 0x54001002, 0x41001202, 0x408200fe, 0x40820082, 0x40820082, 0x00006afe, // RICON_RESIZE - 0x00000000, 0x3f003f00, 0x3f003f00, 0x3f003f00, 0x00400080, 0x001c0020, 0x001c001c, 0x00000000, // RICON_FILTER_POINT - 0x6d800000, 0x00004080, 0x40804080, 0x40800000, 0x00406d80, 0x001c0020, 0x001c001c, 0x00000000, // RICON_FILTER_BILINEAR - 0x40080000, 0x1ffe2008, 0x14081008, 0x11081208, 0x10481088, 0x10081028, 0x10047ff8, 0x00001002, // RICON_CROP - 0x00100000, 0x3ffc0010, 0x2ab03550, 0x22b02550, 0x20b02150, 0x20302050, 0x2000fff0, 0x00002000, // RICON_CROP_ALPHA - 0x40000000, 0x1ff82000, 0x04082808, 0x01082208, 0x00482088, 0x00182028, 0x35542008, 0x00000002, // RICON_SQUARE_TOGGLE - 0x00000000, 0x02800280, 0x06c006c0, 0x0ea00ee0, 0x1e901eb0, 0x3e883e98, 0x7efc7e8c, 0x00000000, // RICON_SIMMETRY - 0x01000000, 0x05600100, 0x1d480d50, 0x7d423d44, 0x3d447d42, 0x0d501d48, 0x01000560, 0x00000100, // RICON_SIMMETRY_HORIZONTAL - 0x01800000, 0x04200240, 0x10080810, 0x00001ff8, 0x00007ffe, 0x0ff01ff8, 0x03c007e0, 0x00000180, // RICON_SIMMETRY_VERTICAL - 0x00000000, 0x010800f0, 0x02040204, 0x02040204, 0x07f00308, 0x1c000e00, 0x30003800, 0x00000000, // RICON_LENS - 0x00000000, 0x061803f0, 0x08240c0c, 0x08040814, 0x0c0c0804, 0x23f01618, 0x18002400, 0x00000000, // RICON_LENS_BIG - 0x00000000, 0x00000000, 0x1c7007c0, 0x638e3398, 0x1c703398, 0x000007c0, 0x00000000, 0x00000000, // RICON_EYE_ON - 0x00000000, 0x10002000, 0x04700fc0, 0x610e3218, 0x1c703098, 0x001007a0, 0x00000008, 0x00000000, // RICON_EYE_OFF - 0x00000000, 0x00007ffc, 0x40047ffc, 0x10102008, 0x04400820, 0x02800280, 0x02800280, 0x00000100, // RICON_FILTER_TOP - 0x00000000, 0x40027ffe, 0x10082004, 0x04200810, 0x02400240, 0x02400240, 0x01400240, 0x000000c0, // RICON_FILTER - 0x00800000, 0x00800080, 0x00000080, 0x3c9e0000, 0x00000000, 0x00800080, 0x00800080, 0x00000000, // RICON_TARGET_POINT - 0x00800000, 0x00800080, 0x00800080, 0x3f7e01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // RICON_TARGET_SMALL - 0x00800000, 0x00800080, 0x03e00080, 0x3e3e0220, 0x03e00220, 0x00800080, 0x00800080, 0x00000000, // RICON_TARGET_BIG - 0x01000000, 0x04400280, 0x01000100, 0x43842008, 0x43849ab2, 0x01002008, 0x04400100, 0x01000280, // RICON_TARGET_MOVE - 0x01000000, 0x04400280, 0x01000100, 0x41042108, 0x41049ff2, 0x01002108, 0x04400100, 0x01000280, // RICON_CURSOR_MOVE - 0x781e0000, 0x500a4002, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x4002500a, 0x0000781e, // RICON_CURSOR_SCALE - 0x00000000, 0x20003c00, 0x24002800, 0x01000200, 0x00400080, 0x00140024, 0x003c0004, 0x00000000, // RICON_CURSOR_SCALE_RIGHT - 0x00000000, 0x0004003c, 0x00240014, 0x00800040, 0x02000100, 0x28002400, 0x3c002000, 0x00000000, // RICON_CURSOR_SCALE_LEFT - 0x00000000, 0x00100020, 0x10101fc8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // RICON_UNDO - 0x00000000, 0x08000400, 0x080813f8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // RICON_REDO - 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3f902020, 0x00400020, 0x00000000, // RICON_REREDO - 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3fc82010, 0x00200010, 0x00000000, // RICON_MUTATE - 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18101020, 0x00100fc8, 0x00000020, // RICON_ROTATE - 0x00000000, 0x04000200, 0x240429fc, 0x20042204, 0x20442004, 0x3f942024, 0x00400020, 0x00000000, // RICON_REPEAT - 0x00000000, 0x20001000, 0x22104c0e, 0x00801120, 0x11200040, 0x4c0e2210, 0x10002000, 0x00000000, // RICON_SHUFFLE - 0x7ffe0000, 0x50024002, 0x44024802, 0x41024202, 0x40424082, 0x40124022, 0x4002400a, 0x00007ffe, // RICON_EMPTYBOX - 0x00800000, 0x03e00080, 0x08080490, 0x3c9e0808, 0x08080808, 0x03e00490, 0x00800080, 0x00000000, // RICON_TARGET - 0x00800000, 0x00800080, 0x00800080, 0x3ffe01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // RICON_TARGET_SMALL_FILL - 0x00800000, 0x00800080, 0x03e00080, 0x3ffe03e0, 0x03e003e0, 0x00800080, 0x00800080, 0x00000000, // RICON_TARGET_BIG_FILL - 0x01000000, 0x07c00380, 0x01000100, 0x638c2008, 0x638cfbbe, 0x01002008, 0x07c00100, 0x01000380, // RICON_TARGET_MOVE_FILL - 0x01000000, 0x07c00380, 0x01000100, 0x610c2108, 0x610cfffe, 0x01002108, 0x07c00100, 0x01000380, // RICON_CURSOR_MOVE_FILL - 0x781e0000, 0x6006700e, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x700e6006, 0x0000781e, // RICON_CURSOR_SCALE_FILL - 0x00000000, 0x38003c00, 0x24003000, 0x01000200, 0x00400080, 0x000c0024, 0x003c001c, 0x00000000, // RICON_CURSOR_SCALE_RIGHT - 0x00000000, 0x001c003c, 0x0024000c, 0x00800040, 0x02000100, 0x30002400, 0x3c003800, 0x00000000, // RICON_CURSOR_SCALE_LEFT - 0x00000000, 0x00300020, 0x10301ff8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // RICON_UNDO_FILL - 0x00000000, 0x0c000400, 0x0c081ff8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // RICON_REDO_FILL - 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3ff02060, 0x00400060, 0x00000000, // RICON_REREDO_FILL - 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3ff82030, 0x00200030, 0x00000000, // RICON_MUTATE_FILL - 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18301020, 0x00300ff8, 0x00000020, // RICON_ROTATE_FILL - 0x00000000, 0x06000200, 0x26042ffc, 0x20042204, 0x20442004, 0x3ff42064, 0x00400060, 0x00000000, // RICON_REPEAT_FILL - 0x00000000, 0x30001000, 0x32107c0e, 0x00801120, 0x11200040, 0x7c0e3210, 0x10003000, 0x00000000, // RICON_SHUFFLE_FILL - 0x00000000, 0x30043ffc, 0x24042804, 0x21042204, 0x20442084, 0x20142024, 0x3ffc200c, 0x00000000, // RICON_EMPTYBOX_SMALL - 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX - 0x00000000, 0x23c43ffc, 0x23c423c4, 0x200423c4, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_TOP - 0x00000000, 0x3e043ffc, 0x3e043e04, 0x20043e04, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_TOP_RIGHT - 0x00000000, 0x20043ffc, 0x20042004, 0x3e043e04, 0x3e043e04, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_RIGHT - 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x3e042004, 0x3e043e04, 0x3ffc3e04, 0x00000000, // RICON_BOX_BOTTOM_RIGHT - 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x23c42004, 0x23c423c4, 0x3ffc23c4, 0x00000000, // RICON_BOX_BOTTOM - 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x207c2004, 0x207c207c, 0x3ffc207c, 0x00000000, // RICON_BOX_BOTTOM_LEFT - 0x00000000, 0x20043ffc, 0x20042004, 0x207c207c, 0x207c207c, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_LEFT - 0x00000000, 0x207c3ffc, 0x207c207c, 0x2004207c, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_TOP_LEFT - 0x00000000, 0x20043ffc, 0x20042004, 0x23c423c4, 0x23c423c4, 0x20042004, 0x3ffc2004, 0x00000000, // RICON_BOX_CIRCLE_MASK - 0x7ffe0000, 0x40024002, 0x47e24182, 0x4ff247e2, 0x47e24ff2, 0x418247e2, 0x40024002, 0x00007ffe, // RICON_BOX_CENTER - 0x7fff0000, 0x40014001, 0x40014001, 0x49555ddd, 0x4945495d, 0x400149c5, 0x40014001, 0x00007fff, // RICON_POT - 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x404e40ce, 0x48125432, 0x4006540e, 0x00007ffe, // RICON_ALPHA_MULTIPLY - 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x5c4e40ce, 0x44124432, 0x40065c0e, 0x00007ffe, // RICON_ALPHA_CLEAR - 0x7ffe0000, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x00007ffe, // RICON_DITHERING - 0x07fe0000, 0x1ffa0002, 0x7fea000a, 0x402a402a, 0x5b2a512a, 0x5128552a, 0x40205128, 0x00007fe0, // RICON_MIPMAPS - 0x00000000, 0x1ff80000, 0x12481248, 0x12481ff8, 0x1ff81248, 0x12481248, 0x00001ff8, 0x00000000, // RICON_BOX_GRID - 0x12480000, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x00001248, // RICON_GRID - 0x00000000, 0x1c380000, 0x1c3817e8, 0x08100810, 0x08100810, 0x17e81c38, 0x00001c38, 0x00000000, // RICON_BOX_CORNERS_SMALL - 0x700e0000, 0x700e5ffa, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x5ffa700e, 0x0000700e, // RICON_BOX_CORNERS_BIG - 0x3f7e0000, 0x21422142, 0x21422142, 0x00003f7e, 0x21423f7e, 0x21422142, 0x3f7e2142, 0x00000000, // RICON_FOUR_BOXES - 0x00000000, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x00000000, // RICON_GRID_FILL - 0x7ffe0000, 0x7ffe7ffe, 0x77fe7000, 0x77fe77fe, 0x777e7700, 0x777e777e, 0x777e777e, 0x0000777e, // RICON_BOX_MULTISIZE - 0x781e0000, 0x40024002, 0x00004002, 0x01800000, 0x00000180, 0x40020000, 0x40024002, 0x0000781e, // RICON_ZOOM_SMALL - 0x781e0000, 0x40024002, 0x00004002, 0x03c003c0, 0x03c003c0, 0x40020000, 0x40024002, 0x0000781e, // RICON_ZOOM_MEDIUM - 0x781e0000, 0x40024002, 0x07e04002, 0x07e007e0, 0x07e007e0, 0x400207e0, 0x40024002, 0x0000781e, // RICON_ZOOM_BIG - 0x781e0000, 0x5ffa4002, 0x1ff85ffa, 0x1ff81ff8, 0x1ff81ff8, 0x5ffa1ff8, 0x40025ffa, 0x0000781e, // RICON_ZOOM_ALL - 0x00000000, 0x2004381c, 0x00002004, 0x00000000, 0x00000000, 0x20040000, 0x381c2004, 0x00000000, // RICON_ZOOM_CENTER - 0x00000000, 0x1db80000, 0x10081008, 0x10080000, 0x00001008, 0x10081008, 0x00001db8, 0x00000000, // RICON_BOX_DOTS_SMALL - 0x35560000, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x35562002, 0x00000000, // RICON_BOX_DOTS_BIG - 0x7ffe0000, 0x40024002, 0x48124ff2, 0x49924812, 0x48124992, 0x4ff24812, 0x40024002, 0x00007ffe, // RICON_BOX_CONCENTRIC - 0x00000000, 0x10841ffc, 0x10841084, 0x1ffc1084, 0x10841084, 0x10841084, 0x00001ffc, 0x00000000, // RICON_BOX_GRID_BIG - 0x00000000, 0x00000000, 0x10000000, 0x04000800, 0x01040200, 0x00500088, 0x00000020, 0x00000000, // RICON_OK_TICK - 0x00000000, 0x10080000, 0x04200810, 0x01800240, 0x02400180, 0x08100420, 0x00001008, 0x00000000, // RICON_CROSS - 0x00000000, 0x02000000, 0x00800100, 0x00200040, 0x00200010, 0x00800040, 0x02000100, 0x00000000, // RICON_ARROW_LEFT - 0x00000000, 0x00400000, 0x01000080, 0x04000200, 0x04000800, 0x01000200, 0x00400080, 0x00000000, // RICON_ARROW_RIGHT - 0x00000000, 0x00000000, 0x00000000, 0x08081004, 0x02200410, 0x00800140, 0x00000000, 0x00000000, // RICON_ARROW_DOWN - 0x00000000, 0x00000000, 0x01400080, 0x04100220, 0x10040808, 0x00000000, 0x00000000, 0x00000000, // RICON_ARROW_UP - 0x00000000, 0x02000000, 0x03800300, 0x03e003c0, 0x03e003f0, 0x038003c0, 0x02000300, 0x00000000, // RICON_ARROW_LEFT_FILL - 0x00000000, 0x00400000, 0x01c000c0, 0x07c003c0, 0x07c00fc0, 0x01c003c0, 0x004000c0, 0x00000000, // RICON_ARROW_RIGHT_FILL - 0x00000000, 0x00000000, 0x00000000, 0x0ff81ffc, 0x03e007f0, 0x008001c0, 0x00000000, 0x00000000, // RICON_ARROW_DOWN_FILL - 0x00000000, 0x00000000, 0x01c00080, 0x07f003e0, 0x1ffc0ff8, 0x00000000, 0x00000000, 0x00000000, // RICON_ARROW_UP_FILL - 0x00000000, 0x18a008c0, 0x32881290, 0x24822686, 0x26862482, 0x12903288, 0x08c018a0, 0x00000000, // RICON_AUDIO - 0x00000000, 0x04800780, 0x004000c0, 0x662000f0, 0x08103c30, 0x130a0e18, 0x0000318e, 0x00000000, // RICON_FX - 0x00000000, 0x00800000, 0x08880888, 0x2aaa0a8a, 0x0a8a2aaa, 0x08880888, 0x00000080, 0x00000000, // RICON_WAVE - 0x00000000, 0x00600000, 0x01080090, 0x02040108, 0x42044204, 0x24022402, 0x00001800, 0x00000000, // RICON_WAVE_SINUS - 0x00000000, 0x07f80000, 0x04080408, 0x04080408, 0x04080408, 0x7c0e0408, 0x00000000, 0x00000000, // RICON_WAVE_SQUARE - 0x00000000, 0x00000000, 0x00a00040, 0x22084110, 0x08021404, 0x00000000, 0x00000000, 0x00000000, // RICON_WAVE_TRIANGULAR - 0x00000000, 0x00000000, 0x04200000, 0x01800240, 0x02400180, 0x00000420, 0x00000000, 0x00000000, // RICON_CROSS_SMALL - 0x00000000, 0x18380000, 0x12281428, 0x10a81128, 0x112810a8, 0x14281228, 0x00001838, 0x00000000, // RICON_PLAYER_PREVIOUS - 0x00000000, 0x18000000, 0x11801600, 0x10181060, 0x10601018, 0x16001180, 0x00001800, 0x00000000, // RICON_PLAYER_PLAY_BACK - 0x00000000, 0x00180000, 0x01880068, 0x18080608, 0x06081808, 0x00680188, 0x00000018, 0x00000000, // RICON_PLAYER_PLAY - 0x00000000, 0x1e780000, 0x12481248, 0x12481248, 0x12481248, 0x12481248, 0x00001e78, 0x00000000, // RICON_PLAYER_PAUSE - 0x00000000, 0x1ff80000, 0x10081008, 0x10081008, 0x10081008, 0x10081008, 0x00001ff8, 0x00000000, // RICON_PLAYER_STOP - 0x00000000, 0x1c180000, 0x14481428, 0x15081488, 0x14881508, 0x14281448, 0x00001c18, 0x00000000, // RICON_PLAYER_NEXT - 0x00000000, 0x03c00000, 0x08100420, 0x10081008, 0x10081008, 0x04200810, 0x000003c0, 0x00000000, // RICON_PLAYER_RECORD - 0x00000000, 0x0c3007e0, 0x13c81818, 0x14281668, 0x14281428, 0x1c381c38, 0x08102244, 0x00000000, // RICON_MAGNET - 0x07c00000, 0x08200820, 0x3ff80820, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // RICON_LOCK_CLOSE - 0x07c00000, 0x08000800, 0x3ff80800, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // RICON_LOCK_OPEN - 0x01c00000, 0x0c180770, 0x3086188c, 0x60832082, 0x60034781, 0x30062002, 0x0c18180c, 0x01c00770, // RICON_CLOCK - 0x0a200000, 0x1b201b20, 0x04200e20, 0x04200420, 0x04700420, 0x0e700e70, 0x0e700e70, 0x04200e70, // RICON_TOOLS - 0x01800000, 0x3bdc318c, 0x0ff01ff8, 0x7c3e1e78, 0x1e787c3e, 0x1ff80ff0, 0x318c3bdc, 0x00000180, // RICON_GEAR - 0x01800000, 0x3ffc318c, 0x1c381ff8, 0x781e1818, 0x1818781e, 0x1ff81c38, 0x318c3ffc, 0x00000180, // RICON_GEAR_BIG - 0x00000000, 0x08080ff8, 0x08081ffc, 0x0aa80aa8, 0x0aa80aa8, 0x0aa80aa8, 0x08080aa8, 0x00000ff8, // RICON_BIN - 0x00000000, 0x00000000, 0x20043ffc, 0x08043f84, 0x04040f84, 0x04040784, 0x000007fc, 0x00000000, // RICON_HAND_POINTER - 0x00000000, 0x24400400, 0x00001480, 0x6efe0e00, 0x00000e00, 0x24401480, 0x00000400, 0x00000000, // RICON_LASER - 0x00000000, 0x03c00000, 0x08300460, 0x11181118, 0x11181118, 0x04600830, 0x000003c0, 0x00000000, // RICON_COIN - 0x00000000, 0x10880080, 0x06c00810, 0x366c07e0, 0x07e00240, 0x00001768, 0x04200240, 0x00000000, // RICON_EXPLOSION - 0x00000000, 0x3d280000, 0x2528252c, 0x3d282528, 0x05280528, 0x05e80528, 0x00000000, 0x00000000, // RICON_1UP - 0x01800000, 0x03c003c0, 0x018003c0, 0x0ff007e0, 0x0bd00bd0, 0x0a500bd0, 0x02400240, 0x02400240, // RICON_PLAYER - 0x01800000, 0x03c003c0, 0x118013c0, 0x03c81ff8, 0x07c003c8, 0x04400440, 0x0c080478, 0x00000000, // RICON_PLAYER_JUMP - 0x3ff80000, 0x30183ff8, 0x30183018, 0x3ff83ff8, 0x03000300, 0x03c003c0, 0x03e00300, 0x000003e0, // RICON_KEY - 0x3ff80000, 0x3ff83ff8, 0x33983ff8, 0x3ff83398, 0x3ff83ff8, 0x00000540, 0x0fe00aa0, 0x00000fe0, // RICON_DEMON - 0x00000000, 0x0ff00000, 0x20041008, 0x25442004, 0x10082004, 0x06000bf0, 0x00000300, 0x00000000, // RICON_TEXT_POPUP - 0x00000000, 0x11440000, 0x07f00be8, 0x1c1c0e38, 0x1c1c0c18, 0x07f00e38, 0x11440be8, 0x00000000, // RICON_GEAR_EX - 0x00000000, 0x20080000, 0x0c601010, 0x07c00fe0, 0x07c007c0, 0x0c600fe0, 0x20081010, 0x00000000, // RICON_CRACK - 0x00000000, 0x20080000, 0x0c601010, 0x04400fe0, 0x04405554, 0x0c600fe0, 0x20081010, 0x00000000, // RICON_CRACK_POINTS - 0x00000000, 0x00800080, 0x01c001c0, 0x1ffc3ffe, 0x03e007f0, 0x07f003e0, 0x0c180770, 0x00000808, // RICON_STAR - 0x0ff00000, 0x08180810, 0x08100818, 0x0a100810, 0x08180810, 0x08100818, 0x08100810, 0x00001ff8, // RICON_DOOR - 0x0ff00000, 0x08100810, 0x08100810, 0x10100010, 0x4f902010, 0x10102010, 0x08100010, 0x00000ff0, // RICON_EXIT - 0x00040000, 0x001f000e, 0x0ef40004, 0x12f41284, 0x0ef41214, 0x10040004, 0x7ffc3004, 0x10003000, // RICON_MODE_2D - 0x78040000, 0x501f600e, 0x0ef44004, 0x12f41284, 0x0ef41284, 0x10140004, 0x7ffc300c, 0x10003000, // RICON_MODE_3D - 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // RICON_CUBE - 0x7fe00000, 0x5ff87ff0, 0x47fe4ffc, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // RICON_CUBE_FACE_TOP - 0x7fe00000, 0x50386030, 0x47fe483c, 0x443e443e, 0x443e443e, 0x241e75fe, 0x0c06140e, 0x000007fe, // RICON_CUBE_FACE_LEFT - 0x7fe00000, 0x50286030, 0x47fe4804, 0x47fe47fe, 0x47fe47fe, 0x27fe77fe, 0x0ffe17fe, 0x000007fe, // RICON_CUBE_FACE_FRONT - 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x3ff27fe2, 0x0ffe1ffa, 0x000007fe, // RICON_CUBE_FACE_BOTTOM - 0x7fe00000, 0x70286030, 0x7ffe7804, 0x7c227c02, 0x7c227c22, 0x3c127de2, 0x0c061c0a, 0x000007fe, // RICON_CUBE_FACE_RIGHT - 0x7fe00000, 0x7fe87ff0, 0x7ffe7fe4, 0x7fe27fe2, 0x7fe27fe2, 0x24127fe2, 0x0c06140a, 0x000007fe, // RICON_CUBE_FACE_BACK - 0x00000000, 0x2a0233fe, 0x22022602, 0x22022202, 0x2a022602, 0x00a033fe, 0x02080110, 0x00000000, // RICON_CAMERA - 0x00000000, 0x200c3ffc, 0x000c000c, 0x3ffc000c, 0x30003000, 0x30003000, 0x3ffc3004, 0x00000000, // RICON_SPECIAL - 0x00000000, 0x0022003e, 0x012201e2, 0x0100013e, 0x01000100, 0x79000100, 0x4f004900, 0x00007800, // RICON_LINK_NET - 0x00000000, 0x44007c00, 0x45004600, 0x00627cbe, 0x00620022, 0x45007cbe, 0x44004600, 0x00007c00, // RICON_LINK_BOXES - 0x00000000, 0x0044007c, 0x0010007c, 0x3f100010, 0x3f1021f0, 0x3f100010, 0x3f0021f0, 0x00000000, // RICON_LINK_MULTI - 0x00000000, 0x0044007c, 0x00440044, 0x0010007c, 0x00100010, 0x44107c10, 0x440047f0, 0x00007c00, // RICON_LINK - 0x00000000, 0x0044007c, 0x00440044, 0x0000007c, 0x00000010, 0x44007c10, 0x44004550, 0x00007c00, // RICON_LINK_BROKE - 0x02a00000, 0x22a43ffc, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // RICON_TEXT_NOTES - 0x3ffc0000, 0x20042004, 0x245e27c4, 0x27c42444, 0x2004201e, 0x201e2004, 0x20042004, 0x00003ffc, // RICON_NOTEBOOK - 0x00000000, 0x07e00000, 0x04200420, 0x24243ffc, 0x24242424, 0x24242424, 0x3ffc2424, 0x00000000, // RICON_SUITCASE - 0x00000000, 0x0fe00000, 0x08200820, 0x40047ffc, 0x7ffc5554, 0x40045554, 0x7ffc4004, 0x00000000, // RICON_SUITCASE_ZIP - 0x00000000, 0x20043ffc, 0x3ffc2004, 0x13c81008, 0x100813c8, 0x10081008, 0x1ff81008, 0x00000000, // RICON_MAILBOX - 0x00000000, 0x40027ffe, 0x5ffa5ffa, 0x5ffa5ffa, 0x40025ffa, 0x03c07ffe, 0x1ff81ff8, 0x00000000, // RICON_MONITOR - 0x0ff00000, 0x6bfe7ffe, 0x7ffe7ffe, 0x68167ffe, 0x08106816, 0x08100810, 0x0ff00810, 0x00000000, // RICON_PRINTER - 0x3ff80000, 0xfffe2008, 0x870a8002, 0x904a888a, 0x904a904a, 0x870a888a, 0xfffe8002, 0x00000000, // RICON_PHOTO_CAMERA - 0x0fc00000, 0xfcfe0cd8, 0x8002fffe, 0x84428382, 0x84428442, 0x80028382, 0xfffe8002, 0x00000000, // RICON_PHOTO_CAMERA_FLASH - 0x00000000, 0x02400180, 0x08100420, 0x20041008, 0x23c42004, 0x22442244, 0x3ffc2244, 0x00000000, // RICON_HOUSE - 0x00000000, 0x1c700000, 0x3ff83ef8, 0x3ff83ff8, 0x0fe01ff0, 0x038007c0, 0x00000100, 0x00000000, // RICON_HEART - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xe000c000, // RICON_CORNER - 0x00000000, 0x14001c00, 0x15c01400, 0x15401540, 0x155c1540, 0x15541554, 0x1ddc1554, 0x00000000, // RICON_VERTICAL_BARS - 0x00000000, 0x03000300, 0x1b001b00, 0x1b601b60, 0x1b6c1b60, 0x1b6c1b6c, 0x1b6c1b6c, 0x00000000, // RICON_VERTICAL_BARS_FILL - 0x00000000, 0x00000000, 0x403e7ffe, 0x7ffe403e, 0x7ffe0000, 0x43fe43fe, 0x00007ffe, 0x00000000, // RICON_LIFE_BARS - 0x7ffc0000, 0x43844004, 0x43844284, 0x43844004, 0x42844284, 0x42844284, 0x40044384, 0x00007ffc, // RICON_INFO - 0x40008000, 0x10002000, 0x04000800, 0x01000200, 0x00400080, 0x00100020, 0x00040008, 0x00010002, // RICON_CROSSLINE - 0x00000000, 0x1ff01ff0, 0x18301830, 0x1f001830, 0x03001f00, 0x00000300, 0x03000300, 0x00000000, // RICON_HELP - 0x3ff00000, 0x2abc3550, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x00003ffc, // RICON_FILETYPE_ALPHA - 0x3ff00000, 0x201c2010, 0x22442184, 0x28142424, 0x29942814, 0x2ff42994, 0x20042004, 0x00003ffc, // RICON_FILETYPE_HOME - 0x07fe0000, 0x04020402, 0x7fe20402, 0x44224422, 0x44224422, 0x402047fe, 0x40204020, 0x00007fe0, // RICON_LAYERS_VISIBLE - 0x07fe0000, 0x04020402, 0x7c020402, 0x44024402, 0x44024402, 0x402047fe, 0x40204020, 0x00007fe0, // RICON_LAYERS - 0x00000000, 0x40027ffe, 0x7ffe4002, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // RICON_WINDOW - 0x09100000, 0x09f00910, 0x09100910, 0x00000910, 0x24a2779e, 0x27a224a2, 0x709e20a2, 0x00000000, // RICON_HIDPI - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_200 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_201 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_202 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_203 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_204 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_205 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_206 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_207 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_208 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_209 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_210 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_211 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_212 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_213 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_214 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_215 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_216 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_217 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_218 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_219 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_220 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_221 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_222 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_223 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_224 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_225 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_226 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_227 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_228 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_229 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_230 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_231 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_232 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_233 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_234 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_235 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_236 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_237 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_238 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_239 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_240 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_241 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_242 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_243 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_244 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_245 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_246 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_247 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_248 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_249 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_250 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_251 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_252 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_253 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_254 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // RICON_255 -}; - -#endif // RAYGUI_CUSTOM_RICONS - -#endif // !RAYGUI_NO_RICONS - -#ifndef RICON_SIZE - #define RICON_SIZE 0 -#endif - -#define RAYGUI_MAX_CONTROLS 16 // Maximum number of standard controls -#define RAYGUI_MAX_PROPS_BASE 16 // Maximum number of standard properties -#define RAYGUI_MAX_PROPS_EXTENDED 8 // Maximum number of extended properties - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// Gui control property style color element -typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -static GuiControlState guiState = GUI_STATE_NORMAL; - -static Font guiFont = { 0 }; // Gui current font (WARNING: highly coupled to raylib) -static bool guiLocked = false; // Gui lock state (no inputs processed) -static float guiAlpha = 1.0f; // Gui element transpacency on drawing - -//---------------------------------------------------------------------------------- -// Style data array for all gui style properties (allocated on data segment by default) -// -// NOTE 1: First set of BASE properties are generic to all controls but could be individually -// overwritten per control, first set of EXTENDED properties are generic to all controls and -// can not be overwritten individually but custom EXTENDED properties can be used by control -// -// NOTE 2: A new style set could be loaded over this array using GuiLoadStyle(), -// but default gui style could always be recovered with GuiLoadStyleDefault() -// -// guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB -//---------------------------------------------------------------------------------- -static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)] = { 0 }; - -static bool guiStyleLoaded = false; // Style loaded flag for lazy style initialization - -//---------------------------------------------------------------------------------- -// Standalone Mode Functions Declaration -// -// NOTE: raygui depend on some raylib input and drawing functions -// To use raygui as standalone library, below functions must be defined by the user -//---------------------------------------------------------------------------------- -#if defined(RAYGUI_STANDALONE) - -#define KEY_RIGHT 262 -#define KEY_LEFT 263 -#define KEY_DOWN 264 -#define KEY_UP 265 -#define KEY_BACKSPACE 259 -#define KEY_ENTER 257 - -#define MOUSE_LEFT_BUTTON 0 - -// Input required functions -//------------------------------------------------------------------------------- -static Vector2 GetMousePosition(void); -static float GetMouseWheelMove(void); -static bool IsMouseButtonDown(int button); -static bool IsMouseButtonPressed(int button); -static bool IsMouseButtonReleased(int button); - -static bool IsKeyDown(int key); -static bool IsKeyPressed(int key); -static int GetCharPressed(void); // -- GuiTextBox(), GuiTextBoxMulti(), GuiValueBox() -//------------------------------------------------------------------------------- - -// Drawing required functions -//------------------------------------------------------------------------------- -static void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle(), GuiDrawIcon() - -static void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker() -//------------------------------------------------------------------------------- - -// Text required functions -//------------------------------------------------------------------------------- -static Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int glyphCount); // -- GuiLoadStyle() -static Font GetFontDefault(void); // -- GuiLoadStyleDefault() -static Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle() -static void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle() -static char *LoadFileText(const char *fileName); // -- GuiLoadStyle() -static const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle() - -static Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // -- GetTextWidth(), GuiTextBoxMulti() -static void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // -- GuiDrawText() -//------------------------------------------------------------------------------- - -// raylib functions already implemented in raygui -//------------------------------------------------------------------------------- -static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value -static int ColorToInt(Color color); // Returns hexadecimal value for a Color -static Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f -static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle -static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' -static const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings -static int TextToInteger(const char *text); // Get integer value from text -static int GetCodepoint(const char *text, int *bytesProcessed); // Get next codepoint in a UTF-8 encoded text -static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter) - -static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2); // Draw rectangle vertical gradient -//------------------------------------------------------------------------------- - -#endif // RAYGUI_STANDALONE - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -static int GetTextWidth(const char *text); // Gui get text width using default font -static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds -static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor - -static void GuiDrawText(const char *text, Rectangle bounds, int alignment, Color tint); // Gui draw text using default font -static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style - -static const char **GuiTextSplit(const char *text, int *count, int *textRow); // Split controls text into multiple strings -static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB -static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV - -//---------------------------------------------------------------------------------- -// Gui Setup Functions Definition -//---------------------------------------------------------------------------------- -// Enable gui global state -void GuiEnable(void) { guiState = GUI_STATE_NORMAL; } - -// Disable gui global state -void GuiDisable(void) { guiState = GUI_STATE_DISABLED; } - -// Lock gui global state -void GuiLock(void) { guiLocked = true; } - -// Unlock gui global state -void GuiUnlock(void) { guiLocked = false; } - -// Check if gui is locked (global state) -bool GuiIsLocked(void) { return guiLocked; } - -// Set gui controls alpha global state -void GuiFade(float alpha) -{ - if (alpha < 0.0f) alpha = 0.0f; - else if (alpha > 1.0f) alpha = 1.0f; - - guiAlpha = alpha; -} - -// Set gui state (global state) -void GuiSetState(int state) { guiState = (GuiControlState)state; } - -// Get gui state (global state) -int GuiGetState(void) { return guiState; } - -// Set custom gui font -// NOTE: Font loading/unloading is external to raygui -void GuiSetFont(Font font) -{ - if (font.texture.id > 0) - { - // NOTE: If we try to setup a font but default style has not been - // lazily loaded before, it will be overwritten, so we need to force - // default style loading first - if (!guiStyleLoaded) GuiLoadStyleDefault(); - - guiFont = font; - GuiSetStyle(DEFAULT, TEXT_SIZE, font.baseSize); - } -} - -// Get custom gui font -Font GuiGetFont(void) -{ - return guiFont; -} - -// Set control style property value -void GuiSetStyle(int control, int property, int value) -{ - if (!guiStyleLoaded) GuiLoadStyleDefault(); - guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value; - - // Default properties are propagated to all controls - if ((control == 0) && (property < RAYGUI_MAX_PROPS_BASE)) - { - for (int i = 1; i < RAYGUI_MAX_CONTROLS; i++) guiStyle[i*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value; - } -} - -// Get control style property value -int GuiGetStyle(int control, int property) -{ - if (!guiStyleLoaded) GuiLoadStyleDefault(); - return guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property]; -} - -//---------------------------------------------------------------------------------- -// Gui Controls Functions Definition -//---------------------------------------------------------------------------------- - -// Window Box control -bool GuiWindowBox(Rectangle bounds, const char *title) -{ - // NOTE: This define is also used by GuiMessageBox() and GuiTextInputBox() - #define WINDOW_STATUSBAR_HEIGHT 22 - - //GuiControlState state = guiState; - bool clicked = false; - - int statusBarHeight = WINDOW_STATUSBAR_HEIGHT + 2*GuiGetStyle(STATUSBAR, BORDER_WIDTH); - statusBarHeight += (statusBarHeight%2); - - Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)statusBarHeight }; - if (bounds.height < statusBarHeight*2.0f) bounds.height = statusBarHeight*2.0f; - - Rectangle windowPanel = { bounds.x, bounds.y + (float)statusBarHeight - 1, bounds.width, bounds.height - (float)statusBarHeight }; - Rectangle closeButtonRec = { statusBar.x + statusBar.width - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - 20, - statusBar.y + statusBarHeight/2.0f - 18.0f/2.0f, 18, 18 }; - - // Update control - //-------------------------------------------------------------------- - // NOTE: Logic is directly managed by button - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiStatusBar(statusBar, title); // Draw window header as status bar - GuiPanel(windowPanel); // Draw window base - - // Draw window close button - int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, BORDER_WIDTH, 1); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); -#if defined(RAYGUI_NO_RICONS) - clicked = GuiButton(closeButtonRec, "x"); -#else - clicked = GuiButton(closeButtonRec, GuiIconText(RICON_CROSS_SMALL, NULL)); -#endif - GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); - //-------------------------------------------------------------------- - - return clicked; -} - -// Group Box control with text name -void GuiGroupBox(Rectangle bounds, const char *text) -{ - #define GROUPBOX_LINE_THICK 1 - #define GROUPBOX_TEXT_PADDING 10 - - GuiControlState state = guiState; - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha)); - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, GROUPBOX_LINE_THICK }, 0, BLANK, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha)); - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y, GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha)); - - GuiLine(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width, 1 }, text); - //-------------------------------------------------------------------- -} - -// Line control -void GuiLine(Rectangle bounds, const char *text) -{ - #define LINE_TEXT_PADDING 10 - - GuiControlState state = guiState; - - Color color = Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED : LINE_COLOR)), guiAlpha); - - // Draw control - //-------------------------------------------------------------------- - if (text == NULL) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, bounds.width, 1 }, 0, BLANK, color); - else - { - Rectangle textBounds = { 0 }; - textBounds.width = (float)GetTextWidth(text); - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x + LINE_TEXT_PADDING; - textBounds.y = bounds.y - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - - // Draw line with embedded text label: "--- text --------------" - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, LINE_TEXT_PADDING - 2, 1 }, 0, BLANK, color); - GuiLabel(textBounds, text); - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + LINE_TEXT_PADDING + textBounds.width + 4, bounds.y, bounds.width - textBounds.width - LINE_TEXT_PADDING - 4, 1 }, 0, BLANK, color); - } - //-------------------------------------------------------------------- -} - -// Panel control -void GuiPanel(Rectangle bounds) -{ - #define PANEL_BORDER_WIDTH 1 - - GuiControlState state = guiState; - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, PANEL_BORDER_WIDTH, Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BORDER_COLOR_DISABLED: LINE_COLOR)), guiAlpha), - Fade(GetColor(GuiGetStyle(DEFAULT, (state == GUI_STATE_DISABLED)? BASE_COLOR_DISABLED : BACKGROUND_COLOR)), guiAlpha)); - //-------------------------------------------------------------------- -} - -// Scroll Panel control -Rectangle GuiScrollPanel(Rectangle bounds, Rectangle content, Vector2 *scroll) -{ - GuiControlState state = guiState; - - Vector2 scrollPos = { 0.0f, 0.0f }; - if (scroll != NULL) scrollPos = *scroll; - - bool hasHorizontalScrollBar = (content.width > bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false; - bool hasVerticalScrollBar = (content.height > bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false; - - // Recheck to account for the other scrollbar being visible - if (!hasHorizontalScrollBar) hasHorizontalScrollBar = (hasVerticalScrollBar && (content.width > (bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false; - if (!hasVerticalScrollBar) hasVerticalScrollBar = (hasHorizontalScrollBar && (content.height > (bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false; - - const int horizontalScrollBarWidth = hasHorizontalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; - const int verticalScrollBarWidth = hasVerticalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; - const Rectangle horizontalScrollBar = { (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + verticalScrollBarWidth : (float)bounds.x) + GuiGetStyle(DEFAULT, BORDER_WIDTH), (float)bounds.y + bounds.height - horizontalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH), (float)bounds.width - verticalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH), (float)horizontalScrollBarWidth }; - const Rectangle verticalScrollBar = { (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)bounds.x + bounds.width - verticalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH)), (float)bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), (float)verticalScrollBarWidth, (float)bounds.height - horizontalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) }; - - // Calculate view area (area without the scrollbars) - Rectangle view = (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? - RAYGUI_CLITERAL(Rectangle){ bounds.x + verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth } : - RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth }; - - // Clip view area to the actual content size - if (view.width > content.width) view.width = content.width; - if (view.height > content.height) view.height = content.height; - - const float horizontalMin = hasHorizontalScrollBar? ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH); - const float horizontalMax = hasHorizontalScrollBar? content.width - bounds.width + (float)verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) - (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)verticalScrollBarWidth : 0) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); - const float verticalMin = hasVerticalScrollBar? (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); - const float verticalMax = hasVerticalScrollBar? content.height - bounds.height + (float)horizontalScrollBarWidth + (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - // Check button state - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; - else state = GUI_STATE_FOCUSED; - - if (hasHorizontalScrollBar) - { - if (IsKeyDown(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - if (IsKeyDown(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - } - - if (hasVerticalScrollBar) - { - if (IsKeyDown(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - if (IsKeyDown(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - } - - float wheelMove = GetMouseWheelMove(); - - // Horizontal scroll (Shift + Mouse wheel) - if (hasHorizontalScrollBar && (IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT))) scrollPos.x += wheelMove*20; - else scrollPos.y += wheelMove*20; // Vertical scroll - } - } - - // Normalize scroll values - if (scrollPos.x > -horizontalMin) scrollPos.x = -horizontalMin; - if (scrollPos.x < -horizontalMax) scrollPos.x = -horizontalMax; - if (scrollPos.y > -verticalMin) scrollPos.y = -verticalMin; - if (scrollPos.y < -verticalMax) scrollPos.y = -verticalMax; - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background - - // Save size of the scrollbar slider - const int slider = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); - - // Draw horizontal scrollbar if visible - if (hasHorizontalScrollBar) - { - // Change scrollbar slider size to show the diff in size between the content width and the widget width - GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth)/(int)content.width)*((int)bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth))); - scrollPos.x = (float)-GuiScrollBar(horizontalScrollBar, (int)-scrollPos.x, (int)horizontalMin, (int)horizontalMax); - } - - // Draw vertical scrollbar if visible - if (hasVerticalScrollBar) - { - // Change scrollbar slider size to show the diff in size between the content height and the widget height - GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth)/(int)content.height)*((int)bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth))); - scrollPos.y = (float)-GuiScrollBar(verticalScrollBar, (int)-scrollPos.y, (int)verticalMin, (int)verticalMax); - } - - // Draw detail corner rectangle if both scroll bars are visible - if (hasHorizontalScrollBar && hasVerticalScrollBar) - { - Rectangle corner = { (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE) ? (bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) + 2) : (horizontalScrollBar.x + horizontalScrollBar.width + 2), verticalScrollBar.y + verticalScrollBar.height + 2, (float)horizontalScrollBarWidth - 4, (float)verticalScrollBarWidth - 4 }; - GuiDrawRectangle(corner, 0, BLANK, Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT + (state*3))), guiAlpha)); - } - - // Draw scrollbar lines depending on current state - GuiDrawRectangle(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), guiAlpha), BLANK); - - // Set scrollbar slider size back to the way it was before - GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, slider); - //-------------------------------------------------------------------- - - if (scroll != NULL) *scroll = scrollPos; - - return view; -} - -// Label control -void GuiLabel(Rectangle bounds, const char *text) -{ - GuiControlState state = guiState; - - // Update control - //-------------------------------------------------------------------- - // ... - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LABEL, (state == GUI_STATE_DISABLED)? TEXT_COLOR_DISABLED : TEXT_COLOR_NORMAL)), guiAlpha)); - //-------------------------------------------------------------------- -} - -// Button control, returns true when clicked -bool GuiButton(Rectangle bounds, const char *text) -{ - GuiControlState state = guiState; - bool pressed = false; - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - // Check button state - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; - else state = GUI_STATE_FOCUSED; - - if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(BUTTON, BASE + (state*3))), guiAlpha)); - GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(BUTTON, TEXT + (state*3))), guiAlpha)); - //------------------------------------------------------------------ - - return pressed; -} - -// Label button control -bool GuiLabelButton(Rectangle bounds, const char *text) -{ - GuiControlState state = guiState; - bool pressed = false; - - // NOTE: We force bounds.width to be all text - float textWidth = MeasureTextEx(guiFont, text, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING)).x; - if (bounds.width < textWidth) bounds.width = textWidth; - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - // Check checkbox state - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; - else state = GUI_STATE_FOCUSED; - - if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha)); - //-------------------------------------------------------------------- - - return pressed; -} - -// Toggle Button control, returns true when active -bool GuiToggle(Rectangle bounds, const char *text, bool active) -{ - GuiControlState state = guiState; - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - // Check toggle button state - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; - else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) - { - state = GUI_STATE_NORMAL; - active = !active; - } - else state = GUI_STATE_FOCUSED; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (state == GUI_STATE_NORMAL) - { - GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TOGGLE, (active? BORDER_COLOR_PRESSED : (BORDER + state*3)))), guiAlpha), Fade(GetColor(GuiGetStyle(TOGGLE, (active? BASE_COLOR_PRESSED : (BASE + state*3)))), guiAlpha)); - GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, (active? TEXT_COLOR_PRESSED : (TEXT + state*3)))), guiAlpha)); - } - else - { - GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TOGGLE, BORDER + state*3)), guiAlpha), Fade(GetColor(GuiGetStyle(TOGGLE, BASE + state*3)), guiAlpha)); - GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, TEXT + state*3)), guiAlpha)); - } - //-------------------------------------------------------------------- - - return active; -} - -// Toggle Group control, returns toggled button index -int GuiToggleGroup(Rectangle bounds, const char *text, int active) -{ - #if !defined(TOGGLEGROUP_MAX_ELEMENTS) - #define TOGGLEGROUP_MAX_ELEMENTS 32 - #endif - - float initBoundsX = bounds.x; - - // Get substrings items from text (items pointers) - int rows[TOGGLEGROUP_MAX_ELEMENTS] = { 0 }; - int itemCount = 0; - const char **items = GuiTextSplit(text, &itemCount, rows); - - int prevRow = rows[0]; - - for (int i = 0; i < itemCount; i++) - { - if (prevRow != rows[i]) - { - bounds.x = initBoundsX; - bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); - prevRow = rows[i]; - } - - if (i == active) GuiToggle(bounds, items[i], true); - else if (GuiToggle(bounds, items[i], false) == true) active = i; - - bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); - } - - return active; -} - -// Check Box control, returns true when active -bool GuiCheckBox(Rectangle bounds, const char *text, bool checked) -{ - GuiControlState state = guiState; - - Rectangle textBounds = { 0 }; - - if (text != NULL) - { - textBounds.width = (float)GetTextWidth(text); - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x + bounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING); - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - if (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(CHECKBOX, TEXT_PADDING); - } - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - Rectangle totalBounds = { - (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_LEFT)? textBounds.x : bounds.x, - bounds.y, - bounds.width + textBounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING), - bounds.height, - }; - - // Check checkbox state - if (CheckCollisionPointRec(mousePoint, totalBounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; - else state = GUI_STATE_FOCUSED; - - if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) checked = !checked; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(CHECKBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(CHECKBOX, BORDER + (state*3))), guiAlpha), BLANK); - - if (checked) - { - Rectangle check = { bounds.x + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING), - bounds.y + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING), - bounds.width - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)), - bounds.height - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)) }; - GuiDrawRectangle(check, 0, BLANK, Fade(GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3)), guiAlpha)); - } - - GuiDrawText(text, textBounds, (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha)); - //-------------------------------------------------------------------- - - return checked; -} - -// Combo Box control, returns selected item index -int GuiComboBox(Rectangle bounds, const char *text, int active) -{ - GuiControlState state = guiState; - - bounds.width -= (GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH) + GuiGetStyle(COMBOBOX, COMBO_BUTTON_PADDING)); - - Rectangle selector = { (float)bounds.x + bounds.width + GuiGetStyle(COMBOBOX, COMBO_BUTTON_PADDING), - (float)bounds.y, (float)GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH), (float)bounds.height }; - - // Get substrings items from text (items pointers, lengths and count) - int itemCount = 0; - const char **items = GuiTextSplit(text, &itemCount, NULL); - - if (active < 0) active = 0; - else if (active > itemCount - 1) active = itemCount - 1; - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked && (itemCount > 1)) - { - Vector2 mousePoint = GetMousePosition(); - - if (CheckCollisionPointRec(mousePoint, bounds) || - CheckCollisionPointRec(mousePoint, selector)) - { - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) - { - active += 1; - if (active >= itemCount) active = 0; - } - - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; - else state = GUI_STATE_FOCUSED; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - // Draw combo box main - GuiDrawRectangle(bounds, GuiGetStyle(COMBOBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(COMBOBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(COMBOBOX, BASE + (state*3))), guiAlpha)); - GuiDrawText(items[active], GetTextBounds(COMBOBOX, bounds), GuiGetStyle(COMBOBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(COMBOBOX, TEXT + (state*3))), guiAlpha)); - - // Draw selector using a custom button - // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values - int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, BORDER_WIDTH, 1); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); - - GuiButton(selector, TextFormat("%i/%i", active + 1, itemCount)); - - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); - GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); - //-------------------------------------------------------------------- - - return active; -} - -// Dropdown Box control -// NOTE: Returns mouse click -bool GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode) -{ - GuiControlState state = guiState; - int itemSelected = *active; - int itemFocused = -1; - - // Get substrings items from text (items pointers, lengths and count) - int itemCount = 0; - const char **items = GuiTextSplit(text, &itemCount, NULL); - - Rectangle boundsOpen = bounds; - boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_PADDING)); - - Rectangle itemBounds = bounds; - - bool pressed = false; // Check mouse button pressed - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1)) - { - Vector2 mousePoint = GetMousePosition(); - - if (editMode) - { - state = GUI_STATE_PRESSED; - - // Check if mouse has been pressed or released outside limits - if (!CheckCollisionPointRec(mousePoint, boundsOpen)) - { - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) pressed = true; - } - - // Check if already selected item has been pressed again - if (CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true; - - // Check focused and selected item - for (int i = 0; i < itemCount; i++) - { - // Update item rectangle y position for next item - itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_PADDING)); - - if (CheckCollisionPointRec(mousePoint, itemBounds)) - { - itemFocused = i; - if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) - { - itemSelected = i; - pressed = true; // Item selected, change to editMode = false - } - break; - } - } - - itemBounds = bounds; - } - else - { - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) - { - pressed = true; - state = GUI_STATE_PRESSED; - } - else state = GUI_STATE_FOCUSED; - } - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (editMode) GuiPanel(boundsOpen); - - GuiDrawRectangle(bounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BORDER + state*3)), guiAlpha), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BASE + state*3)), guiAlpha)); - GuiDrawText(items[itemSelected], GetTextBounds(DEFAULT, bounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + state*3)), guiAlpha)); - - if (editMode) - { - // Draw visible items - for (int i = 0; i < itemCount; i++) - { - // Update item rectangle y position for next item - itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_PADDING)); - - if (i == itemSelected) - { - GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_PRESSED)), guiAlpha), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_PRESSED)), guiAlpha)); - GuiDrawText(items[i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_PRESSED)), guiAlpha)); - } - else if (i == itemFocused) - { - GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_FOCUSED)), guiAlpha), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_FOCUSED)), guiAlpha)); - GuiDrawText(items[i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_FOCUSED)), guiAlpha)); - } - else GuiDrawText(items[i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_NORMAL)), guiAlpha)); - } - } - - // Draw arrows (using icon if available) -#if defined(RAYGUI_NO_RICONS) - GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, - GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))), guiAlpha)); -#else - GuiDrawText("#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, - GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))), guiAlpha)); // RICON_ARROW_DOWN_FILL -#endif - //-------------------------------------------------------------------- - - *active = itemSelected; - return pressed; -} - -// Text Box control, updates input text -// NOTE 2: Returns if KEY_ENTER pressed (useful for data validation) -bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) -{ - GuiControlState state = guiState; - bool pressed = false; - - Rectangle cursor = { - bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GetTextWidth(text) + 2, - bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE), - 4, - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)*2 - }; - - if (cursor.height > bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2; - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - if (editMode) - { - state = GUI_STATE_PRESSED; - - int key = GetCharPressed(); // Returns codepoint as Unicode - int keyCount = (int)strlen(text); - - // Only allow keys in range [32..125] - if (keyCount < (textSize - 1)) - { - float maxWidth = (bounds.width - (GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING)*2)); - - if ((GetTextWidth(text) < (maxWidth - GuiGetStyle(DEFAULT, TEXT_SIZE))) && (key >= 32)) - { - int byteSize = 0; - const char *textUTF8 = CodepointToUTF8(key, &byteSize); - - for (int i = 0; i < byteSize; i++) - { - text[keyCount] = textUTF8[i]; - keyCount++; - } - - text[keyCount] = '\0'; - } - } - - // Delete text - if (keyCount > 0) - { - if (IsKeyPressed(KEY_BACKSPACE)) - { - keyCount--; - text[keyCount] = '\0'; - if (keyCount < 0) keyCount = 0; - } - } - - if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) pressed = true; - - // Check text alignment to position cursor properly - int textAlignment = GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT); - if (textAlignment == GUI_TEXT_ALIGN_CENTER) cursor.x = bounds.x + GetTextWidth(text)/2 + bounds.width/2 + 1; - else if (textAlignment == GUI_TEXT_ALIGN_RIGHT) cursor.x = bounds.x + bounds.width - GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING); - } - else - { - if (CheckCollisionPointRec(mousePoint, bounds)) - { - state = GUI_STATE_FOCUSED; - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true; - } - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (state == GUI_STATE_PRESSED) - { - GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)), guiAlpha)); - } - else if (state == GUI_STATE_DISABLED) - { - GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED)), guiAlpha)); - } - else GuiDrawRectangle(bounds, 1, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), BLANK); - - GuiDrawText(text, GetTextBounds(TEXTBOX, bounds), GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha)); - - // Draw cursor - if (editMode) GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha)); - //-------------------------------------------------------------------- - - return pressed; -} - -// Spinner control, returns selected value -bool GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) -{ - GuiControlState state = guiState; - - bool pressed = false; - int tempValue = *value; - - Rectangle spinner = { bounds.x + GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_PADDING), bounds.y, - bounds.width - 2*(GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH) + GuiGetStyle(SPINNER, SPIN_BUTTON_PADDING)), bounds.height }; - Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height }; - Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.y, (float)GuiGetStyle(SPINNER, SPIN_BUTTON_WIDTH), (float)bounds.height }; - - Rectangle textBounds = { 0 }; - if (text != NULL) - { - textBounds.width = (float)GetTextWidth(text); - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x + bounds.width + GuiGetStyle(SPINNER, TEXT_PADDING); - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - if (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SPINNER, TEXT_PADDING); - } - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - // Check spinner state - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; - else state = GUI_STATE_FOCUSED; - } - } - - if (!editMode) - { - if (tempValue < minValue) tempValue = minValue; - if (tempValue > maxValue) tempValue = maxValue; - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - // TODO: Set Spinner properties for ValueBox - pressed = GuiValueBox(spinner, NULL, &tempValue, minValue, maxValue, editMode); - - // Draw value selector custom buttons - // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values - int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(SPINNER, BORDER_WIDTH)); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); - -#if defined(RAYGUI_NO_RICONS) - if (GuiButton(leftButtonBound, "<")) tempValue--; - if (GuiButton(rightButtonBound, ">")) tempValue++; -#else - if (GuiButton(leftButtonBound, GuiIconText(RICON_ARROW_LEFT_FILL, NULL))) tempValue--; - if (GuiButton(rightButtonBound, GuiIconText(RICON_ARROW_RIGHT_FILL, NULL))) tempValue++; -#endif - - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); - GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); - - // Draw text label if provided - GuiDrawText(text, textBounds, (GuiGetStyle(SPINNER, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha)); - //-------------------------------------------------------------------- - - *value = tempValue; - return pressed; -} - -// Value Box control, updates input text with numbers -// NOTE: Requires static variables: frameCounter -bool GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) -{ - #if !defined(VALUEBOX_MAX_CHARS) - #define VALUEBOX_MAX_CHARS 32 - #endif - - GuiControlState state = guiState; - bool pressed = false; - - char textValue[VALUEBOX_MAX_CHARS + 1] = "\0"; - sprintf(textValue, "%i", *value); - - Rectangle textBounds = { 0 }; - if (text != NULL) - { - textBounds.width = (float)GetTextWidth(text); - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING); - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING); - } - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - bool valueHasChanged = false; - - if (editMode) - { - state = GUI_STATE_PRESSED; - - int keyCount = (int)strlen(textValue); - - // Only allow keys in range [48..57] - if (keyCount < VALUEBOX_MAX_CHARS) - { - if (GetTextWidth(textValue) < bounds.width) - { - int key = GetCharPressed(); - if ((key >= 48) && (key <= 57)) - { - textValue[keyCount] = (char)key; - keyCount++; - valueHasChanged = true; - } - } - } - - // Delete text - if (keyCount > 0) - { - if (IsKeyPressed(KEY_BACKSPACE)) - { - keyCount--; - textValue[keyCount] = '\0'; - if (keyCount < 0) keyCount = 0; - valueHasChanged = true; - } - } - - if (valueHasChanged) *value = TextToInteger(textValue); - - if (IsKeyPressed(KEY_ENTER) || (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) pressed = true; - } - else - { - if (*value > maxValue) *value = maxValue; - else if (*value < minValue) *value = minValue; - - if (CheckCollisionPointRec(mousePoint, bounds)) - { - state = GUI_STATE_FOCUSED; - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true; - } - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - Color baseColor = BLANK; - if (state == GUI_STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED)); - else if (state == GUI_STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED)); - - // WARNING: BLANK color does not work properly with Fade() - GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), guiAlpha), baseColor); - GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3))), guiAlpha)); - - // Draw cursor - if (editMode) - { - // NOTE: ValueBox internal text is always centered - Rectangle cursor = { bounds.x + GetTextWidth(textValue)/2 + bounds.width/2 + 2, bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH) }; - GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED)), guiAlpha)); - } - - // Draw text label if provided - GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT)? GUI_TEXT_ALIGN_LEFT : GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(LABEL, TEXT + (state*3))), guiAlpha)); - //-------------------------------------------------------------------- - - return pressed; -} - -// Text Box control with multiple lines -bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode) -{ - GuiControlState state = guiState; - bool pressed = false; - - Rectangle textAreaBounds = { - bounds.x + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING), - bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING), - bounds.width - 2*(GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING)), - bounds.height - 2*(GuiGetStyle(TEXTBOX, BORDER_WIDTH) + GuiGetStyle(TEXTBOX, TEXT_INNER_PADDING)) - }; - - // Cursor position, [x, y] values should be updated - Rectangle cursor = { 0, -1, 4, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) + 2 }; - - float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize; // Character rectangle scaling factor - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - if (editMode) - { - state = GUI_STATE_PRESSED; - - // We get an Unicode codepoint - int codepoint = GetCharPressed(); - int textLength = (int)strlen(text); // Length in bytes (UTF-8 string) - - // Introduce characters - if (textLength < (textSize - 1)) - { - if (IsKeyPressed(KEY_ENTER)) - { - text[textLength] = '\n'; - textLength++; - } - else if (codepoint >= 32) - { - // Supports Unicode inputs -> Encoded to UTF-8 - int charUTF8Length = 0; - const char *charEncoded = CodepointToUTF8(codepoint, &charUTF8Length); - memcpy(text + textLength, charEncoded, charUTF8Length); - textLength += charUTF8Length; - } - } - - // Delete characters - if (textLength > 0) - { - if (IsKeyPressed(KEY_BACKSPACE)) - { - if ((unsigned char)text[textLength - 1] < 127) - { - // Remove ASCII equivalent character (1 byte) - textLength--; - text[textLength] = '\0'; - } - else - { - // Remove latest UTF-8 unicode character introduced (n bytes) - int charUTF8Length = 0; - while (((unsigned char)text[textLength - 1 - charUTF8Length] & 0b01000000) == 0) charUTF8Length++; - - textLength -= (charUTF8Length + 1); - text[textLength] = '\0'; - } - } - } - - // Exit edit mode - if (!CheckCollisionPointRec(mousePoint, bounds) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true; - } - else - { - if (CheckCollisionPointRec(mousePoint, bounds)) - { - state = GUI_STATE_FOCUSED; - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) pressed = true; - } - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (state == GUI_STATE_PRESSED) - { - GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED)), guiAlpha)); - } - else if (state == GUI_STATE_DISABLED) - { - GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED)), guiAlpha)); - } - else GuiDrawRectangle(bounds, 1, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), guiAlpha), BLANK); - - int wrapMode = 1; // 0-No wrap, 1-Char wrap, 2-Word wrap - Vector2 cursorPos = { textAreaBounds.x, textAreaBounds.y }; - - //int lastSpacePos = 0; - //int lastSpaceWidth = 0; - //int lastSpaceCursorPos = 0; - - for (int i = 0, codepointLength = 0; text[i] != '\0'; i += codepointLength) - { - int codepoint = GetCodepoint(text + i, &codepointLength); - int index = GetGlyphIndex(guiFont, codepoint); // If requested codepoint is not found, we get '?' (0x3f) - Rectangle atlasRec = guiFont.recs[index]; - GlyphInfo glyphInfo = guiFont.glyphs[index]; // Glyph measures - - if ((codepointLength == 1) && (codepoint == '\n')) - { - cursorPos.y += (guiFont.baseSize*scaleFactor + GuiGetStyle(TEXTBOX, TEXT_LINES_PADDING)); // Line feed - cursorPos.x = textAreaBounds.x; // Carriage return - } - else - { - if (wrapMode == 1) - { - int glyphWidth = 0; - if (glyphInfo.advanceX != 0) glyphWidth += glyphInfo.advanceX; - else glyphWidth += (atlasRec.width + glyphInfo.offsetX); - - // Jump line if the end of the text box area has been reached - if ((cursorPos.x + (glyphWidth*scaleFactor)) > (textAreaBounds.x + textAreaBounds.width)) - { - cursorPos.y += (guiFont.baseSize*scaleFactor + GuiGetStyle(TEXTBOX, TEXT_LINES_PADDING)); // Line feed - cursorPos.x = textAreaBounds.x; // Carriage return - } - } - else if (wrapMode == 2) - { - /* - if ((codepointLength == 1) && (codepoint == ' ')) - { - lastSpacePos = i; - lastSpaceWidth = 0; - lastSpaceCursorPos = cursorPos.x; - } - - // Jump line if last word reaches end of text box area - if ((lastSpaceCursorPos + lastSpaceWidth) > (textAreaBounds.x + textAreaBounds.width)) - { - cursorPos.y += 12; // Line feed - cursorPos.x = textAreaBounds.x; // Carriage return - } - */ - } - - // Draw current character glyph - DrawTextCodepoint(guiFont, codepoint, cursorPos, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), Fade(GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3))), guiAlpha)); - - int glyphWidth = 0; - if (glyphInfo.advanceX != 0) glyphWidth += glyphInfo.advanceX; - else glyphWidth += (atlasRec.width + glyphInfo.offsetX); - - cursorPos.x += (glyphWidth*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); - //if (i > lastSpacePos) lastSpaceWidth += (atlasRec.width + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); - } - } - - cursor.x = cursorPos.x; - cursor.y = cursorPos.y; - - // Draw cursor position considering text glyphs - if (editMode) GuiDrawRectangle(cursor, 0, BLANK, Fade(GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED)), guiAlpha)); - //-------------------------------------------------------------------- - - return pressed; -} - -// Slider control with pro parameters -// NOTE: Other GuiSlider*() controls use this one -float GuiSliderPro(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue, int sliderWidth) -{ - GuiControlState state = guiState; - - int sliderValue = (int)(((value - minValue)/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); - - Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING), - 0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) }; - - if (sliderWidth > 0) // Slider - { - slider.x += (sliderValue - sliderWidth/2); - slider.width = (float)sliderWidth; - } - else if (sliderWidth == 0) // SliderBar - { - slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH); - slider.width = (float)sliderValue; - } - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - state = GUI_STATE_PRESSED; - - // Get equivalent value and slider position from mousePoint.x - value = ((maxValue - minValue)*(mousePoint.x - (float)(bounds.x + sliderWidth/2)))/(float)(bounds.width - sliderWidth) + minValue; - - if (sliderWidth > 0) slider.x = mousePoint.x - slider.width/2; // Slider - else if (sliderWidth == 0) slider.width = (float)sliderValue; // SliderBar - } - else state = GUI_STATE_FOCUSED; - } - - if (value > maxValue) value = maxValue; - else if (value < minValue) value = minValue; - } - - // Bar limits check - if (sliderWidth > 0) // Slider - { - if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH); - else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH); - } - else if (sliderWidth == 0) // SliderBar - { - if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH); - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), guiAlpha), Fade(GetColor(GuiGetStyle(SLIDER, (state != GUI_STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha)); - - // Draw slider internal bar (depends on state) - if ((state == GUI_STATE_NORMAL) || (state == GUI_STATE_PRESSED)) GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED)), guiAlpha)); - else if (state == GUI_STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED)), guiAlpha)); - - // Draw left/right text if provided - if (textLeft != NULL) - { - Rectangle textBounds = { 0 }; - textBounds.width = (float)GetTextWidth(textLeft); - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING); - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - - GuiDrawText(textLeft, textBounds, GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha)); - } - - if (textRight != NULL) - { - Rectangle textBounds = { 0 }; - textBounds.width = (float)GetTextWidth(textRight); - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING); - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - - GuiDrawText(textRight, textBounds, GUI_TEXT_ALIGN_LEFT, Fade(GetColor(GuiGetStyle(SLIDER, TEXT + (state*3))), guiAlpha)); - } - //-------------------------------------------------------------------- - - return value; -} - -// Slider control extended, returns selected value and has text -float GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue) -{ - return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, GuiGetStyle(SLIDER, SLIDER_WIDTH)); -} - -// Slider Bar control extended, returns selected value -float GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue) -{ - return GuiSliderPro(bounds, textLeft, textRight, value, minValue, maxValue, 0); -} - -// Progress Bar control extended, shows current progress value -float GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float value, float minValue, float maxValue) -{ - GuiControlState state = guiState; - - Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), - bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING), 0, - bounds.height - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) }; - - // Update control - //-------------------------------------------------------------------- - if (state != GUI_STATE_DISABLED) progress.width = ((float)(value/(maxValue - minValue))*(float)(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH))); - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(PROGRESSBAR, BORDER + (state*3))), guiAlpha), BLANK); - - // Draw slider internal progress bar (depends on state) - if ((state == GUI_STATE_NORMAL) || (state == GUI_STATE_PRESSED)) GuiDrawRectangle(progress, 0, BLANK, Fade(GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED)), guiAlpha)); - else if (state == GUI_STATE_FOCUSED) GuiDrawRectangle(progress, 0, BLANK, Fade(GetColor(GuiGetStyle(PROGRESSBAR, TEXT_COLOR_FOCUSED)), guiAlpha)); - - // Draw left/right text if provided - if (textLeft != NULL) - { - Rectangle textBounds = { 0 }; - textBounds.width = (float)GetTextWidth(textLeft); - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x - textBounds.width - GuiGetStyle(PROGRESSBAR, TEXT_PADDING); - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - - GuiDrawText(textLeft, textBounds, GUI_TEXT_ALIGN_RIGHT, Fade(GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3))), guiAlpha)); - } - - if (textRight != NULL) - { - Rectangle textBounds = { 0 }; - textBounds.width = (float)GetTextWidth(textRight); - textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - textBounds.x = bounds.x + bounds.width + GuiGetStyle(PROGRESSBAR, TEXT_PADDING); - textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; - - GuiDrawText(textRight, textBounds, GUI_TEXT_ALIGN_LEFT, Fade(GetColor(GuiGetStyle(PROGRESSBAR, TEXT + (state*3))), guiAlpha)); - } - //-------------------------------------------------------------------- - - return value; -} - -// Status Bar control -void GuiStatusBar(Rectangle bounds, const char *text) -{ - GuiControlState state = guiState; - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(STATUSBAR, (state != GUI_STATE_DISABLED)? BORDER_COLOR_NORMAL : BORDER_COLOR_DISABLED)), guiAlpha), - Fade(GetColor(GuiGetStyle(STATUSBAR, (state != GUI_STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha)); - GuiDrawText(text, GetTextBounds(STATUSBAR, bounds), GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(STATUSBAR, (state != GUI_STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED)), guiAlpha)); - //-------------------------------------------------------------------- -} - -// Dummy rectangle control, intended for placeholding -void GuiDummyRec(Rectangle bounds, const char *text) -{ - GuiControlState state = guiState; - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - // Check button state - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) state = GUI_STATE_PRESSED; - else state = GUI_STATE_FOCUSED; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, 0, BLANK, Fade(GetColor(GuiGetStyle(DEFAULT, (state != GUI_STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED)), guiAlpha)); - GuiDrawText(text, GetTextBounds(DEFAULT, bounds), GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(BUTTON, (state != GUI_STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED)), guiAlpha)); - //------------------------------------------------------------------ -} - -// Scroll Bar control -int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) -{ - GuiControlState state = guiState; - - // Is the scrollbar horizontal or vertical? - bool isVertical = (bounds.width > bounds.height)? false : true; - - // The size (width or height depending on scrollbar type) of the spinner buttons - const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; - - // Arrow buttons [<] [>] [∧] [∨] - Rectangle arrowUpLeft = { 0 }; - Rectangle arrowDownRight = { 0 }; - - // Actual area of the scrollbar excluding the arrow buttons - Rectangle scrollbar = { 0 }; - - // Slider bar that moves --[///]----- - Rectangle slider = { 0 }; - - // Normalize value - if (value > maxValue) value = maxValue; - if (value < minValue) value = minValue; - - const int range = maxValue - minValue; - int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); - - // Calculate rectangles for all of the components - arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; - - if (isVertical) - { - arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize}; - scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; - sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; // Make sure the slider won't get outside of the scrollbar - slider = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), (float)scrollbar.y + (int)(((float)(value - minValue)/range)*(scrollbar.height - sliderSize)), (float)bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), (float)sliderSize }; - } - else - { - arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize}; - scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING))}; - sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; // Make sure the slider won't get outside of the scrollbar - slider = RAYGUI_CLITERAL(Rectangle){ (float)scrollbar.x + (int)(((float)(value - minValue)/range)*(scrollbar.width - sliderSize)), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), (float)sliderSize, (float)bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; - } - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - if (CheckCollisionPointRec(mousePoint, bounds)) - { - state = GUI_STATE_FOCUSED; - - // Handle mouse wheel - int wheel = (int)GetMouseWheelMove(); - if (wheel != 0) value += wheel; - - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) - { - if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= range/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += range/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - - state = GUI_STATE_PRESSED; - } - else if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - if (!isVertical) - { - Rectangle scrollArea = { arrowUpLeft.x + arrowUpLeft.width, arrowUpLeft.y, scrollbar.width, bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)}; - if (CheckCollisionPointRec(mousePoint, scrollArea)) value = (int)(((float)(mousePoint.x - scrollArea.x - slider.width/2)*range)/(scrollArea.width - slider.width) + minValue); - } - else - { - Rectangle scrollArea = { arrowUpLeft.x, arrowUpLeft.y+arrowUpLeft.height, bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), scrollbar.height}; - if (CheckCollisionPointRec(mousePoint, scrollArea)) value = (int)(((float)(mousePoint.y - scrollArea.y - slider.height/2)*range)/(scrollArea.height - slider.height) + minValue); - } - } - } - - // Normalize value - if (value > maxValue) value = maxValue; - if (value < minValue) value = minValue; - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), guiAlpha), Fade(GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED)), guiAlpha)); // Draw the background - - GuiDrawRectangle(scrollbar, 0, BLANK, Fade(GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL)), guiAlpha)); // Draw the scrollbar active area background - GuiDrawRectangle(slider, 0, BLANK, Fade(GetColor(GuiGetStyle(SLIDER, BORDER + state*3)), guiAlpha)); // Draw the slider bar - - // Draw arrows (using icon if available) - if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) - { -#if defined(RAYGUI_NO_RICONS) - GuiDrawText(isVertical? "^" : "<", RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))), guiAlpha)); - GuiDrawText(isVertical? "v" : ">", RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3))), guiAlpha)); -#else - GuiDrawText(isVertical? "#121#" : "#118#", RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3)), guiAlpha)); // RICON_ARROW_UP_FILL / RICON_ARROW_LEFT_FILL - GuiDrawText(isVertical? "#120#" : "#119#", RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - GUI_TEXT_ALIGN_CENTER, Fade(GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3)), guiAlpha)); // RICON_ARROW_DOWN_FILL / RICON_ARROW_RIGHT_FILL -#endif - } - //-------------------------------------------------------------------- - - return value; -} - -// List View control -int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int active) -{ - int itemCount = 0; - const char **items = NULL; - - if (text != NULL) items = GuiTextSplit(text, &itemCount, NULL); - - return GuiListViewEx(bounds, items, itemCount, NULL, scrollIndex, active); -} - -// List View control with extended parameters -int GuiListViewEx(Rectangle bounds, const char **text, int count, int *focus, int *scrollIndex, int active) -{ - GuiControlState state = guiState; - int itemFocused = (focus == NULL)? -1 : *focus; - int itemSelected = active; - - // Check if we need a scroll bar - bool useScrollBar = false; - if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING))*count > bounds.height) useScrollBar = true; - - // Define base item rectangle [0] - Rectangle itemBounds = { 0 }; - itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING); - itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); - itemBounds.width = bounds.width - 2*GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) - GuiGetStyle(DEFAULT, BORDER_WIDTH); - itemBounds.height = (float)GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT); - if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH); - - // Get items on the list - int visibleItems = (int)bounds.height/(GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)); - if (visibleItems > count) visibleItems = count; - - int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex; - if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0; - int endIndex = startIndex + visibleItems; - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - // Check mouse inside list view - if (CheckCollisionPointRec(mousePoint, bounds)) - { - state = GUI_STATE_FOCUSED; - - // Check focused and selected item - for (int i = 0; i < visibleItems; i++) - { - if (CheckCollisionPointRec(mousePoint, itemBounds)) - { - itemFocused = startIndex + i; - if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) - { - if (itemSelected == (startIndex + i)) itemSelected = -1; - else itemSelected = startIndex + i; - } - break; - } - - // Update item rectangle y position for next item - itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)); - } - - if (useScrollBar) - { - int wheelMove = (int)GetMouseWheelMove(); - startIndex -= wheelMove; - - if (startIndex < 0) startIndex = 0; - else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems; - - endIndex = startIndex + visibleItems; - if (endIndex > count) endIndex = count; - } - } - else itemFocused = -1; - - // Reset item rectangle y to [0] - itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), guiAlpha), GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background - - // Draw visible items - for (int i = 0; ((i < visibleItems) && (text != NULL)); i++) - { - if (state == GUI_STATE_DISABLED) - { - if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), guiAlpha), Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)), guiAlpha)); - - GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED)), guiAlpha)); - } - else - { - if ((startIndex + i) == itemSelected) - { - // Draw item selected - GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), guiAlpha), Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)), guiAlpha)); - GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)), guiAlpha)); - } - else if ((startIndex + i) == itemFocused) - { - // Draw item focused - GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), guiAlpha), Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)), guiAlpha)); - GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)), guiAlpha)); - } - else - { - // Draw item normal - GuiDrawText(text[startIndex + i], GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL)), guiAlpha)); - } - } - - // Update item rectangle y position for next item - itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)); - } - - if (useScrollBar) - { - Rectangle scrollBarBounds = { - bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), - bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), - bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - }; - - // Calculate percentage of visible items and apply same percentage to scrollbar - float percentVisible = (float)(endIndex - startIndex)/count; - float sliderSize = bounds.height*percentVisible; - - int prevSliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); // Save default slider size - int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed - GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)sliderSize); // Change slider size - GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed - - startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems); - - GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default - GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, prevSliderSize); // Reset slider size to default - } - //-------------------------------------------------------------------- - - if (focus != NULL) *focus = itemFocused; - if (scrollIndex != NULL) *scrollIndex = startIndex; - - return itemSelected; -} - -// Color Panel control -Color GuiColorPanel(Rectangle bounds, Color color) -{ - const Color colWhite = { 255, 255, 255, 255 }; - const Color colBlack = { 0, 0, 0, 255 }; - - GuiControlState state = guiState; - Vector2 pickerSelector = { 0 }; - - Vector3 vcolor = { (float)color.r/255.0f, (float)color.g/255.0f, (float)color.b/255.0f }; - Vector3 hsv = ConvertRGBtoHSV(vcolor); - - pickerSelector.x = bounds.x + (float)hsv.y*bounds.width; // HSV: Saturation - pickerSelector.y = bounds.y + (1.0f - (float)hsv.z)*bounds.height; // HSV: Value - - float hue = -1.0f; - Vector3 maxHue = { hue >= 0.0f ? hue : hsv.x, 1.0f, 1.0f }; - Vector3 rgbHue = ConvertHSVtoRGB(maxHue); - Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), - (unsigned char)(255.0f*rgbHue.y), - (unsigned char)(255.0f*rgbHue.z), 255 }; - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - if (CheckCollisionPointRec(mousePoint, bounds)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - state = GUI_STATE_PRESSED; - pickerSelector = mousePoint; - - // Calculate color from picker - Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; - - colorPick.x /= (float)bounds.width; // Get normalized value on x - colorPick.y /= (float)bounds.height; // Get normalized value on y - - hsv.y = colorPick.x; - hsv.z = 1.0f - colorPick.y; - - Vector3 rgb = ConvertHSVtoRGB(hsv); - - // NOTE: Vector3ToColor() only available on raylib 1.8.1 - color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), - (unsigned char)(255.0f*rgb.y), - (unsigned char)(255.0f*rgb.z), - (unsigned char)(255.0f*(float)color.a/255.0f) }; - - } - else state = GUI_STATE_FOCUSED; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (state != GUI_STATE_DISABLED) - { - DrawRectangleGradientEx(bounds, Fade(colWhite, guiAlpha), Fade(colWhite, guiAlpha), Fade(maxHueCol, guiAlpha), Fade(maxHueCol, guiAlpha)); - DrawRectangleGradientEx(bounds, Fade(colBlack, 0), Fade(colBlack, guiAlpha), Fade(colBlack, guiAlpha), Fade(colBlack, 0)); - - // Draw color picker: selector - Rectangle selector = { pickerSelector.x - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, pickerSelector.y - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE), (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE) }; - GuiDrawRectangle(selector, 0, BLANK, Fade(colWhite, guiAlpha)); - } - else - { - DrawRectangleGradientEx(bounds, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.6f), guiAlpha)); - } - - GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha), BLANK); - //-------------------------------------------------------------------- - - return color; -} - -// Color Bar Alpha control -// NOTE: Returns alpha value normalized [0..1] -float GuiColorBarAlpha(Rectangle bounds, float alpha) -{ - #define COLORBARALPHA_CHECKED_SIZE 10 - - GuiControlState state = guiState; - Rectangle selector = { (float)bounds.x + alpha*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 }; - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - if (CheckCollisionPointRec(mousePoint, bounds) || - CheckCollisionPointRec(mousePoint, selector)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - state = GUI_STATE_PRESSED; - - alpha = (mousePoint.x - bounds.x)/bounds.width; - if (alpha <= 0.0f) alpha = 0.0f; - if (alpha >= 1.0f) alpha = 1.0f; - //selector.x = bounds.x + (int)(((alpha - 0)/(100 - 0))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))) - selector.width/2; - } - else state = GUI_STATE_FOCUSED; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - - // Draw alpha bar: checked background - if (state != GUI_STATE_DISABLED) - { - int checksX = (int)bounds.width/COLORBARALPHA_CHECKED_SIZE; - int checksY = (int)bounds.height/COLORBARALPHA_CHECKED_SIZE; - - for (int x = 0; x < checksX; x++) - { - for (int y = 0; y < checksY; y++) - { - Rectangle check = { bounds.x + x*COLORBARALPHA_CHECKED_SIZE, bounds.y + y*COLORBARALPHA_CHECKED_SIZE, COLORBARALPHA_CHECKED_SIZE, COLORBARALPHA_CHECKED_SIZE }; - GuiDrawRectangle(check, 0, BLANK, ((x + y)%2)? Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.4f), guiAlpha) : Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.4f), guiAlpha)); - } - } - - DrawRectangleGradientEx(bounds, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha)); - } - else DrawRectangleGradientEx(bounds, Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); - - GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha), BLANK); - - // Draw alpha bar: selector - GuiDrawRectangle(selector, 0, BLANK, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha)); - //-------------------------------------------------------------------- - - return alpha; -} - -// Color Bar Hue control -// Returns hue value normalized [0..1] -// NOTE: Other similar bars (for reference): -// Color GuiColorBarSat() [WHITE->color] -// Color GuiColorBarValue() [BLACK->color], HSV/HSL -// float GuiColorBarLuminance() [BLACK->WHITE] -float GuiColorBarHue(Rectangle bounds, float hue) -{ - GuiControlState state = guiState; - Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + hue/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) }; - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GetMousePosition(); - - if (CheckCollisionPointRec(mousePoint, bounds) || - CheckCollisionPointRec(mousePoint, selector)) - { - if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) - { - state = GUI_STATE_PRESSED; - - hue = (mousePoint.y - bounds.y)*360/bounds.height; - if (hue <= 0.0f) hue = 0.0f; - if (hue >= 359.0f) hue = 359.0f; - - } - else state = GUI_STATE_FOCUSED; - - /*if (IsKeyDown(KEY_UP)) - { - hue -= 2.0f; - if (hue <= 0.0f) hue = 0.0f; - } - else if (IsKeyDown(KEY_DOWN)) - { - hue += 2.0f; - if (hue >= 360.0f) hue = 360.0f; - }*/ - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - if (state != GUI_STATE_DISABLED) - { - // Draw hue bar:color bars - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y), (int)bounds.width, ceil(bounds.height/6), Fade(RAYGUI_CLITERAL(Color) { 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color) { 255, 255, 0, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + bounds.height/6), (int)bounds.width, ceil(bounds.height/6), Fade(RAYGUI_CLITERAL(Color) { 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color) { 0, 255, 0, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 2*(bounds.height/6)), (int)bounds.width, ceil(bounds.height/6), Fade(RAYGUI_CLITERAL(Color) { 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color) { 0, 255, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 3*(bounds.height/6)), (int)bounds.width, ceil(bounds.height/6), Fade(RAYGUI_CLITERAL(Color) { 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color) { 0, 0, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 4*(bounds.height/6)), (int)bounds.width, ceil(bounds.height/6), Fade(RAYGUI_CLITERAL(Color) { 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color) { 255, 0, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 5*(bounds.height/6)), (int)bounds.width, (int)(bounds.height/6), Fade(RAYGUI_CLITERAL(Color) { 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color) { 255, 0, 0, 255 }, guiAlpha)); - } - else DrawRectangleGradientV((int)bounds.x, (int)bounds.y, (int)bounds.width, (int)bounds.height, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); - - GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha), BLANK); - - // Draw hue bar: selector - GuiDrawRectangle(selector, 0, BLANK, Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), guiAlpha)); - //-------------------------------------------------------------------- - - return hue; -} - -// Color Picker control -// NOTE: It's divided in multiple controls: -// Color GuiColorPanel(Rectangle bounds, Color color) -// float GuiColorBarAlpha(Rectangle bounds, float alpha) -// float GuiColorBarHue(Rectangle bounds, float value) -// NOTE: bounds define GuiColorPanel() size -Color GuiColorPicker(Rectangle bounds, Color color) -{ - color = GuiColorPanel(bounds, color); - - Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; - //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) }; - - Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ color.r/255.0f, color.g/255.0f, color.b/255.0f }); - hsv.x = GuiColorBarHue(boundsHue, hsv.x); - //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f); - Vector3 rgb = ConvertHSVtoRGB(hsv); - - color = RAYGUI_CLITERAL(Color){ (unsigned char)roundf(rgb.x*255.0f), (unsigned char)roundf(rgb.y*255.0f), (unsigned char)roundf(rgb.z*255.0f), color.a }; - - return color; -} - -// Message Box control -int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons) -{ - #define MESSAGEBOX_BUTTON_HEIGHT 24 - #define MESSAGEBOX_BUTTON_PADDING 10 - - int clicked = -1; // Returns clicked button from buttons list, 0 refers to closed window button - - int buttonCount = 0; - const char **buttonsText = GuiTextSplit(buttons, &buttonCount, NULL); - Rectangle buttonBounds = { 0 }; - buttonBounds.x = bounds.x + MESSAGEBOX_BUTTON_PADDING; - buttonBounds.y = bounds.y + bounds.height - MESSAGEBOX_BUTTON_HEIGHT - MESSAGEBOX_BUTTON_PADDING; - buttonBounds.width = (bounds.width - MESSAGEBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount; - buttonBounds.height = MESSAGEBOX_BUTTON_HEIGHT; - - Vector2 textSize = MeasureTextEx(guiFont, message, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), 1); - - Rectangle textBounds = { 0 }; - textBounds.x = bounds.x + bounds.width/2 - textSize.x/2; - textBounds.y = bounds.y + WINDOW_STATUSBAR_HEIGHT + (bounds.height - WINDOW_STATUSBAR_HEIGHT - MESSAGEBOX_BUTTON_HEIGHT - MESSAGEBOX_BUTTON_PADDING)/2 - textSize.y/2; - textBounds.width = textSize.x; - textBounds.height = textSize.y; - - // Draw control - //-------------------------------------------------------------------- - if (GuiWindowBox(bounds, title)) clicked = 0; - - int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); - GuiSetStyle(LABEL, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); - GuiLabel(textBounds, message); - GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment); - - prevTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); - - for (int i = 0; i < buttonCount; i++) - { - if (GuiButton(buttonBounds, buttonsText[i])) clicked = i + 1; - buttonBounds.x += (buttonBounds.width + MESSAGEBOX_BUTTON_PADDING); - } - - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment); - //-------------------------------------------------------------------- - - return clicked; -} - -// Text Input Box control, ask for text -int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text) -{ - #define TEXTINPUTBOX_BUTTON_HEIGHT 24 - #define TEXTINPUTBOX_BUTTON_PADDING 10 - #define TEXTINPUTBOX_HEIGHT 30 - - #define TEXTINPUTBOX_MAX_TEXT_LENGTH 256 - - // Used to enable text edit mode - // WARNING: No more than one GuiTextInputBox() should be open at the same time - static bool textEditMode = false; - - int btnIndex = -1; - - int buttonCount = 0; - const char **buttonsText = GuiTextSplit(buttons, &buttonCount, NULL); - Rectangle buttonBounds = { 0 }; - buttonBounds.x = bounds.x + TEXTINPUTBOX_BUTTON_PADDING; - buttonBounds.y = bounds.y + bounds.height - TEXTINPUTBOX_BUTTON_HEIGHT - TEXTINPUTBOX_BUTTON_PADDING; - buttonBounds.width = (bounds.width - TEXTINPUTBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount; - buttonBounds.height = TEXTINPUTBOX_BUTTON_HEIGHT; - - int messageInputHeight = (int)bounds.height - WINDOW_STATUSBAR_HEIGHT - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - TEXTINPUTBOX_BUTTON_HEIGHT - 2*TEXTINPUTBOX_BUTTON_PADDING; - - Rectangle textBounds = { 0 }; - if (message != NULL) - { - Vector2 textSize = MeasureTextEx(guiFont, message, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), 1); - - textBounds.x = bounds.x + bounds.width/2 - textSize.x/2; - textBounds.y = bounds.y + WINDOW_STATUSBAR_HEIGHT + messageInputHeight/4 - textSize.y/2; - textBounds.width = textSize.x; - textBounds.height = textSize.y; - } - - Rectangle textBoxBounds = { 0 }; - textBoxBounds.x = bounds.x + TEXTINPUTBOX_BUTTON_PADDING; - textBoxBounds.y = bounds.y + WINDOW_STATUSBAR_HEIGHT - TEXTINPUTBOX_HEIGHT/2; - if (message == NULL) textBoxBounds.y += messageInputHeight/2; - else textBoxBounds.y += (messageInputHeight/2 + messageInputHeight/4); - textBoxBounds.width = bounds.width - TEXTINPUTBOX_BUTTON_PADDING*2; - textBoxBounds.height = TEXTINPUTBOX_HEIGHT; - - // Draw control - //-------------------------------------------------------------------- - if (GuiWindowBox(bounds, title)) btnIndex = 0; - - // Draw message if available - if (message != NULL) - { - int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); - GuiSetStyle(LABEL, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); - GuiLabel(textBounds, message); - GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment); - } - - if (GuiTextBox(textBoxBounds, text, TEXTINPUTBOX_MAX_TEXT_LENGTH, textEditMode)) textEditMode = !textEditMode; - - int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); - - for (int i = 0; i < buttonCount; i++) - { - if (GuiButton(buttonBounds, buttonsText[i])) btnIndex = i + 1; - buttonBounds.x += (buttonBounds.width + MESSAGEBOX_BUTTON_PADDING); - } - - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment); - //-------------------------------------------------------------------- - - return btnIndex; -} - -// Grid control -// NOTE: Returns grid mouse-hover selected cell -// About drawing lines at subpixel spacing, simple put, not easy solution: -// https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster -Vector2 GuiGrid(Rectangle bounds, float spacing, int subdivs) -{ - #if !defined(GRID_COLOR_ALPHA) - #define GRID_COLOR_ALPHA 0.15f // Grid lines alpha amount - #endif - - GuiControlState state = guiState; - Vector2 mousePoint = GetMousePosition(); - Vector2 currentCell = { -1, -1 }; - - int linesV = ((int)(bounds.width/spacing))*subdivs + 1; - int linesH = ((int)(bounds.height/spacing))*subdivs + 1; - - // Update control - //-------------------------------------------------------------------- - if ((state != GUI_STATE_DISABLED) && !guiLocked) - { - if (CheckCollisionPointRec(mousePoint, bounds)) - { - currentCell.x = (mousePoint.x - bounds.x)/spacing; - currentCell.y = (mousePoint.y - bounds.y)/spacing; - } - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - switch (state) - { - case GUI_STATE_NORMAL: - { - if (subdivs > 0) - { - // Draw vertical grid lines - for (int i = 0; i < linesV; i++) - { - Rectangle lineV = { bounds.x + spacing*i/subdivs, bounds.y, 1, bounds.height }; - GuiDrawRectangle(lineV, 0, BLANK, ((i%subdivs) == 0) ? Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), GRID_COLOR_ALPHA*4) : Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), GRID_COLOR_ALPHA)); - } - - // Draw horizontal grid lines - for (int i = 0; i < linesH; i++) - { - Rectangle lineH = { bounds.x, bounds.y + spacing*i/subdivs, bounds.width, 1 }; - GuiDrawRectangle(lineH, 0, BLANK, ((i%subdivs) == 0) ? Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), GRID_COLOR_ALPHA*4) : Fade(GetColor(GuiGetStyle(DEFAULT, LINE_COLOR)), GRID_COLOR_ALPHA)); - } - } - } break; - default: break; - } - - return currentCell; -} - -//---------------------------------------------------------------------------------- -// Styles loading functions -//---------------------------------------------------------------------------------- - -// Load raygui style file (.rgs) -void GuiLoadStyle(const char *fileName) -{ - bool tryBinary = false; - - // Try reading the files as text file first - FILE *rgsFile = fopen(fileName, "rt"); - - if (rgsFile != NULL) - { - char buffer[256] = { 0 }; - fgets(buffer, 256, rgsFile); - - if (buffer[0] == '#') - { - int controlId = 0; - int propertyId = 0; - unsigned int propertyValue = 0; - - while (!feof(rgsFile)) - { - switch (buffer[0]) - { - case 'p': - { - // Style property: p - - sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue); - - GuiSetStyle(controlId, propertyId, (int)propertyValue); - - } break; - case 'f': - { - // Style font: f - - int fontSize = 0; - char charmapFileName[256] = { 0 }; - char fontFileName[256] = { 0 }; - sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, fontFileName); - - Font font = { 0 }; - - if (charmapFileName[0] != '0') - { - // Load characters from charmap file, - // expected '\n' separated list of integer values - char *charValues = LoadFileText(charmapFileName); - if (charValues != NULL) - { - int glyphCount = 0; - const char **chars = TextSplit(charValues, '\n', &glyphCount); - - int *values = (int *)RAYGUI_MALLOC(glyphCount*sizeof(int)); - for (int i = 0; i < glyphCount; i++) values[i] = TextToInteger(chars[i]); - - font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, values, glyphCount); - - RAYGUI_FREE(values); - } - } - else font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, NULL, 0); - - if ((font.texture.id > 0) && (font.glyphCount > 0)) GuiSetFont(font); - - } break; - default: break; - } - - fgets(buffer, 256, rgsFile); - } - } - else tryBinary = true; - - fclose(rgsFile); - } - - if (tryBinary) - { - rgsFile = fopen(fileName, "rb"); - - if (rgsFile == NULL) return; - - char signature[5] = ""; - short version = 0; - short reserved = 0; - int propertyCount = 0; - - fread(signature, 1, 4, rgsFile); - fread(&version, 1, sizeof(short), rgsFile); - fread(&reserved, 1, sizeof(short), rgsFile); - fread(&propertyCount, 1, sizeof(int), rgsFile); - - if ((signature[0] == 'r') && - (signature[1] == 'G') && - (signature[2] == 'S') && - (signature[3] == ' ')) - { - short controlId = 0; - short propertyId = 0; - int propertyValue = 0; - - for (int i = 0; i < propertyCount; i++) - { - fread(&controlId, 1, sizeof(short), rgsFile); - fread(&propertyId, 1, sizeof(short), rgsFile); - fread(&propertyValue, 1, sizeof(int), rgsFile); - - if (controlId == 0) // DEFAULT control - { - // If a DEFAULT property is loaded, it is propagated to all controls - // NOTE: All DEFAULT properties should be defined first in the file - GuiSetStyle(0, (int)propertyId, propertyValue); - - if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int i = 1; i < RAYGUI_MAX_CONTROLS; i++) GuiSetStyle(i, (int)propertyId, propertyValue); - } - else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); - } - - // Font loading is highly dependant on raylib API to load font data and image -#if !defined(RAYGUI_STANDALONE) - // Load custom font if available - int fontDataSize = 0; - fread(&fontDataSize, 1, sizeof(int), rgsFile); - - if (fontDataSize > 0) - { - Font font = { 0 }; - int fontType = 0; // 0-Normal, 1-SDF - Rectangle whiteRec = { 0 }; - - fread(&font.baseSize, 1, sizeof(int), rgsFile); - fread(&font.glyphCount, 1, sizeof(int), rgsFile); - fread(&fontType, 1, sizeof(int), rgsFile); - - // Load font white rectangle - fread(&whiteRec, 1, sizeof(Rectangle), rgsFile); - - // Load font image parameters - int fontImageSize = 0; - fread(&fontImageSize, 1, sizeof(int), rgsFile); - - if (fontImageSize > 0) - { - Image imFont = { 0 }; - imFont.mipmaps = 1; - fread(&imFont.width, 1, sizeof(int), rgsFile); - fread(&imFont.height, 1, sizeof(int), rgsFile); - fread(&imFont.format, 1, sizeof(int), rgsFile); - - imFont.data = (unsigned char *)RAYGUI_MALLOC(fontImageSize); - fread(imFont.data, 1, fontImageSize, rgsFile); - - font.texture = LoadTextureFromImage(imFont); - - RAYGUI_FREE(imFont.data); - } - - // Load font recs data - font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); - for (int i = 0; i < font.glyphCount; i++) fread(&font.recs[i], 1, sizeof(Rectangle), rgsFile); - - // Load font chars info data - font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); - for (int i = 0; i < font.glyphCount; i++) - { - fread(&font.glyphs[i].value, 1, sizeof(int), rgsFile); - fread(&font.glyphs[i].offsetX, 1, sizeof(int), rgsFile); - fread(&font.glyphs[i].offsetY, 1, sizeof(int), rgsFile); - fread(&font.glyphs[i].advanceX, 1, sizeof(int), rgsFile); - } - - GuiSetFont(font); - - // Set font texture source rectangle to be used as white texture to draw shapes - // NOTE: This way, all gui can be draw using a single draw call - if ((whiteRec.width != 0) && (whiteRec.height != 0)) SetShapesTexture(font.texture, whiteRec); - } -#endif - } - - fclose(rgsFile); - } -} - -// Load style default over global style -void GuiLoadStyleDefault(void) -{ - // We set this variable first to avoid cyclic function calls - // when calling GuiSetStyle() and GuiGetStyle() - guiStyleLoaded = true; - - // Initialize default LIGHT style property values - GuiSetStyle(DEFAULT, BORDER_COLOR_NORMAL, 0x838383ff); - GuiSetStyle(DEFAULT, BASE_COLOR_NORMAL, 0xc9c9c9ff); - GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, 0x686868ff); - GuiSetStyle(DEFAULT, BORDER_COLOR_FOCUSED, 0x5bb2d9ff); - GuiSetStyle(DEFAULT, BASE_COLOR_FOCUSED, 0xc9effeff); - GuiSetStyle(DEFAULT, TEXT_COLOR_FOCUSED, 0x6c9bbcff); - GuiSetStyle(DEFAULT, BORDER_COLOR_PRESSED, 0x0492c7ff); - GuiSetStyle(DEFAULT, BASE_COLOR_PRESSED, 0x97e8ffff); - GuiSetStyle(DEFAULT, TEXT_COLOR_PRESSED, 0x368bafff); - GuiSetStyle(DEFAULT, BORDER_COLOR_DISABLED, 0xb5c1c2ff); - GuiSetStyle(DEFAULT, BASE_COLOR_DISABLED, 0xe6e9e9ff); - GuiSetStyle(DEFAULT, TEXT_COLOR_DISABLED, 0xaeb7b8ff); - GuiSetStyle(DEFAULT, BORDER_WIDTH, 1); // WARNING: Some controls use other values - GuiSetStyle(DEFAULT, TEXT_PADDING, 0); // WARNING: Some controls use other values - GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_CENTER); // WARNING: Some controls use other values - - // Initialize control-specific property values - // NOTE: Those properties are in default list but require specific values by control type - GuiSetStyle(LABEL, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT); - GuiSetStyle(BUTTON, BORDER_WIDTH, 2); - GuiSetStyle(SLIDER, TEXT_PADDING, 5); - GuiSetStyle(CHECKBOX, TEXT_PADDING, 5); - GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_RIGHT); - GuiSetStyle(TEXTBOX, TEXT_PADDING, 5); - GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT); - GuiSetStyle(VALUEBOX, TEXT_PADDING, 4); - GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT); - GuiSetStyle(SPINNER, TEXT_PADDING, 4); - GuiSetStyle(SPINNER, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT); - GuiSetStyle(STATUSBAR, TEXT_PADDING, 6); - GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, GUI_TEXT_ALIGN_LEFT); - - // Initialize extended property values - // NOTE: By default, extended property values are initialized to 0 - GuiSetStyle(DEFAULT, TEXT_SIZE, 10); // DEFAULT, shared by all controls - GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls - GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property - GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property - GuiSetStyle(TOGGLE, GROUP_PADDING, 2); - GuiSetStyle(SLIDER, SLIDER_WIDTH, 15); - GuiSetStyle(SLIDER, SLIDER_PADDING, 1); - GuiSetStyle(PROGRESSBAR, PROGRESS_PADDING, 1); - GuiSetStyle(CHECKBOX, CHECK_PADDING, 1); - GuiSetStyle(COMBOBOX, COMBO_BUTTON_WIDTH, 30); - GuiSetStyle(COMBOBOX, COMBO_BUTTON_PADDING, 2); - GuiSetStyle(DROPDOWNBOX, ARROW_PADDING, 16); - GuiSetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_PADDING, 2); - GuiSetStyle(TEXTBOX, TEXT_LINES_PADDING, 5); - GuiSetStyle(TEXTBOX, TEXT_INNER_PADDING, 4); - GuiSetStyle(TEXTBOX, COLOR_SELECTED_FG, 0xf0fffeff); - GuiSetStyle(TEXTBOX, COLOR_SELECTED_BG, 0x839affe0); - GuiSetStyle(SPINNER, SPIN_BUTTON_WIDTH, 20); - GuiSetStyle(SPINNER, SPIN_BUTTON_PADDING, 2); - GuiSetStyle(SCROLLBAR, BORDER_WIDTH, 0); - GuiSetStyle(SCROLLBAR, ARROWS_VISIBLE, 0); - GuiSetStyle(SCROLLBAR, ARROWS_SIZE, 6); - GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING, 0); - GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, 16); - GuiSetStyle(SCROLLBAR, SCROLL_PADDING, 0); - GuiSetStyle(SCROLLBAR, SCROLL_SPEED, 10); - GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 0x1e); - GuiSetStyle(LISTVIEW, LIST_ITEMS_PADDING, 2); - GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 10); - GuiSetStyle(LISTVIEW, SCROLLBAR_SIDE, SCROLLBAR_RIGHT_SIDE); - GuiSetStyle(COLORPICKER, COLOR_SELECTOR_SIZE, 6); - GuiSetStyle(COLORPICKER, HUEBAR_WIDTH, 0x14); - GuiSetStyle(COLORPICKER, HUEBAR_PADDING, 0xa); - GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT, 6); - GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW, 2); - - guiFont = GetFontDefault(); // Initialize default font -} - -// Get text with icon id prepended -// NOTE: Useful to add icons by name id (enum) instead of -// a number that can change between ricon versions -const char *GuiIconText(int iconId, const char *text) -{ -#if defined(RAYGUI_NO_RICONS) - return NULL; -#else - static char buffer[1024] = { 0 }; - memset(buffer, 0, 1024); - - sprintf(buffer, "#%03i#", iconId); - - if (text != NULL) - { - for (int i = 5; i < 1024; i++) - { - buffer[i] = text[i - 5]; - if (text[i - 5] == '\0') break; - } - } - - return buffer; -#endif -} - -#if !defined(RAYGUI_NO_RICONS) - -// Get full icons data pointer -unsigned int *GuiGetIcons(void) { return guiIcons; } - -// Load raygui icons file (.rgi) -// NOTE: In case nameIds are required, they can be requested with loadIconsName, -// they are returned as a guiIconsName[iconCount][RICON_MAX_NAME_LENGTH], -// WARNING: guiIconsName[]][] memory should be manually freed! -char **GuiLoadIcons(const char *fileName, bool loadIconsName) -{ - // Style File Structure (.rgi) - // ------------------------------------------------------ - // Offset | Size | Type | Description - // ------------------------------------------------------ - // 0 | 4 | char | Signature: "rGI " - // 4 | 2 | short | Version: 100 - // 6 | 2 | short | reserved - - // 8 | 2 | short | Num icons (N) - // 10 | 2 | short | Icons size (Options: 16, 32, 64) (S) - - // Icons name id (32 bytes per name id) - // foreach (icon) - // { - // 12+32*i | 32 | char | Icon NameId - // } - - // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) - // S*S pixels/32bit per unsigned int = K unsigned int per icon - // foreach (icon) - // { - // ... | K | unsigned int | Icon Data - // } - - FILE *rgiFile = fopen(fileName, "rb"); - - char **guiIconsName = NULL; - - if (rgiFile != NULL) - { - char signature[5] = ""; - short version = 0; - short reserved = 0; - short iconCount = 0; - short iconSize = 0; - - fread(signature, 1, 4, rgiFile); - fread(&version, 1, sizeof(short), rgiFile); - fread(&reserved, 1, sizeof(short), rgiFile); - fread(&iconCount, 1, sizeof(short), rgiFile); - fread(&iconSize, 1, sizeof(short), rgiFile); - - if ((signature[0] == 'r') && - (signature[1] == 'G') && - (signature[2] == 'I') && - (signature[3] == ' ')) - { - if (loadIconsName) - { - guiIconsName = (char **)RAYGUI_MALLOC(iconCount*sizeof(char **)); - for (int i = 0; i < iconCount; i++) - { - guiIconsName[i] = (char *)RAYGUI_MALLOC(RICON_MAX_NAME_LENGTH); - fread(guiIconsName[i], RICON_MAX_NAME_LENGTH, 1, rgiFile); - } - } - else fseek(rgiFile, iconCount*RICON_MAX_NAME_LENGTH, SEEK_CUR); - - // Read icons data directly over guiIcons data array - fread(guiIcons, iconCount*(iconSize*iconSize/32), sizeof(unsigned int), rgiFile); - } - - fclose(rgiFile); - } - - return guiIconsName; -} - -// Draw selected icon using rectangles pixel-by-pixel -void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color) -{ - #define BIT_CHECK(a,b) ((a) & (1<<(b))) - - for (int i = 0, y = 0; i < RICON_SIZE*RICON_SIZE/32; i++) - { - for (int k = 0; k < 32; k++) - { - if (BIT_CHECK(guiIcons[iconId*RICON_DATA_ELEMENTS + i], k)) - { - #if !defined(RAYGUI_STANDALONE) - DrawRectangle(posX + (k%RICON_SIZE)*pixelSize, posY + y*pixelSize, pixelSize, pixelSize, color); - #endif - } - - if ((k == 15) || (k == 31)) y++; - } - } -} - -// Get icon bit data -// NOTE: Bit data array grouped as unsigned int (ICON_SIZE*ICON_SIZE/32 elements) -unsigned int *GuiGetIconData(int iconId) -{ - static unsigned int iconData[RICON_DATA_ELEMENTS] = { 0 }; - memset(iconData, 0, RICON_DATA_ELEMENTS*sizeof(unsigned int)); - - if (iconId < RICON_MAX_ICONS) memcpy(iconData, &guiIcons[iconId*RICON_DATA_ELEMENTS], RICON_DATA_ELEMENTS*sizeof(unsigned int)); - - return iconData; -} - -// Set icon bit data -// NOTE: Data must be provided as unsigned int array (ICON_SIZE*ICON_SIZE/32 elements) -void GuiSetIconData(int iconId, unsigned int *data) -{ - if (iconId < RICON_MAX_ICONS) memcpy(&guiIcons[iconId*RICON_DATA_ELEMENTS], data, RICON_DATA_ELEMENTS*sizeof(unsigned int)); -} - -// Set icon pixel value -void GuiSetIconPixel(int iconId, int x, int y) -{ - #define BIT_SET(a,b) ((a) |= (1<<(b))) - - // This logic works for any RICON_SIZE pixels icons, - // For example, in case of 16x16 pixels, every 2 lines fit in one unsigned int data element - BIT_SET(guiIcons[iconId*RICON_DATA_ELEMENTS + y/(sizeof(unsigned int)*8/RICON_SIZE)], x + (y%(sizeof(unsigned int)*8/RICON_SIZE)*RICON_SIZE)); -} - -// Clear icon pixel value -void GuiClearIconPixel(int iconId, int x, int y) -{ - #define BIT_CLEAR(a,b) ((a) &= ~((1)<<(b))) - - // This logic works for any RICON_SIZE pixels icons, - // For example, in case of 16x16 pixels, every 2 lines fit in one unsigned int data element - BIT_CLEAR(guiIcons[iconId*RICON_DATA_ELEMENTS + y/(sizeof(unsigned int)*8/RICON_SIZE)], x + (y%(sizeof(unsigned int)*8/RICON_SIZE)*RICON_SIZE)); -} - -// Check icon pixel value -bool GuiCheckIconPixel(int iconId, int x, int y) -{ - #define BIT_CHECK(a,b) ((a) & (1<<(b))) - - return (BIT_CHECK(guiIcons[iconId*8 + y/2], x + (y%2*16))); -} -#endif // !RAYGUI_NO_RICONS - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- -// Gui get text width using default font -// NOTE: Icon is not considered here -static int GetTextWidth(const char *text) -{ - Vector2 size = { 0 }; - - if ((text != NULL) && (text[0] != '\0')) - { - size = MeasureTextEx(guiFont, text, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); - } - - return (int)size.x; -} - -// Get text bounds considering control bounds -static Rectangle GetTextBounds(int control, Rectangle bounds) -{ - Rectangle textBounds = bounds; - - textBounds.x = bounds.x + GuiGetStyle(control, BORDER_WIDTH); - textBounds.y = bounds.y + GuiGetStyle(control, BORDER_WIDTH); - textBounds.width = bounds.width - 2*GuiGetStyle(control, BORDER_WIDTH); - textBounds.height = bounds.height - 2*GuiGetStyle(control, BORDER_WIDTH); - - // Consider TEXT_PADDING properly, depends on control type and TEXT_ALIGNMENT - switch (control) - { - case COMBOBOX: bounds.width -= (GuiGetStyle(control, COMBO_BUTTON_WIDTH) + GuiGetStyle(control, COMBO_BUTTON_PADDING)); break; - case VALUEBOX: break; // NOTE: ValueBox text value always centered, text padding applies to label - default: - { - if (GuiGetStyle(control, TEXT_ALIGNMENT) == GUI_TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING); - else textBounds.x += GuiGetStyle(control, TEXT_PADDING); - } break; - } - - // TODO: Special cases (no label): COMBOBOX, DROPDOWNBOX, LISTVIEW (scrollbar?) - // More special cases (label on side): CHECKBOX, SLIDER, VALUEBOX, SPINNER - - return textBounds; -} - -// Get text icon if provided and move text cursor -// NOTE: We support up to 999 values for iconId -static const char *GetTextIcon(const char *text, int *iconId) -{ -#if !defined(RAYGUI_NO_RICONS) - *iconId = -1; - if (text[0] == '#') // Maybe we have an icon! - { - char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0' - - int pos = 1; - while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9')) - { - iconValue[pos - 1] = text[pos]; - pos++; - } - - if (text[pos] == '#') - { - *iconId = TextToInteger(iconValue); - - // Move text pointer after icon - // WARNING: If only icon provided, it could point to EOL character: '\0' - if (*iconId >= 0) text += (pos + 1); - } - } -#endif - - return text; -} - -// Gui draw text using default font -static void GuiDrawText(const char *text, Rectangle bounds, int alignment, Color tint) -{ - #define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect - - if ((text != NULL) && (text[0] != '\0')) - { - int iconId = 0; - text = GetTextIcon(text, &iconId); // Check text for icon and move cursor - - // Get text position depending on alignment and iconId - //--------------------------------------------------------------------------------- - #define RICON_TEXT_PADDING 4 - - Vector2 position = { bounds.x, bounds.y }; - - // NOTE: We get text size after icon has been processed - int textWidth = GetTextWidth(text); - int textHeight = GuiGetStyle(DEFAULT, TEXT_SIZE); - - // If text requires an icon, add size to measure - if (iconId >= 0) - { - textWidth += RICON_SIZE; - - // WARNING: If only icon provided, text could be pointing to EOF character: '\0' - if ((text != NULL) && (text[0] != '\0')) textWidth += RICON_TEXT_PADDING; - } - - // Check guiTextAlign global variables - switch (alignment) - { - case GUI_TEXT_ALIGN_LEFT: - { - position.x = bounds.x; - position.y = bounds.y + bounds.height/2 - textHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height); - } break; - case GUI_TEXT_ALIGN_CENTER: - { - position.x = bounds.x + bounds.width/2 - textWidth/2; - position.y = bounds.y + bounds.height/2 - textHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height); - } break; - case GUI_TEXT_ALIGN_RIGHT: - { - position.x = bounds.x + bounds.width - textWidth; - position.y = bounds.y + bounds.height/2 - textHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height); - } break; - default: break; - } - - // NOTE: Make sure we get pixel-perfect coordinates, - // In case of decimals we got weird text positioning - position.x = (float)((int)position.x); - position.y = (float)((int)position.y); - //--------------------------------------------------------------------------------- - - // Draw text (with icon if available) - //--------------------------------------------------------------------------------- -#if !defined(RAYGUI_NO_RICONS) - if (iconId >= 0) - { - // NOTE: We consider icon height, probably different than text size - GuiDrawIcon(iconId, (int)position.x, (int)(bounds.y + bounds.height/2 - RICON_SIZE/2 + TEXT_VALIGN_PIXEL_OFFSET(bounds.height)), 1, tint); - position.x += (RICON_SIZE + RICON_TEXT_PADDING); - } -#endif - DrawTextEx(guiFont, text, position, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING), tint); - //--------------------------------------------------------------------------------- - } -} - -// Gui draw rectangle using default raygui plain style with borders -static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color) -{ - if (color.a > 0) - { - // Draw rectangle filled with color - DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, color); - } - - if (borderWidth > 0) - { - // Draw rectangle border lines with color - DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, borderWidth, borderColor); - DrawRectangle((int)rec.x, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, borderColor); - DrawRectangle((int)rec.x + (int)rec.width - borderWidth, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, borderColor); - DrawRectangle((int)rec.x, (int)rec.y + (int)rec.height - borderWidth, (int)rec.width, borderWidth, borderColor); - } -} - -// Split controls text into multiple strings -// Also check for multiple columns (required by GuiToggleGroup()) -static const char **GuiTextSplit(const char *text, int *count, int *textRow) -{ - // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) - // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, - // all used memory is static... it has some limitations: - // 1. Maximum number of possible split strings is set by TEXTSPLIT_MAX_TEXT_ELEMENTS - // 2. Maximum size of text to split is TEXTSPLIT_MAX_TEXT_LENGTH - // NOTE: Those definitions could be externally provided if required - - #if !defined(TEXTSPLIT_MAX_TEXT_LENGTH) - #define TEXTSPLIT_MAX_TEXT_LENGTH 1024 - #endif - - #if !defined(TEXTSPLIT_MAX_TEXT_ELEMENTS) - #define TEXTSPLIT_MAX_TEXT_ELEMENTS 128 - #endif - - static const char *result[TEXTSPLIT_MAX_TEXT_ELEMENTS] = { NULL }; - static char buffer[TEXTSPLIT_MAX_TEXT_LENGTH] = { 0 }; - memset(buffer, 0, TEXTSPLIT_MAX_TEXT_LENGTH); - - result[0] = buffer; - int counter = 1; - - if (textRow != NULL) textRow[0] = 0; - - // Count how many substrings we have on text and point to every one - for (int i = 0; i < TEXTSPLIT_MAX_TEXT_LENGTH; i++) - { - buffer[i] = text[i]; - if (buffer[i] == '\0') break; - else if ((buffer[i] == ';') || (buffer[i] == '\n')) - { - result[counter] = buffer + i + 1; - - if (textRow != NULL) - { - if (buffer[i] == '\n') textRow[counter] = textRow[counter - 1] + 1; - else textRow[counter] = textRow[counter - 1]; - } - - buffer[i] = '\0'; // Set an end of string at this point - - counter++; - if (counter == TEXTSPLIT_MAX_TEXT_ELEMENTS) break; - } - } - - *count = counter; - - return result; -} - -// Convert color data from RGB to HSV -// NOTE: Color data should be passed normalized -static Vector3 ConvertRGBtoHSV(Vector3 rgb) -{ - Vector3 hsv = { 0 }; - float min = 0.0f; - float max = 0.0f; - float delta = 0.0f; - - min = (rgb.x < rgb.y)? rgb.x : rgb.y; - min = (min < rgb.z)? min : rgb.z; - - max = (rgb.x > rgb.y)? rgb.x : rgb.y; - max = (max > rgb.z)? max : rgb.z; - - hsv.z = max; // Value - delta = max - min; - - if (delta < 0.00001f) - { - hsv.y = 0.0f; - hsv.x = 0.0f; // Undefined, maybe NAN? - return hsv; - } - - if (max > 0.0f) - { - // NOTE: If max is 0, this divide would cause a crash - hsv.y = (delta/max); // Saturation - } - else - { - // NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined - hsv.y = 0.0f; - hsv.x = 0.0f; // Undefined, maybe NAN? - return hsv; - } - - // NOTE: Comparing float values could not work properly - if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta - else - { - if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow - else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan - } - - hsv.x *= 60.0f; // Convert to degrees - - if (hsv.x < 0.0f) hsv.x += 360.0f; - - return hsv; -} - -// Convert color data from HSV to RGB -// NOTE: Color data should be passed normalized -static Vector3 ConvertHSVtoRGB(Vector3 hsv) -{ - Vector3 rgb = { 0 }; - float hh = 0.0f, p = 0.0f, q = 0.0f, t = 0.0f, ff = 0.0f; - long i = 0; - - // NOTE: Comparing float values could not work properly - if (hsv.y <= 0.0f) - { - rgb.x = hsv.z; - rgb.y = hsv.z; - rgb.z = hsv.z; - return rgb; - } - - hh = hsv.x; - if (hh >= 360.0f) hh = 0.0f; - hh /= 60.0f; - - i = (long)hh; - ff = hh - i; - p = hsv.z*(1.0f - hsv.y); - q = hsv.z*(1.0f - (hsv.y*ff)); - t = hsv.z*(1.0f - (hsv.y*(1.0f - ff))); - - switch (i) - { - case 0: - { - rgb.x = hsv.z; - rgb.y = t; - rgb.z = p; - } break; - case 1: - { - rgb.x = q; - rgb.y = hsv.z; - rgb.z = p; - } break; - case 2: - { - rgb.x = p; - rgb.y = hsv.z; - rgb.z = t; - } break; - case 3: - { - rgb.x = p; - rgb.y = q; - rgb.z = hsv.z; - } break; - case 4: - { - rgb.x = t; - rgb.y = p; - rgb.z = hsv.z; - } break; - case 5: - default: - { - rgb.x = hsv.z; - rgb.y = p; - rgb.z = q; - } break; - } - - return rgb; -} - -#if defined(RAYGUI_STANDALONE) -// Returns a Color struct from hexadecimal value -static Color GetColor(int hexValue) -{ - Color color; - - color.r = (unsigned char)(hexValue >> 24) & 0xFF; - color.g = (unsigned char)(hexValue >> 16) & 0xFF; - color.b = (unsigned char)(hexValue >> 8) & 0xFF; - color.a = (unsigned char)hexValue & 0xFF; - - return color; -} - -// Returns hexadecimal value for a Color -static int ColorToInt(Color color) -{ - return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a); -} - -// Check if point is inside rectangle -static bool CheckCollisionPointRec(Vector2 point, Rectangle rec) -{ - bool collision = false; - - if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) && - (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true; - - return collision; -} - -// Color fade-in or fade-out, alpha goes from 0.0f to 1.0f -static Color Fade(Color color, float alpha) -{ - if (alpha < 0.0f) alpha = 0.0f; - else if (alpha > 1.0f) alpha = 1.0f; - - Color result = { color.r, color.g, color.b, (unsigned char)(255.0f*alpha) }; - - return result; -} - -// Formatting of text with variables to 'embed' -static const char *TextFormat(const char *text, ...) -{ - #define MAX_FORMATTEXT_LENGTH 64 - - static char buffer[MAX_FORMATTEXT_LENGTH]; - - va_list args; - va_start(args, text); - vsprintf(buffer, text, args); - va_end(args); - - return buffer; -} - -// Draw rectangle with vertical gradient fill color -// NOTE: This function is only used by GuiColorPicker() -static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2) -{ - Rectangle bounds = { (float)posX, (float)posY, (float)width, (float)height }; - DrawRectangleGradientEx(bounds, color1, color2, color2, color1); -} - -#define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH 1024 // Size of static buffer: TextSplit() -#define TEXTSPLIT_MAX_SUBSTRINGS_COUNT 128 // Size of static pointers array: TextSplit() - -// Split string into multiple strings -const char **TextSplit(const char *text, char delimiter, int *count) -{ - // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) - // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, - // all used memory is static... it has some limitations: - // 1. Maximum number of possible split strings is set by TEXTSPLIT_MAX_SUBSTRINGS_COUNT - // 2. Maximum size of text to split is TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH - - static const char *result[TEXTSPLIT_MAX_SUBSTRINGS_COUNT] = { NULL }; - static char buffer[TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH] = { 0 }; - memset(buffer, 0, TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH); - - result[0] = buffer; - int counter = 0; - - if (text != NULL) - { - counter = 1; - - // Count how many substrings we have on text and point to every one - for (int i = 0; i < TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH; i++) - { - buffer[i] = text[i]; - if (buffer[i] == '\0') break; - else if (buffer[i] == delimiter) - { - buffer[i] = '\0'; // Set an end of string at this point - result[counter] = buffer + i + 1; - counter++; - - if (counter == TEXTSPLIT_MAX_SUBSTRINGS_COUNT) break; - } - } - } - - *count = counter; - return result; -} - -// Get integer value from text -// NOTE: This function replaces atoi() [stdlib.h] -static int TextToInteger(const char *text) -{ - int value = 0; - int sign = 1; - - if ((text[0] == '+') || (text[0] == '-')) - { - if (text[0] == '-') sign = -1; - text++; - } - - for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0'); - - return value*sign; -} - -// Encode codepoint into UTF-8 text (char array size returned as parameter) -static const char *CodepointToUTF8(int codepoint, int *byteSize) -{ - static char utf8[6] = { 0 }; - int size = 0; - - if (codepoint <= 0x7f) - { - utf8[0] = (char)codepoint; - size = 1; - } - else if (codepoint <= 0x7ff) - { - utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0); - utf8[1] = (char)((codepoint & 0x3f) | 0x80); - size = 2; - } - else if (codepoint <= 0xffff) - { - utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0); - utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80); - utf8[2] = (char)((codepoint & 0x3f) | 0x80); - size = 3; - } - else if (codepoint <= 0x10ffff) - { - utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0); - utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80); - utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80); - utf8[3] = (char)((codepoint & 0x3f) | 0x80); - size = 4; - } - - *byteSize = size; - - return utf8; -} - -// Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found -// When a invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned -// Total number of bytes processed are returned as a parameter -// NOTE: the standard says U+FFFD should be returned in case of errors -// but that character is not supported by the default font in raylib -static int GetCodepoint(const char *text, int *bytesProcessed) -{ -/* - UTF-8 specs from https://www.ietf.org/rfc/rfc3629.txt - - Char. number range | UTF-8 octet sequence - (hexadecimal) | (binary) - --------------------+--------------------------------------------- - 0000 0000-0000 007F | 0xxxxxxx - 0000 0080-0000 07FF | 110xxxxx 10xxxxxx - 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx - 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx -*/ - // NOTE: on decode errors we return as soon as possible - - int code = 0x3f; // Codepoint (defaults to '?') - int octet = (unsigned char)(text[0]); // The first UTF8 octet - *bytesProcessed = 1; - - if (octet <= 0x7f) - { - // Only one octet (ASCII range x00-7F) - code = text[0]; - } - else if ((octet & 0xe0) == 0xc0) - { - // Two octets - - // [0]xC2-DF [1]UTF8-tail(x80-BF) - unsigned char octet1 = text[1]; - - if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence - - if ((octet >= 0xc2) && (octet <= 0xdf)) - { - code = ((octet & 0x1f) << 6) | (octet1 & 0x3f); - *bytesProcessed = 2; - } - } - else if ((octet & 0xf0) == 0xe0) - { - // Three octets - unsigned char octet1 = text[1]; - unsigned char octet2 = '\0'; - - if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence - - octet2 = text[2]; - - if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; } // Unexpected sequence - - // [0]xE0 [1]xA0-BF [2]UTF8-tail(x80-BF) - // [0]xE1-EC [1]UTF8-tail [2]UTF8-tail(x80-BF) - // [0]xED [1]x80-9F [2]UTF8-tail(x80-BF) - // [0]xEE-EF [1]UTF8-tail [2]UTF8-tail(x80-BF) - - if (((octet == 0xe0) && !((octet1 >= 0xa0) && (octet1 <= 0xbf))) || - ((octet == 0xed) && !((octet1 >= 0x80) && (octet1 <= 0x9f)))) { *bytesProcessed = 2; return code; } - - if ((octet >= 0xe0) && (0 <= 0xef)) - { - code = ((octet & 0xf) << 12) | ((octet1 & 0x3f) << 6) | (octet2 & 0x3f); - *bytesProcessed = 3; - } - } - else if ((octet & 0xf8) == 0xf0) - { - // Four octets - if (octet > 0xf4) return code; - - unsigned char octet1 = text[1]; - unsigned char octet2 = '\0'; - unsigned char octet3 = '\0'; - - if ((octet1 == '\0') || ((octet1 >> 6) != 2)) { *bytesProcessed = 2; return code; } // Unexpected sequence - - octet2 = text[2]; - - if ((octet2 == '\0') || ((octet2 >> 6) != 2)) { *bytesProcessed = 3; return code; } // Unexpected sequence - - octet3 = text[3]; - - if ((octet3 == '\0') || ((octet3 >> 6) != 2)) { *bytesProcessed = 4; return code; } // Unexpected sequence - - // [0]xF0 [1]x90-BF [2]UTF8-tail [3]UTF8-tail - // [0]xF1-F3 [1]UTF8-tail [2]UTF8-tail [3]UTF8-tail - // [0]xF4 [1]x80-8F [2]UTF8-tail [3]UTF8-tail - - if (((octet == 0xf0) && !((octet1 >= 0x90) && (octet1 <= 0xbf))) || - ((octet == 0xf4) && !((octet1 >= 0x80) && (octet1 <= 0x8f)))) { *bytesProcessed = 2; return code; } // Unexpected sequence - - if (octet >= 0xf0) - { - code = ((octet & 0x7) << 18) | ((octet1 & 0x3f) << 12) | ((octet2 & 0x3f) << 6) | (octet3 & 0x3f); - *bytesProcessed = 4; - } - } - - if (code > 0x10ffff) code = 0x3f; // Codepoints after U+10ffff are invalid - - return code; -} -#endif // RAYGUI_STANDALONE - -#endif // RAYGUI_IMPLEMENTATION diff --git a/include/raylib.h b/include/raylib.h deleted file mode 100644 index 7a7711d..0000000 --- a/include/raylib.h +++ /dev/null @@ -1,1621 +0,0 @@ -/********************************************************************************************** -* -* raylib v4.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, FreeBSD, OpenBSD, NetBSD, DragonFly, -* MacOS, Haiku, Android, Raspberry Pi, DRM native, HTML5. -* - Written in plain C code (C99) in PascalCase/camelCase notation -* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3, 4.3 or ES2 - choose at compile) -* - Unique OpenGL abstraction layer (usable as standalone module): [rlgl] -* - Multiple Fonts formats supported (TTF, XNA fonts, AngelCode fonts) -* - Outstanding texture formats support, 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) -* - 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, 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 (included): -* [rcore] rglfw (Camilla Löwy - github.com/glfw/glfw) for window/context management and input (PLATFORM_DESKTOP) -* [rlgl] glad (David Herberth - github.com/Dav1dde/glad) for OpenGL 3.3 extensions loading (PLATFORM_DESKTOP) -* [raudio] miniaudio (David Reid - github.com/mackron/miniaudio) for audio device/context management -* -* OPTIONAL DEPENDENCIES (included): -* [rcore] msf_gif (Miles Fogle) for GIF recording -* [rcore] sinfl (Micha Mettke) for DEFLATE decompression algorythm -* [rcore] sdefl (Micha Mettke) for DEFLATE compression algorythm -* [rtextures] stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...) -* [rtextures] stb_image_write (Sean Barret) for image writing (BMP, TGA, PNG, JPG) -* [rtextures] stb_image_resize (Sean Barret) for image resizing algorithms -* [rtext] stb_truetype (Sean Barret) for ttf fonts loading -* [rtext] stb_rect_pack (Sean Barret) 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) -* [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 Barret) for OGG audio loading -* [raudio] jar_xm (Joshua Reisenauer) for XM audio module loading -* [raudio] jar_mod (Joshua Reisenauer) for MOD audio module loading -* -* -* 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-2021 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 "4.0" - -// Function specifiers in case library is build/used as a shared library (Windows) -// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll -#if defined(_WIN32) -#if defined(BUILD_LIBTYPE_SHARED) -#define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) -#elif defined(USE_LIBTYPE_SHARED) -#define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) -#endif -#endif - -#ifndef RLAPI -#define RLAPI // Functions defined as 'extern' by default (implicit specifiers) -#endif - -//---------------------------------------------------------------------------------- -// Some basic Defines -//---------------------------------------------------------------------------------- -#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 -#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 { } -#if defined(__cplusplus) -#define CLITERAL(type) type -#else -#define CLITERAL(type) (type) -#endif - -// NOTE: We 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 very 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) - -//---------------------------------------------------------------------------------- -// Structures Definition -//---------------------------------------------------------------------------------- -// Boolean type -#if defined(__STDC__) && __STDC_VERSION__ >= 199901L -#include -#elif !defined(__cplusplus) && !defined(bool) -typedef enum bool -{ - false, - true -} 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 apperture in Y (degrees) in perspective, used as near plane width 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 (displacement from target) - Vector2 target; // Camera target (rotation and zoom origin) - float rotation; // Camera rotation in degrees - float zoom; // Camera zoom (scaling), should be 1.0f by default -} 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 second texture coordinates (useful for lightmaps) (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) - - // Animation vertex data - float *animVertices; // Animated vertex positions (after bones transformations) - float *animNormals; // Animated normals (after bones transformations) - unsigned char *boneIds; // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) - float *boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning) - - // 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, vectex transformation data -typedef struct Transform -{ - Vector3 translation; // Translation - Quaternion rotation; // Rotation - Vector3 scale; // Scale -} Transform; - -// Bone, skeletal animation bone -typedef struct BoneInfo -{ - char name[32]; // Bone name - int parent; // Bone parent -} BoneInfo; - -// 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 - int boneCount; // Number of bones - BoneInfo *bones; // Bones information (skeleton) - Transform *bindPose; // Bones base transformation (pose) -} Model; - -// ModelAnimation -typedef struct ModelAnimation -{ - int boneCount; // Number of bones - int frameCount; // Number of animation frames - BoneInfo *bones; // Bones information (skeleton) - Transform **framePoses; // Poses array by frame -} ModelAnimation; - -// Ray, ray for raycasting -typedef struct Ray -{ - Vector3 position; // Ray position (origin) - Vector3 direction; // Ray direction -} Ray; - -// RayCollision, ray hit information -typedef struct RayCollision -{ - bool hit; // Did the ray hit something? - float distance; // Distance to nearest hit - Vector3 point; // Point of 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; - -typedef struct rAudioBuffer rAudioBuffer; - -// AudioStream, custom audio stream -typedef struct AudioStream -{ - rAudioBuffer *buffer; // Pointer to internal data used by the audio system - - 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 vScreenCenter; // Screen center 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; - -//---------------------------------------------------------------------------------- -// 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_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 = 82, // 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 fordward (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 omni-directional 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, just 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: Square, Xbox: X) - 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: Circle, Xbox: B) - 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 (one), 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 axis -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 -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: height - 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 -} 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_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_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, just pixel aproximation - 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 an 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 - CUBEMAP_LAYOUT_PANORAMA // Layout is defined by a panorama image (equirectangular map) -} 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_CUSTOM // Belnd textures using custom src/dst factors (use rlSetBlendMode()) -} BlendMode; - -// Gesture -// NOTE: It could be used as flags to enable only some 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, // Custom camera - CAMERA_FREE, // Free camera - CAMERA_ORBITAL, // Orbital camera - CAMERA_FIRST_PERSON, // First person camera - CAMERA_THIRD_PERSON // Third person camera -} 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: This callbacks are intended for advance users -typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args); // Logging: Redirect trace log messages -typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, unsigned int *bytesRead); // FileIO: Load binary data -typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, unsigned int bytesToWrite); // FileIO: Save binary data -typedef char *(*LoadFileTextCallback)(const char *fileName); // FileIO: Load text data -typedef bool (*SaveFileTextCallback)(const char *fileName, 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 bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed - RLAPI void CloseWindow(void); // Close window and unload OpenGL context - 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 (only PLATFORM_DESKTOP) - RLAPI bool IsWindowMinimized(void); // Check if window is currently minimized (only PLATFORM_DESKTOP) - RLAPI bool IsWindowMaximized(void); // Check if window is currently maximized (only PLATFORM_DESKTOP) - RLAPI bool IsWindowFocused(void); // Check if window is currently focused (only PLATFORM_DESKTOP) - 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 (only PLATFORM_DESKTOP) - RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable (only PLATFORM_DESKTOP) - RLAPI void MinimizeWindow(void); // Set window state: minimized, if resizable (only PLATFORM_DESKTOP) - RLAPI void RestoreWindow(void); // Set window state: not minimized/maximized (only PLATFORM_DESKTOP) - RLAPI void SetWindowIcon(Image image); // Set icon for window (only PLATFORM_DESKTOP) - RLAPI void SetWindowTitle(const char *title); // Set title for window (only PLATFORM_DESKTOP) - RLAPI void SetWindowPosition(int x, int y); // Set window position on screen (only PLATFORM_DESKTOP) - RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window (fullscreen mode) - RLAPI void SetWindowMinSize(int width, int height); // Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE) - RLAPI void SetWindowSize(int width, int height); // Set window dimensions - 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 GetMonitorCount(void); // Get number of connected monitors - RLAPI int GetCurrentMonitor(void); // Get current connected monitor - RLAPI Vector2 GetMonitorPosition(int monitor); // Get specified monitor position - RLAPI int GetMonitorWidth(int monitor); // Get specified monitor width (max available by monitor) - RLAPI int GetMonitorHeight(int monitor); // Get specified monitor height (max available 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 primary monitor - RLAPI void SetClipboardText(const char *text); // Set clipboard text content - RLAPI const char *GetClipboardText(void); // Get clipboard text content - - // Custom frame control functions - // NOTE: Those functions are intended for advance users that want full control over the frame processing - // By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timming + 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(float ms); // Wait for some milliseconds (halt program execution) - - // 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 - // End custom shader drawing (use default shader) - RLAPI void EndShaderMode(void); - 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 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 for texture (sampler2d) - RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) - - // Screen-space-related functions - RLAPI Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Get a ray trace from mouse position - RLAPI Matrix GetCameraMatrix(Camera camera); // Get camera transform matrix (view matrix) - RLAPI Matrix GetCameraMatrix2D(Camera2D camera); // Get camera 2d transform matrix - 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 - - // Timing-related functions - RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum) - RLAPI int GetFPS(void); // Get current FPS - 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() - - // Misc. functions - RLAPI int GetRandomValue(int min, int max); // Get a random value between min and max (both included) - RLAPI void SetRandomSeed(unsigned int seed); // Set the seed for the random number generator - 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 TraceLog(int logLevel, const char *text, ...); // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...) - RLAPI void SetTraceLogLevel(int logLevel); // Set the current threshold (minimum) log level - RLAPI void *MemAlloc(int size); // Internal memory allocator - RLAPI void *MemRealloc(void *ptr, int size); // Internal memory reallocator - RLAPI void MemFree(void *ptr); // Internal memory free - - // Set custom callbacks - // WARNING: Callbacks setup is intended for advance users - RLAPI void SetTraceLogCallback(TraceLogCallback callback); // Set custom trace log - 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 - - // Files management functions - RLAPI unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead); // 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, unsigned int bytesToWrite); // Save data to file from byte array (write), 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, char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success - 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 (including point: .png, .wav) - 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 char **GetDirectoryFiles(const char *dirPath, int *count); // Get filenames in a directory path (memory should be freed) - RLAPI void ClearDirectoryFiles(void); // Clear directory files paths buffers (free memory) - RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success - RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window - RLAPI char **GetDroppedFiles(int *count); // Get dropped files names (memory should be freed) - RLAPI void ClearDroppedFiles(void); // Clear dropped files paths buffer (free memory) - RLAPI long GetFileModTime(const char *fileName); // Get file modification time (last write time) - - // Compression/Encoding functionality - RLAPI unsigned char *CompressData(unsigned char *data, int dataLength, int *compDataLength); // Compress data (DEFLATE algorithm) - RLAPI unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *dataLength); // Decompress data (DEFLATE algorithm) - RLAPI char *EncodeDataBase64(const unsigned char *data, int dataLength, int *outputLength); // Encode data to Base64 string - RLAPI unsigned char *DecodeDataBase64(unsigned char *data, int *outputLength); // Decode Base64 string data - - // Persistent storage management - RLAPI bool SaveStorageValue(unsigned int position, int value); // Save integer value to storage file (to defined position), returns true on success - RLAPI int LoadStorageValue(unsigned int position); // Load integer value from storage file (from defined position) - - RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available) - - //------------------------------------------------------------------------------------ - // Input Handling Functions (Module: core) - //------------------------------------------------------------------------------------ - - // Input-related functions: keyboard - RLAPI bool IsKeyPressed(int key); // Check if a key has been pressed once - 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 void SetExitKey(int key); // Set a custom key to exit program (default is ESC) - 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 - - // 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 gamepad axis count for a gamepad - RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Get axis movement value for a gamepad axis - RLAPI int SetGamepadMappings(const char *mappings); // Set internal gamepad mappings (SDL_GameControllerDB) - - // 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 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(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 milliseconds - 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 SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available) - RLAPI void UpdateCamera(Camera *camera); // Update camera position for selected mode - - RLAPI void SetCameraPanControl(int keyPan); // Set camera pan key to combine with mouse movement (free camera) - RLAPI void SetCameraAltControl(int keyAlt); // Set camera alt key to combine with mouse movement (free camera) - RLAPI void SetCameraSmoothZoomControl(int keySmoothZoom); // Set camera smooth zoom key to combine with mouse (free camera) - RLAPI void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras) - - //------------------------------------------------------------------------------------ - // 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 - - // Basic shapes drawing functions - RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel - RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel (Vector version) - 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 (Vector version) - RLAPI void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line defining thickness - RLAPI void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line using cubic-bezier curves in-out - RLAPI void DrawLineBezierQuad(Vector2 startPos, Vector2 endPos, Vector2 controlPos, float thick, Color color); // Draw line using quadratic bezier curves with a control point - RLAPI void DrawLineBezierCubic(Vector2 startPos, Vector2 endPos, Vector2 startControlPos, Vector2 endControlPos, float thick, Color color); // Draw line using cubic bezier curves with 2 control points - RLAPI void DrawLineStrip(Vector2 *points, int pointCount, Color color); // Draw lines sequence - RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color); // Draw a color-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 DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2); // Draw a gradient-filled circle - RLAPI void DrawCircleV(Vector2 center, float radius, Color color); // Draw a color-filled circle (Vector version) - RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline - RLAPI void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse - RLAPI void DrawEllipseLines(int centerX, int centerY, float radiusH, float radiusV, Color color); // Draw ellipse outline - 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 color1, Color color2); // Draw a vertical-gradient-filled rectangle - RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2); // Draw a horizontal-gradient-filled rectangle - RLAPI void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // 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, 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(Vector2 *points, int pointCount, Color color); // Draw a triangle fan defined by points (first vertex is the center) - RLAPI void DrawTriangleStrip(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 - - // 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 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 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 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 Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); // Get collision rectangle for two rectangles collision - - //------------------------------------------------------------------------------------ - // Texture Loading and Drawing Functions (Module: textures) - //------------------------------------------------------------------------------------ - - // Image loading functions - // NOTE: This 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 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 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 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 GenImageGradientV(int width, int height, Color top, Color bottom); // Generate image: vertical gradient - RLAPI Image GenImageGradientH(int width, int height, Color left, Color right); // Generate image: horizontal gradient - RLAPI Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer); // Generate image: radial 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 GenImageCellular(int width, int height, int tileSize); // Generate image: cellular algorithm, bigger tileSize means bigger cells - - // 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 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 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 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 ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color); // Draw circle within an image - RLAPI void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color); // Draw circle 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 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 void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) - 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 - RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data - - // 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 DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint); // Draw texture quad with tiling and offset parameters - RLAPI void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, float scale, Color tint); // Draw part of a texture (defined by a rectangle) with rotation and scale tiled into dest. - 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 - RLAPI void DrawTexturePoly(Texture2D texture, Vector2 center, Vector2 *points, Vector2 *texcoords, int pointCount, Color tint); // Draw a textured polygon - - // Color/pixel related functions - 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 - 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 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 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, int *fontChars, int glyphCount); // Load font from file with extended parameters - 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, int *fontChars, int glyphCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf' - RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount, int type); // Load font data for further use - RLAPI Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **recs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info - RLAPI void UnloadFontData(GlyphInfo *chars, int glyphCount); // Unload font chars info data (RAM) - RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM) - - // 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) - - // Text font info functions - 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 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 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 *bytesProcessed); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure - RLAPI const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode one codepoint into UTF-8 byte array (array length returned as parameter) - RLAPI char *TextCodepointsToUTF8(int *codepoints, int length); // Encode text as codepoints array into UTF-8 text string (WARNING: memory must be freed!) - - // Text strings management functions (no UTF-8 strings, only byte chars) - // NOTE: Some strings allocate memory internally for returned strings, just be careful! - 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 char *TextReplace(char *text, const char *replace, const char *by); // Replace text string (WARNING: memory must be freed!) - RLAPI char *TextInsert(const char *text, const char *insert, int position); // Insert text in a position (WARNING: memory must be freed!) - RLAPI const char *TextJoin(const char **textList, int count, const char *delimiter); // Join text strings with delimiter - RLAPI const char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple 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 *find); // Find first text occurrence within a string - RLAPI const char *TextToUpper(const char *text); // Get upper case version of provided string - RLAPI const char *TextToLower(const char *text); // Get lower case version of provided string - RLAPI const char *TextToPascal(const char *text); // Get Pascal case notation version of provided string - RLAPI int TextToInteger(const char *text); // Get integer value from text (negative values not supported) - - //------------------------------------------------------------------------------------ - // 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(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 DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color); // Draw cube textured - RLAPI void DrawCubeTextureRec(Texture2D texture, Rectangle source, Vector3 position, float width, float height, float length, Color color); // Draw cube with a region of a texture - 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 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 void UnloadModel(Model model); // Unload model (including meshes) from memory (RAM and/or VRAM) - RLAPI void UnloadModelKeepMeshes(Model model); // Unload model (but not 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 size, 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, 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, Matrix *transforms, int instances); // Draw multiple mesh instances with material and different transforms - RLAPI bool ExportMesh(Mesh mesh, const char *fileName); // Export mesh data to file, returns true on success - RLAPI BoundingBox GetMeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits - RLAPI void GenMeshTangents(Mesh *mesh); // Compute mesh tangents - RLAPI void GenMeshBinormals(Mesh *mesh); // Compute mesh binormals - - // 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 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, unsigned int *animCount); // Load model animations from file - RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); // Update model animation pose - RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data - RLAPI void UnloadModelAnimations(ModelAnimation *animations, unsigned int count); // 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 GetRayCollisionModel(Ray ray, Model model); // Get collision info between ray and model - 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) - //------------------------------------------------------------------------------------ - - // 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) - - // 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 Sound LoadSound(const char *fileName); // Load sound from file - RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data - RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data - RLAPI void UnloadWave(Wave wave); // Unload wave data - RLAPI void UnloadSound(Sound sound); // Unload sound - 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 void PlaySoundMulti(Sound sound); // Play a sound (using multichannel buffer pool) - RLAPI void StopSoundMulti(void); // Stop any sound playing (using multichannel buffer pool) - RLAPI int GetSoundsPlaying(void); // Get number of sounds playing in the multichannel - 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 WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format - RLAPI Wave WaveCopy(Wave wave); // Copy a wave to a new wave - RLAPI void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range - RLAPI float *LoadWaveSamples(Wave wave); // Load samples data from wave as a floats 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, unsigned char *data, int dataSize); // Load music stream from data - 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 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 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 SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams - -#if defined(__cplusplus) -} -#endif - -#endif // RAYLIB_H diff --git a/include/raymath.h b/include/raymath.h deleted file mode 100644 index 48846a7..0000000 --- a/include/raymath.h +++ /dev/null @@ -1,1853 +0,0 @@ -/********************************************************************************************** -* -* raymath v1.5 - Math functions to work with Vector2, Vector3, Matrix and Quaternions -* -* 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. -* -* CONVENTIONS: -* -* - 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" anmed variable for return -* - Functions are always defined inline -* - Angles are always in radians (DEG2RAD/RAD2DEG macros provided for convenience) -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2015-2021 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 // We are building raylib as a Win32 shared library (.dll). - #elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED) - #define RMAPI __declspec(dllimport) // We are 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 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 -typedef struct float3 { - float v[3]; -} float3; - -typedef struct float16 { - float v[16]; -} float16; - -#include // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), fminf(), fmaxf(), fabs() - -//---------------------------------------------------------------------------------- -// 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; -} - -//---------------------------------------------------------------------------------- -// 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 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 angle from two vectors in X-axis -RMAPI float Vector2Angle(Vector2 v1, Vector2 v2) -{ - float result = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI); - - if (result < 0) result += 360.0f; - - 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) - { - result.x = v.x*1.0f/length; - result.y = v.y*1.0f/length; - } - - 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; -} - -// Rotate vector by angle -RMAPI Vector2 Vector2Rotate(Vector2 v, float angle) -{ - Vector2 result = { 0 }; - - result.x = v.x*cosf(angle) - v.y*sinf(angle); - result.y = v.x*sinf(angle) + v.y*cosf(angle); - - 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; -} - -//---------------------------------------------------------------------------------- -// 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 = (float) fabs(v.x); - Vector3 cardinalAxis = {1.0f, 0.0f, 0.0f}; - - if (fabs(v.y) < min) - { - min = (float) fabs(v.y); - Vector3 tmp = {0.0f, 1.0f, 0.0f}; - cardinalAxis = tmp; - } - - if (fabs(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 angle between two vectors in XY and XZ -RMAPI Vector2 Vector3Angle(Vector3 v1, Vector3 v2) -{ - Vector2 result = { 0 }; - - float dx = v2.x - v1.x; - float dy = v2.y - v1.y; - float dz = v2.z - v1.z; - - result.x = atan2f(dx, dz); // Angle in XZ - result.y = atan2f(dy, sqrtf(dx*dx + dz*dz)); // Angle in XY - - 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) length = 1.0f; - float ilength = 1.0f/length; - - result.x *= ilength; - result.y *= ilength; - result.z *= ilength; - - 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; -} - -// 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 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: We are avoiding calling other raymath functions despite available -RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view) -{ - Vector3 result = { 0 }; - - // Calculate unproject matrix (multiply view patrix 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 unproject 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; -} - -//---------------------------------------------------------------------------------- -// 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; - - 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; - - 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; -} - -// Normalize provided matrix -RMAPI Matrix MatrixNormalize(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; - - // MatrixDeterminant(mat) - float det = 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; - - result.m0 = mat.m0/det; - result.m1 = mat.m1/det; - result.m2 = mat.m2/det; - result.m3 = mat.m3/det; - result.m4 = mat.m4/det; - result.m5 = mat.m5/det; - result.m6 = mat.m6/det; - result.m7 = mat.m7/det; - result.m8 = mat.m8/det; - result.m9 = mat.m9/det; - result.m10 = mat.m10/det; - result.m11 = mat.m11/det; - result.m12 = mat.m12/det; - result.m13 = mat.m13/det; - result.m14 = mat.m14/det; - result.m15 = mat.m15/det; - - 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 }; - - 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; -} - -// 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 (angle 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 (angle 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 (angle 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 (angles in radians) -RMAPI Matrix MatrixRotateXYZ(Vector3 ang) -{ - 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(-ang.z); - float sinz = sinf(-ang.z); - float cosy = cosf(-ang.y); - float siny = sinf(-ang.y); - float cosx = cosf(-ang.x); - float sinx = sinf(-ang.x); - - result.m0 = cosz*cosy; - result.m4 = (cosz*siny*sinx) - (sinz*cosx); - result.m8 = (cosz*siny*cosx) + (sinz*sinx); - - result.m1 = sinz*cosy; - result.m5 = (sinz*siny*sinx) + (cosz*cosx); - result.m9 = (sinz*siny*cosx) - (cosz*sinx); - - result.m2 = -siny; - result.m6 = cosy*sinx; - result.m10= cosy*cosx; - - return result; -} - -// Get zyx-rotation matrix (angles in radians) -RMAPI Matrix MatrixRotateZYX(Vector3 ang) -{ - Matrix result = { 0 }; - - float cz = cosf(ang.z); - float sz = sinf(ang.z); - float cy = cosf(ang.y); - float sy = sinf(ang.y); - float cx = cosf(ang.x); - float sx = sinf(ang.x); - - result.m0 = cz*cy; - result.m1 = cz*sy*sx - cx*sz; - result.m2 = sz*sx + cz*cx*sy; - result.m3 = 0; - - result.m4 = cy*sz; - result.m5 = cz*cx + sz*sy*sx; - result.m6 = cx*sz*sy - cz*sx; - result.m7 = 0; - - result.m8 = -sy; - result.m9 = cy*sx; - result.m10 = cy*cx; - result.m11 = 0; - - result.m12 = 0; - result.m13 = 0; - result.m14 = 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 near, double far) -{ - Matrix result = { 0 }; - - float rl = (float)(right - left); - float tb = (float)(top - bottom); - float fn = (float)(far - near); - - result.m0 = ((float)near*2.0f)/rl; - result.m1 = 0.0f; - result.m2 = 0.0f; - result.m3 = 0.0f; - - result.m4 = 0.0f; - result.m5 = ((float)near*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)far + (float)near)/fn; - result.m11 = -1.0f; - - result.m12 = 0.0f; - result.m13 = 0.0f; - result.m14 = -((float)far*(float)near*2.0f)/fn; - result.m15 = 0.0f; - - return result; -} - -// Get perspective projection matrix -// NOTE: Angle should be provided in radians -RMAPI Matrix MatrixPerspective(double fovy, double aspect, double near, double far) -{ - Matrix result = { 0 }; - - double top = near*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)(far - near); - - result.m0 = ((float)near*2.0f)/rl; - result.m5 = ((float)near*2.0f)/tb; - result.m8 = ((float)right + (float)left)/rl; - result.m9 = ((float)top + (float)bottom)/tb; - result.m10 = -((float)far + (float)near)/fn; - result.m11 = -1.0f; - result.m14 = -((float)far*(float)near*2.0f)/fn; - - return result; -} - -// Get orthographic projection matrix -RMAPI Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far) -{ - Matrix result = { 0 }; - - float rl = (float)(right - left); - float tb = (float)(top - bottom); - float fn = (float)(far - near); - - 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)far + (float)near)/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 length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w); - float lengthSq = length*length; - - if (lengthSq != 0.0) - { - 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 }; - - float qax = q.x, qay = q.y, qaz = q.z, qaw = q.w; - - result.x = qax*mul + qaw*mul + qay*mul - qaz*mul; - result.y = qay*mul + qaw*mul + qaz*mul - qax*mul; - result.z = qaz*mul + qaw*mul + qax*mul - qay*mul; - result.w = qaw*mul - qax*mul - qay*mul - qaz*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 }; - - 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 (fabs(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 (fabs(sinHalfTheta) < 0.001f) - { - 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 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 = 1.0f + 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 }; - - if ((mat.m0 > mat.m5) && (mat.m0 > mat.m10)) - { - float s = sqrtf(1.0f + mat.m0 - mat.m5 - mat.m10)*2; - - result.x = 0.25f*s; - result.y = (mat.m4 + mat.m1)/s; - result.z = (mat.m2 + mat.m8)/s; - result.w = (mat.m9 - mat.m6)/s; - } - else if (mat.m5 > mat.m10) - { - float s = sqrtf(1.0f + mat.m5 - mat.m0 - mat.m10)*2; - result.x = (mat.m4 + mat.m1)/s; - result.y = 0.25f*s; - result.z = (mat.m9 + mat.m6)/s; - result.w = (mat.m2 - mat.m8)/s; - } - else - { - float s = sqrtf(1.0f + mat.m10 - mat.m0 - mat.m5)*2; - result.x = (mat.m2 + mat.m8)/s; - result.y = (mat.m9 + mat.m6)/s; - result.z = 0.25f*s; - result.w = (mat.m4 - mat.m1)/s; - } - - 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 axisLength = sqrtf(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z); - - if (axisLength != 0.0f) - { - angle *= 0.5f; - - float length = 0.0f; - float ilength = 0.0f; - - // Vector3Normalize(axis) - Vector3 v = axis; - 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; - 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 (fabs(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 > 0.0001f) - { - 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: just 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; -} - -#endif // RAYMATH_H diff --git a/include/rcamera.h b/include/rcamera.h deleted file mode 100644 index 2a86e36..0000000 --- a/include/rcamera.h +++ /dev/null @@ -1,567 +0,0 @@ -/******************************************************************************************* -* -* rcamera - Basic camera system for multiple camera modes -* -* NOTE: Memory footprint of this library is aproximately 52 bytes (global variables) -* -* CONFIGURATION: -* -* #define CAMERA_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 CAMERA_STANDALONE -* If defined, the library can be used as standalone as a camera system but some -* functions must be redefined to manage inputs accordingly. -* -* CONTRIBUTORS: -* Ramon Santamaria: Supervision, review, update and maintenance -* Marc Palau: Initial implementation (2014) -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2015-2021 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 RCAMERA_H -#define RCAMERA_H - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -// NOTE: Below types are required for CAMERA_STANDALONE usage -//---------------------------------------------------------------------------------- -#if defined(CAMERA_STANDALONE) - // Vector2 type - typedef struct Vector2 { - float x; - float y; - } Vector2; - - // Vector3 type - typedef struct Vector3 { - float x; - float y; - float z; - } Vector3; - - // Camera type, defines a camera 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 apperture in Y (degrees) in perspective, used as near plane width in orthographic - int type; // Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC - } Camera3D; - - typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D - - // Camera system modes - typedef enum { - CAMERA_CUSTOM = 0, - CAMERA_FREE, - CAMERA_ORBITAL, - CAMERA_FIRST_PERSON, - CAMERA_THIRD_PERSON - } CameraMode; - - // Camera projection modes - typedef enum { - CAMERA_PERSPECTIVE = 0, - CAMERA_ORTHOGRAPHIC - } CameraProjection; -#endif - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- - -#ifdef __cplusplus -extern "C" { // Prevents name mangling of functions -#endif - -#if defined(CAMERA_STANDALONE) -void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available) -void UpdateCamera(Camera *camera); // Update camera position for selected mode - -void SetCameraPanControl(int keyPan); // Set camera pan key to combine with mouse movement (free camera) -void SetCameraAltControl(int keyAlt); // Set camera alt key to combine with mouse movement (free camera) -void SetCameraSmoothZoomControl(int szoomKey); // Set camera smooth zoom key to combine with mouse (free camera) -void SetCameraMoveControls(int keyFront, int keyBack, - int keyRight, int keyLeft, - int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras) -#endif - -#ifdef __cplusplus -} -#endif - -#endif // CAMERA_H - - -/*********************************************************************************** -* -* CAMERA IMPLEMENTATION -* -************************************************************************************/ - -#if defined(CAMERA_IMPLEMENTATION) - -#include // Required for: sinf(), cosf(), sqrtf() - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#ifndef PI - #define PI 3.14159265358979323846 -#endif -#ifndef DEG2RAD - #define DEG2RAD (PI/180.0f) -#endif -#ifndef RAD2DEG - #define RAD2DEG (180.0f/PI) -#endif - -// Camera mouse movement sensitivity -#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f -#define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f - -// FREE_CAMERA -#define CAMERA_FREE_MOUSE_SENSITIVITY 0.01f -#define CAMERA_FREE_DISTANCE_MIN_CLAMP 0.3f -#define CAMERA_FREE_DISTANCE_MAX_CLAMP 120.0f -#define CAMERA_FREE_MIN_CLAMP 85.0f -#define CAMERA_FREE_MAX_CLAMP -85.0f -#define CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY 0.05f -#define CAMERA_FREE_PANNING_DIVIDER 5.1f - -// ORBITAL_CAMERA -#define CAMERA_ORBITAL_SPEED 0.01f // Radians per frame - -// FIRST_PERSON -//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY 0.003f -#define CAMERA_FIRST_PERSON_FOCUS_DISTANCE 25.0f -#define CAMERA_FIRST_PERSON_MIN_CLAMP 89.0f -#define CAMERA_FIRST_PERSON_MAX_CLAMP -89.0f - -#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 8.0f -#define CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f -#define CAMERA_FIRST_PERSON_WAVING_DIVIDER 200.0f - -// THIRD_PERSON -//#define CAMERA_THIRD_PERSON_MOUSE_SENSITIVITY 0.003f -#define CAMERA_THIRD_PERSON_DISTANCE_CLAMP 1.2f -#define CAMERA_THIRD_PERSON_MIN_CLAMP 5.0f -#define CAMERA_THIRD_PERSON_MAX_CLAMP -85.0f -#define CAMERA_THIRD_PERSON_OFFSET (Vector3){ 0.4f, 0.0f, 0.0f } - -// PLAYER (used by camera) -#define PLAYER_MOVEMENT_SENSITIVITY 20.0f - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -// Camera move modes (first person and third person cameras) -typedef enum { - MOVE_FRONT = 0, - MOVE_BACK, - MOVE_RIGHT, - MOVE_LEFT, - MOVE_UP, - MOVE_DOWN -} CameraMove; - -// Camera global state context data [56 bytes] -typedef struct { - unsigned int mode; // Current camera mode - float targetDistance; // Camera distance from position to target - float playerEyesPosition; // Player eyes position from ground (in meters) - Vector2 angle; // Camera angle in plane XZ - Vector2 previousMousePosition; // Previous mouse position - - // Camera movement control keys - int moveControl[6]; // Move controls (CAMERA_FIRST_PERSON) - int smoothZoomControl; // Smooth zoom control key - int altControl; // Alternative control key - int panControl; // Pan view control key -} CameraData; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -static CameraData CAMERA = { // Global CAMERA state context - .mode = 0, - .targetDistance = 0, - .playerEyesPosition = 1.85f, - .angle = { 0 }, - .previousMousePosition = { 0 }, - .moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' }, - .smoothZoomControl = 341, // raylib: KEY_LEFT_CONTROL - .altControl = 342, // raylib: KEY_LEFT_ALT - .panControl = 2 // raylib: MOUSE_BUTTON_MIDDLE -}; - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -#if defined(CAMERA_STANDALONE) -// NOTE: Camera controls depend on some raylib input functions -static void EnableCursor() {} // Unlock cursor -static void DisableCursor() {} // Lock cursor - -static int IsKeyDown(int key) { return 0; } - -static int IsMouseButtonDown(int button) { return 0;} -static float GetMouseWheelMove() { return 0.0f; } -static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; } -#endif - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- - -// Select camera mode (multiple camera modes available) -void SetCameraMode(Camera camera, int mode) -{ - Vector3 v1 = camera.position; - Vector3 v2 = camera.target; - - float dx = v2.x - v1.x; - float dy = v2.y - v1.y; - float dz = v2.z - v1.z; - - CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance to target - - // Camera angle calculation - CAMERA.angle.x = atan2f(dx, dz); // Camera angle in plane XZ (0 aligned with Z, move positive CCW) - CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz)); // Camera angle in plane XY (0 aligned with X, move positive CW) - - CAMERA.playerEyesPosition = camera.position.y; // Init player eyes position to camera Y position - - CAMERA.previousMousePosition = GetMousePosition(); // Init mouse position - - // Lock cursor for first person and third person cameras - if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor(); - else EnableCursor(); - - CAMERA.mode = mode; -} - -// Update camera depending on selected mode -// NOTE: Camera controls depend on some raylib functions: -// System: EnableCursor(), DisableCursor() -// Mouse: IsMouseButtonDown(), GetMousePosition(), GetMouseWheelMove() -// Keys: IsKeyDown() -void UpdateCamera(Camera *camera) -{ - static int swingCounter = 0; // Used for 1st person swinging movement - - // TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?) - - // Mouse movement detection - Vector2 mousePositionDelta = { 0.0f, 0.0f }; - Vector2 mousePosition = GetMousePosition(); - float mouseWheelMove = GetMouseWheelMove(); - - // Keys input detection - // TODO: Input detection is raylib-dependant, it could be moved outside the module - bool keyPan = IsMouseButtonDown(CAMERA.panControl); - bool keyAlt = IsKeyDown(CAMERA.altControl); - bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl); - bool direction[6] = { IsKeyDown(CAMERA.moveControl[MOVE_FRONT]), - IsKeyDown(CAMERA.moveControl[MOVE_BACK]), - IsKeyDown(CAMERA.moveControl[MOVE_RIGHT]), - IsKeyDown(CAMERA.moveControl[MOVE_LEFT]), - IsKeyDown(CAMERA.moveControl[MOVE_UP]), - IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) }; - - if (CAMERA.mode != CAMERA_CUSTOM) - { - mousePositionDelta.x = mousePosition.x - CAMERA.previousMousePosition.x; - mousePositionDelta.y = mousePosition.y - CAMERA.previousMousePosition.y; - - CAMERA.previousMousePosition = mousePosition; - } - - // Support for multiple automatic camera modes - // NOTE: In case of CAMERA_CUSTOM nothing happens here, user must update it manually - switch (CAMERA.mode) - { - case CAMERA_FREE: // Camera free controls, using standard 3d-content-creation scheme - { - // Camera zoom - if ((CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) - { - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - if (CAMERA.targetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP; - } - - // Camera looking down - else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - } - else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - - // if (camera->target.y < 0) camera->target.y = -0.001; - } - else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0)) - { - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; - } - // Camera looking up - else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - } - else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0)) - { - camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; - - // if (camera->target.y > 0) camera->target.y = 0.001; - } - else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0)) - { - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; - } - - // Input keys checks - if (keyPan) - { - if (keyAlt) // Alternative key behaviour - { - if (szoomKey) - { - // Camera smooth zoom - CAMERA.targetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY); - } - else - { - // Camera rotation - CAMERA.angle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY; - CAMERA.angle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY; - - // Angle clamp - if (CAMERA.angle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD; - else if (CAMERA.angle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD; - } - } - else - { - // Camera panning - camera->target.x += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); - camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); - camera->target.z += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER); - } - } - - // Update camera position with changes - camera->position.x = -sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; - camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance + camera->target.y; - camera->position.z = -cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; - - } break; - case CAMERA_ORBITAL: // Camera just orbits around target, only zoom allowed - { - CAMERA.angle.x += CAMERA_ORBITAL_SPEED; // Camera orbit angle - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom - - // Camera distance clamp - if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; - - // Update camera position with changes - camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; - camera->position.y = ((CAMERA.angle.y <= 0.0f)? 1 : -1)*sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; - camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; - - } break; - case CAMERA_FIRST_PERSON: // Camera moves as in a first-person game, controls are configurable - { - camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] - - sinf(CAMERA.angle.x)*direction[MOVE_FRONT] - - cosf(CAMERA.angle.x)*direction[MOVE_LEFT] + - cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; - - camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] - - sinf(CAMERA.angle.y)*direction[MOVE_BACK] + - 1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY; - - camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] - - cosf(CAMERA.angle.x)*direction[MOVE_FRONT] + - sinf(CAMERA.angle.x)*direction[MOVE_LEFT] - - sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; - - // Camera orientation calculation - CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY); - CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY); - - // Angle clamp - if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD; - else if (CAMERA.angle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD; - - // Calculate translation matrix - Matrix matTranslation = { 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, (CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER), - 0.0f, 0.0f, 0.0f, 1.0f }; - - // Calculate rotation matrix - Matrix matRotation = { 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 }; - - float cosz = cosf(0.0f); - float sinz = sinf(0.0f); - float cosy = cosf(-(PI*2 - CAMERA.angle.x)); - float siny = sinf(-(PI*2 - CAMERA.angle.x)); - float cosx = cosf(-(PI*2 - CAMERA.angle.y)); - float sinx = sinf(-(PI*2 - CAMERA.angle.y)); - - matRotation.m0 = cosz*cosy; - matRotation.m4 = (cosz*siny*sinx) - (sinz*cosx); - matRotation.m8 = (cosz*siny*cosx) + (sinz*sinx); - matRotation.m1 = sinz*cosy; - matRotation.m5 = (sinz*siny*sinx) + (cosz*cosx); - matRotation.m9 = (sinz*siny*cosx) - (cosz*sinx); - matRotation.m2 = -siny; - matRotation.m6 = cosy*sinx; - matRotation.m10= cosy*cosx; - - // Multiply translation and rotation matrices - Matrix matTransform = { 0 }; - matTransform.m0 = matTranslation.m0*matRotation.m0 + matTranslation.m1*matRotation.m4 + matTranslation.m2*matRotation.m8 + matTranslation.m3*matRotation.m12; - matTransform.m1 = matTranslation.m0*matRotation.m1 + matTranslation.m1*matRotation.m5 + matTranslation.m2*matRotation.m9 + matTranslation.m3*matRotation.m13; - matTransform.m2 = matTranslation.m0*matRotation.m2 + matTranslation.m1*matRotation.m6 + matTranslation.m2*matRotation.m10 + matTranslation.m3*matRotation.m14; - matTransform.m3 = matTranslation.m0*matRotation.m3 + matTranslation.m1*matRotation.m7 + matTranslation.m2*matRotation.m11 + matTranslation.m3*matRotation.m15; - matTransform.m4 = matTranslation.m4*matRotation.m0 + matTranslation.m5*matRotation.m4 + matTranslation.m6*matRotation.m8 + matTranslation.m7*matRotation.m12; - matTransform.m5 = matTranslation.m4*matRotation.m1 + matTranslation.m5*matRotation.m5 + matTranslation.m6*matRotation.m9 + matTranslation.m7*matRotation.m13; - matTransform.m6 = matTranslation.m4*matRotation.m2 + matTranslation.m5*matRotation.m6 + matTranslation.m6*matRotation.m10 + matTranslation.m7*matRotation.m14; - matTransform.m7 = matTranslation.m4*matRotation.m3 + matTranslation.m5*matRotation.m7 + matTranslation.m6*matRotation.m11 + matTranslation.m7*matRotation.m15; - matTransform.m8 = matTranslation.m8*matRotation.m0 + matTranslation.m9*matRotation.m4 + matTranslation.m10*matRotation.m8 + matTranslation.m11*matRotation.m12; - matTransform.m9 = matTranslation.m8*matRotation.m1 + matTranslation.m9*matRotation.m5 + matTranslation.m10*matRotation.m9 + matTranslation.m11*matRotation.m13; - matTransform.m10 = matTranslation.m8*matRotation.m2 + matTranslation.m9*matRotation.m6 + matTranslation.m10*matRotation.m10 + matTranslation.m11*matRotation.m14; - matTransform.m11 = matTranslation.m8*matRotation.m3 + matTranslation.m9*matRotation.m7 + matTranslation.m10*matRotation.m11 + matTranslation.m11*matRotation.m15; - matTransform.m12 = matTranslation.m12*matRotation.m0 + matTranslation.m13*matRotation.m4 + matTranslation.m14*matRotation.m8 + matTranslation.m15*matRotation.m12; - matTransform.m13 = matTranslation.m12*matRotation.m1 + matTranslation.m13*matRotation.m5 + matTranslation.m14*matRotation.m9 + matTranslation.m15*matRotation.m13; - matTransform.m14 = matTranslation.m12*matRotation.m2 + matTranslation.m13*matRotation.m6 + matTranslation.m14*matRotation.m10 + matTranslation.m15*matRotation.m14; - matTransform.m15 = matTranslation.m12*matRotation.m3 + matTranslation.m13*matRotation.m7 + matTranslation.m14*matRotation.m11 + matTranslation.m15*matRotation.m15; - - camera->target.x = camera->position.x - matTransform.m12; - camera->target.y = camera->position.y - matTransform.m13; - camera->target.z = camera->position.z - matTransform.m14; - - // If movement detected (some key pressed), increase swinging - for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter++; break; } - - // Camera position update - // NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position' - camera->position.y = CAMERA.playerEyesPosition - sinf(swingCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER; - - camera->up.x = sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER; - camera->up.z = -sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER; - - } break; - case CAMERA_THIRD_PERSON: // Camera moves as in a third-person game, following target at a distance, controls are configurable - { - camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] - - sinf(CAMERA.angle.x)*direction[MOVE_FRONT] - - cosf(CAMERA.angle.x)*direction[MOVE_LEFT] + - cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; - - camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] - - sinf(CAMERA.angle.y)*direction[MOVE_BACK] + - 1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY; - - camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] - - cosf(CAMERA.angle.x)*direction[MOVE_FRONT] + - sinf(CAMERA.angle.x)*direction[MOVE_LEFT] - - sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY; - - // Camera orientation calculation - CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY); - CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY); - - // Angle clamp - if (CAMERA.angle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD; - else if (CAMERA.angle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD; - - // Camera zoom - CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); - - // Camera distance clamp - if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP; - - camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; - - if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; - else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; - - camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; - - } break; - case CAMERA_CUSTOM: break; - default: break; - } -} - -// Set camera pan key to combine with mouse movement (free camera) -void SetCameraPanControl(int keyPan) { CAMERA.panControl = keyPan; } - -// Set camera alt key to combine with mouse movement (free camera) -void SetCameraAltControl(int keyAlt) { CAMERA.altControl = keyAlt; } - -// Set camera smooth zoom key to combine with mouse (free camera) -void SetCameraSmoothZoomControl(int szoomKey) { CAMERA.smoothZoomControl = szoomKey; } - -// Set camera move controls (1st person and 3rd person cameras) -void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown) -{ - CAMERA.moveControl[MOVE_FRONT] = keyFront; - CAMERA.moveControl[MOVE_BACK] = keyBack; - CAMERA.moveControl[MOVE_RIGHT] = keyRight; - CAMERA.moveControl[MOVE_LEFT] = keyLeft; - CAMERA.moveControl[MOVE_UP] = keyUp; - CAMERA.moveControl[MOVE_DOWN] = keyDown; -} - -#endif // CAMERA_IMPLEMENTATION diff --git a/include/rgestures.h b/include/rgestures.h deleted file mode 100644 index bb9dd16..0000000 --- a/include/rgestures.h +++ /dev/null @@ -1,566 +0,0 @@ -/********************************************************************************************** -* -* rgestures - Gestures system, gestures processing based on input events (touch/mouse) -* -* NOTE: Memory footprint of this library is aproximately 128 bytes (global variables) -* -* CONFIGURATION: -* -* #define GESTURES_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 GESTURES_STANDALONE -* If defined, the library can be used as standalone to process gesture events with -* no external dependencies. -* -* CONTRIBUTORS: -* Marc Palau: Initial implementation (2014) -* Albert Martos: Complete redesign and testing (2015) -* Ian Eito: Complete redesign and testing (2015) -* Ramon Santamaria: Supervision, review, update and maintenance -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2014-2021 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 RGESTURES_H -#define RGESTURES_H - -#ifndef PI - #define PI 3.14159265358979323846 -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#ifndef MAX_TOUCH_POINTS - #define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported -#endif - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -// NOTE: Below types are required for GESTURES_STANDALONE usage -//---------------------------------------------------------------------------------- -// Boolean type -#if defined(__STDC__) && __STDC_VERSION__ >= 199901L - #include -#elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE) - typedef enum bool { false, true } bool; -#endif - -#if !defined(RL_VECTOR2_TYPE) -// Vector2 type -typedef struct Vector2 { - float x; - float y; -} Vector2; -#endif - -#if defined(GESTURES_STANDALONE) -// Gestures type -// NOTE: It could be used as flags to enable only some gestures -typedef enum { - GESTURE_NONE = 0, - GESTURE_TAP = 1, - GESTURE_DOUBLETAP = 2, - GESTURE_HOLD = 4, - GESTURE_DRAG = 8, - GESTURE_SWIPE_RIGHT = 16, - GESTURE_SWIPE_LEFT = 32, - GESTURE_SWIPE_UP = 64, - GESTURE_SWIPE_DOWN = 128, - GESTURE_PINCH_IN = 256, - GESTURE_PINCH_OUT = 512 -} Gesture; -#endif - -typedef enum { - TOUCH_ACTION_UP = 0, - TOUCH_ACTION_DOWN, - TOUCH_ACTION_MOVE, - TOUCH_ACTION_CANCEL -} TouchAction; - -// Gesture event -typedef struct { - int touchAction; - int pointCount; - int pointId[MAX_TOUCH_POINTS]; - Vector2 position[MAX_TOUCH_POINTS]; -} GestureEvent; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- - -#ifdef __cplusplus -extern "C" { // Prevents name mangling of functions -#endif - -void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures -void UpdateGestures(void); // Update gestures detected (must be called every frame) - -#if defined(GESTURES_STANDALONE) -void SetGesturesEnabled(unsigned int flags); // Enable a set of gestures using flags -bool IsGestureDetected(int gesture); // Check if a gesture have been detected -int GetGestureDetected(void); // Get latest detected gesture - -float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds -Vector2 GetGestureDragVector(void); // Get gesture drag vector -float GetGestureDragAngle(void); // Get gesture drag angle -Vector2 GetGesturePinchVector(void); // Get gesture pinch delta -float GetGesturePinchAngle(void); // Get gesture pinch angle -#endif - -#ifdef __cplusplus -} -#endif - -#endif // GESTURES_H - -/*********************************************************************************** -* -* GESTURES IMPLEMENTATION -* -************************************************************************************/ - -#if defined(GESTURES_IMPLEMENTATION) - -#if defined(_WIN32) - #if defined(__cplusplus) - extern "C" { // Prevents name mangling of functions - #endif - // Functions required to query time on Windows - int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount); - int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency); - #if defined(__cplusplus) - } - #endif -#elif defined(__linux__) - #if _POSIX_C_SOURCE < 199309L - #undef _POSIX_C_SOURCE - #define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext. - #endif - #include // Required for: timespec - #include // Required for: clock_gettime() - - #include // Required for: sqrtf(), atan2f() -#endif -#if defined(__APPLE__) // macOS also defines __MACH__ - #include // Required for: clock_get_time() - #include // Required for: mach_timespec_t -#endif - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#define FORCE_TO_SWIPE 0.0005f // Swipe force, measured in normalized screen units/time -#define MINIMUM_DRAG 0.015f // Drag minimum force, measured in normalized screen units (0.0f to 1.0f) -#define MINIMUM_PINCH 0.005f // Pinch minimum force, measured in normalized screen units (0.0f to 1.0f) -#define TAP_TIMEOUT 300 // Tap minimum time, measured in milliseconds -#define PINCH_TIMEOUT 300 // Pinch minimum time, measured in milliseconds -#define DOUBLETAP_RANGE 0.03f // DoubleTap range, measured in normalized screen units (0.0f to 1.0f) - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- - -// Gestures module state context [136 bytes] -typedef struct { - unsigned int current; // Current detected gesture - unsigned int enabledFlags; // Enabled gestures flags - struct { - int firstId; // Touch id for first touch point - int pointCount; // Touch points counter - double eventTime; // Time stamp when an event happened - Vector2 upPosition; // Touch up position - Vector2 downPositionA; // First touch down position - Vector2 downPositionB; // Second touch down position - Vector2 downDragPosition; // Touch drag position - Vector2 moveDownPositionA; // First touch down position on move - Vector2 moveDownPositionB; // Second touch down position on move - int tapCounter; // TAP counter (one tap implies TOUCH_ACTION_DOWN and TOUCH_ACTION_UP actions) - } Touch; - struct { - bool resetRequired; // HOLD reset to get first touch point again - double timeDuration; // HOLD duration in milliseconds - } Hold; - struct { - Vector2 vector; // DRAG vector (between initial and current position) - float angle; // DRAG angle (relative to x-axis) - float distance; // DRAG distance (from initial touch point to final) (normalized [0..1]) - float intensity; // DRAG intensity, how far why did the DRAG (pixels per frame) - } Drag; - struct { - bool start; // SWIPE used to define when start measuring GESTURES.Swipe.timeDuration - double timeDuration; // SWIPE time to calculate drag intensity - } Swipe; - struct { - Vector2 vector; // PINCH vector (between first and second touch points) - float angle; // PINCH angle (relative to x-axis) - float distance; // PINCH displacement distance (normalized [0..1]) - } Pinch; -} GesturesData; - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -static GesturesData GESTURES = { - .Touch.firstId = -1, - .current = GESTURE_NONE, // No current gesture detected - .enabledFlags = 0b0000001111111111 // All gestures supported by default -}; - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -static float rgVector2Angle(Vector2 initialPosition, Vector2 finalPosition); -static float rgVector2Distance(Vector2 v1, Vector2 v2); -static double rgGetCurrentTime(void); - -//---------------------------------------------------------------------------------- -// Module Functions Definition -//---------------------------------------------------------------------------------- - -// Enable only desired getures to be detected -void SetGesturesEnabled(unsigned int flags) -{ - GESTURES.enabledFlags = flags; -} - -// Check if a gesture have been detected -bool IsGestureDetected(int gesture) -{ - if ((GESTURES.enabledFlags & GESTURES.current) == gesture) return true; - else return false; -} - -// Process gesture event and translate it into gestures -void ProcessGestureEvent(GestureEvent event) -{ - // Reset required variables - GESTURES.Touch.pointCount = event.pointCount; // Required on UpdateGestures() - - if (GESTURES.Touch.pointCount == 1) // One touch point - { - if (event.touchAction == TOUCH_ACTION_DOWN) - { - GESTURES.Touch.tapCounter++; // Tap counter - - // Detect GESTURE_DOUBLE_TAP - if ((GESTURES.current == GESTURE_NONE) && (GESTURES.Touch.tapCounter >= 2) && ((rgGetCurrentTime() - GESTURES.Touch.eventTime) < TAP_TIMEOUT) && (rgVector2Distance(GESTURES.Touch.downPositionA, event.position[0]) < DOUBLETAP_RANGE)) - { - GESTURES.current = GESTURE_DOUBLETAP; - GESTURES.Touch.tapCounter = 0; - } - else // Detect GESTURE_TAP - { - GESTURES.Touch.tapCounter = 1; - GESTURES.current = GESTURE_TAP; - } - - GESTURES.Touch.downPositionA = event.position[0]; - GESTURES.Touch.downDragPosition = event.position[0]; - - GESTURES.Touch.upPosition = GESTURES.Touch.downPositionA; - GESTURES.Touch.eventTime = rgGetCurrentTime(); - - GESTURES.Touch.firstId = event.pointId[0]; - - GESTURES.Drag.vector = (Vector2){ 0.0f, 0.0f }; - } - else if (event.touchAction == TOUCH_ACTION_UP) - { - if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.upPosition = event.position[0]; - - // NOTE: GESTURES.Drag.intensity dependend on the resolution of the screen - GESTURES.Drag.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); - GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((rgGetCurrentTime() - GESTURES.Swipe.timeDuration)); - - GESTURES.Swipe.start = false; - - // Detect GESTURE_SWIPE - if ((GESTURES.Drag.intensity > FORCE_TO_SWIPE) && (GESTURES.Touch.firstId == event.pointId[0])) - { - // NOTE: Angle should be inverted in Y - GESTURES.Drag.angle = 360.0f - rgVector2Angle(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition); - - if ((GESTURES.Drag.angle < 30) || (GESTURES.Drag.angle > 330)) GESTURES.current = GESTURE_SWIPE_RIGHT; // Right - else if ((GESTURES.Drag.angle > 30) && (GESTURES.Drag.angle < 120)) GESTURES.current = GESTURE_SWIPE_UP; // Up - else if ((GESTURES.Drag.angle > 120) && (GESTURES.Drag.angle < 210)) GESTURES.current = GESTURE_SWIPE_LEFT; // Left - else if ((GESTURES.Drag.angle > 210) && (GESTURES.Drag.angle < 300)) GESTURES.current = GESTURE_SWIPE_DOWN; // Down - else GESTURES.current = GESTURE_NONE; - } - else - { - GESTURES.Drag.distance = 0.0f; - GESTURES.Drag.intensity = 0.0f; - GESTURES.Drag.angle = 0.0f; - - GESTURES.current = GESTURE_NONE; - } - - GESTURES.Touch.downDragPosition = (Vector2){ 0.0f, 0.0f }; - GESTURES.Touch.pointCount = 0; - } - else if (event.touchAction == TOUCH_ACTION_MOVE) - { - if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.eventTime = rgGetCurrentTime(); - - if (!GESTURES.Swipe.start) - { - GESTURES.Swipe.timeDuration = rgGetCurrentTime(); - GESTURES.Swipe.start = true; - } - - GESTURES.Touch.moveDownPositionA = event.position[0]; - - if (GESTURES.current == GESTURE_HOLD) - { - if (GESTURES.Hold.resetRequired) GESTURES.Touch.downPositionA = event.position[0]; - - GESTURES.Hold.resetRequired = false; - - // Detect GESTURE_DRAG - if (rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_DRAG) - { - GESTURES.Touch.eventTime = rgGetCurrentTime(); - GESTURES.current = GESTURE_DRAG; - } - } - - GESTURES.Drag.vector.x = GESTURES.Touch.moveDownPositionA.x - GESTURES.Touch.downDragPosition.x; - GESTURES.Drag.vector.y = GESTURES.Touch.moveDownPositionA.y - GESTURES.Touch.downDragPosition.y; - } - } - else if (GESTURES.Touch.pointCount == 2) // Two touch points - { - if (event.touchAction == TOUCH_ACTION_DOWN) - { - GESTURES.Touch.downPositionA = event.position[0]; - GESTURES.Touch.downPositionB = event.position[1]; - - //GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.downPositionB); - - GESTURES.Pinch.vector.x = GESTURES.Touch.downPositionB.x - GESTURES.Touch.downPositionA.x; - GESTURES.Pinch.vector.y = GESTURES.Touch.downPositionB.y - GESTURES.Touch.downPositionA.y; - - GESTURES.current = GESTURE_HOLD; - GESTURES.Hold.timeDuration = rgGetCurrentTime(); - } - else if (event.touchAction == TOUCH_ACTION_MOVE) - { - GESTURES.Pinch.distance = rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB); - - GESTURES.Touch.downPositionA = GESTURES.Touch.moveDownPositionA; - GESTURES.Touch.downPositionB = GESTURES.Touch.moveDownPositionB; - - GESTURES.Touch.moveDownPositionA = event.position[0]; - GESTURES.Touch.moveDownPositionB = event.position[1]; - - GESTURES.Pinch.vector.x = GESTURES.Touch.moveDownPositionB.x - GESTURES.Touch.moveDownPositionA.x; - GESTURES.Pinch.vector.y = GESTURES.Touch.moveDownPositionB.y - GESTURES.Touch.moveDownPositionA.y; - - if ((rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.moveDownPositionA) >= MINIMUM_PINCH) || (rgVector2Distance(GESTURES.Touch.downPositionB, GESTURES.Touch.moveDownPositionB) >= MINIMUM_PINCH)) - { - if ((rgVector2Distance(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB) - GESTURES.Pinch.distance) < 0) GESTURES.current = GESTURE_PINCH_IN; - else GESTURES.current = GESTURE_PINCH_OUT; - } - else - { - GESTURES.current = GESTURE_HOLD; - GESTURES.Hold.timeDuration = rgGetCurrentTime(); - } - - // NOTE: Angle should be inverted in Y - GESTURES.Pinch.angle = 360.0f - rgVector2Angle(GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB); - } - else if (event.touchAction == TOUCH_ACTION_UP) - { - GESTURES.Pinch.distance = 0.0f; - GESTURES.Pinch.angle = 0.0f; - GESTURES.Pinch.vector = (Vector2){ 0.0f, 0.0f }; - GESTURES.Touch.pointCount = 0; - - GESTURES.current = GESTURE_NONE; - } - } - else if (GESTURES.Touch.pointCount > 2) // More than two touch points - { - // TODO: Process gesture events for more than two points - } -} - -// Update gestures detected (must be called every frame) -void UpdateGestures(void) -{ - // NOTE: Gestures are processed through system callbacks on touch events - - // Detect GESTURE_HOLD - if (((GESTURES.current == GESTURE_TAP) || (GESTURES.current == GESTURE_DOUBLETAP)) && (GESTURES.Touch.pointCount < 2)) - { - GESTURES.current = GESTURE_HOLD; - GESTURES.Hold.timeDuration = rgGetCurrentTime(); - } - - if (((rgGetCurrentTime() - GESTURES.Touch.eventTime) > TAP_TIMEOUT) && (GESTURES.current == GESTURE_DRAG) && (GESTURES.Touch.pointCount < 2)) - { - GESTURES.current = GESTURE_HOLD; - GESTURES.Hold.timeDuration = rgGetCurrentTime(); - GESTURES.Hold.resetRequired = true; - } - - // Detect GESTURE_NONE - if ((GESTURES.current == GESTURE_SWIPE_RIGHT) || (GESTURES.current == GESTURE_SWIPE_UP) || (GESTURES.current == GESTURE_SWIPE_LEFT) || (GESTURES.current == GESTURE_SWIPE_DOWN)) - { - GESTURES.current = GESTURE_NONE; - } -} - -// Get latest detected gesture -int GetGestureDetected(void) -{ - // Get current gesture only if enabled - return (GESTURES.enabledFlags & GESTURES.current); -} - -// Hold time measured in ms -float GetGestureHoldDuration(void) -{ - // NOTE: time is calculated on current gesture HOLD - - double time = 0.0; - - if (GESTURES.current == GESTURE_HOLD) time = rgGetCurrentTime() - GESTURES.Hold.timeDuration; - - return (float)time; -} - -// Get drag vector (between initial touch point to current) -Vector2 GetGestureDragVector(void) -{ - // NOTE: drag vector is calculated on one touch points TOUCH_ACTION_MOVE - - return GESTURES.Drag.vector; -} - -// Get drag angle -// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise -float GetGestureDragAngle(void) -{ - // NOTE: drag angle is calculated on one touch points TOUCH_ACTION_UP - - return GESTURES.Drag.angle; -} - -// Get distance between two pinch points -Vector2 GetGesturePinchVector(void) -{ - // NOTE: Pinch distance is calculated on two touch points TOUCH_ACTION_MOVE - - return GESTURES.Pinch.vector; -} - -// Get angle beween two pinch points -// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise -float GetGesturePinchAngle(void) -{ - // NOTE: pinch angle is calculated on two touch points TOUCH_ACTION_MOVE - - return GESTURES.Pinch.angle; -} - -//---------------------------------------------------------------------------------- -// Module specific Functions Definition -//---------------------------------------------------------------------------------- -// Get angle from two-points vector with X-axis -static float rgVector2Angle(Vector2 v1, Vector2 v2) -{ - float angle = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI); - - if (angle < 0) angle += 360.0f; - - return angle; -} - -// Calculate distance between two Vector2 -static float rgVector2Distance(Vector2 v1, Vector2 v2) -{ - float result; - - float dx = v2.x - v1.x; - float dy = v2.y - v1.y; - - result = (float)sqrt(dx*dx + dy*dy); - - return result; -} - -// Time measure returned are milliseconds -static double rgGetCurrentTime(void) -{ - double time = 0; - -#if defined(_WIN32) - unsigned long long int clockFrequency, currentTime; - - QueryPerformanceFrequency(&clockFrequency); // BE CAREFUL: Costly operation! - QueryPerformanceCounter(¤tTime); - - time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds -#endif - -#if defined(__linux__) - // NOTE: Only for Linux-based systems - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds - - time = ((double)nowTime/1000000.0); // Time in miliseconds -#endif - -#if defined(__APPLE__) - //#define CLOCK_REALTIME CALENDAR_CLOCK // returns UTC time since 1970-01-01 - //#define CLOCK_MONOTONIC SYSTEM_CLOCK // returns the time since boot time - - clock_serv_t cclock; - mach_timespec_t now; - host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); - - // NOTE: OS X does not have clock_gettime(), using clock_get_time() - clock_get_time(cclock, &now); - mach_port_deallocate(mach_task_self(), cclock); - unsigned long long int nowTime = (unsigned long long int)now.tv_sec*1000000000LLU + (unsigned long long int)now.tv_nsec; // Time in nanoseconds - - time = ((double)nowTime/1000000.0); // Time in miliseconds -#endif - - return time; -} - -#endif // GESTURES_IMPLEMENTATION diff --git a/include/rlgl.h b/include/rlgl.h deleted file mode 100644 index 4f9d8fa..0000000 --- a/include/rlgl.h +++ /dev/null @@ -1,4677 +0,0 @@ -/********************************************************************************************** -* -* rlgl v4.0 - A multi-OpenGL abstraction layer with an immediate-mode style API -* -* An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0) -* that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...) -* -* When chosing an OpenGL backend different than OpenGL 1.1, some internal buffer are -* initialized on rlglInit() to accumulate vertex data. -* -* When an internal state change is required all the stored vertex data is renderer in batch, -* additioanlly, rlDrawRenderBatchActive() could be called to force flushing of the batch. -* -* Some additional 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 additional resources) must be manually unloaded calling rlglClose(). -* -* -* CONFIGURATION: -* -* #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 -* Use selected OpenGL graphics backend, should be supported by platform -* Those preprocessor defines are only used on 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. -* -* #define RLGL_RENDER_TEXTURES_HINT -* Enable framebuffer objects (fbo) support (enabled by default) -* Some GPUs could not support them despite the OpenGL version -* -* #define RLGL_SHOW_GL_DETAILS_INFO -* Show OpenGL extensions and capabilities detailed logs on init -* -* #define RLGL_ENABLE_OPENGL_DEBUG_CONTEXT -* Enable debug context (only available on OpenGL 4.3) -* -* rlgl capabilities could be customized just 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 textures 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.01 // Default projection matrix near cull distance -* #define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance -* -* When loading a shader, the following vertex attribute and uniform -* location names are tried to be set automatically: -* -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Binded by default to shader location: 0 -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1 -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2 -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3 -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4 -* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5 -* #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_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-2021 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 "4.0" - -// Function specifiers in case library is build/used as a shared library (Windows) -// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll -#if defined(_WIN32) - #if defined(BUILD_LIBTYPE_SHARED) - #define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll) - #elif defined(USE_LIBTYPE_SHARED) - #define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll) - #endif -#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 - #define TRACELOGD(...) (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_11) && \ - !defined(GRAPHICS_API_OPENGL_21) && \ - !defined(GRAPHICS_API_OPENGL_33) && \ - !defined(GRAPHICS_API_OPENGL_43) && \ - !defined(GRAPHICS_API_OPENGL_ES2) - #define GRAPHICS_API_OPENGL_33 -#endif - -// Security check in case multiple GRAPHICS_API_OPENGL_* defined -#if defined(GRAPHICS_API_OPENGL_11) - #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 - -// 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 - -// Support framebuffer objects by default -// NOTE: Some driver implementation do not support it, despite they should -#define RLGL_RENDER_TEXTURES_HINT - -//---------------------------------------------------------------------------------- -// 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) - // We reduce memory sizes for embedded systems (RPI and HTML5) - // NOTE: On HTML5 (emscripten) this is allocated on heap, - // by default it's 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.01 // Default near cull distance -#endif -#ifndef RL_CULL_DISTANCE_FAR - #define RL_CULL_DISTANCE_FAR 1000.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_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 - -// 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 - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -typedef enum { - OPENGL_11 = 1, - OPENGL_21, - OPENGL_33, - OPENGL_43, - OPENGL_ES_20 -} rlGlVersion; - -typedef enum { - RL_ATTACHMENT_COLOR_CHANNEL0 = 0, - RL_ATTACHMENT_COLOR_CHANNEL1, - RL_ATTACHMENT_COLOR_CHANNEL2, - RL_ATTACHMENT_COLOR_CHANNEL3, - RL_ATTACHMENT_COLOR_CHANNEL4, - RL_ATTACHMENT_COLOR_CHANNEL5, - RL_ATTACHMENT_COLOR_CHANNEL6, - RL_ATTACHMENT_COLOR_CHANNEL7, - RL_ATTACHMENT_DEPTH = 100, - RL_ATTACHMENT_STENCIL = 200, -} rlFramebufferAttachType; - -typedef enum { - RL_ATTACHMENT_CUBEMAP_POSITIVE_X = 0, - RL_ATTACHMENT_CUBEMAP_NEGATIVE_X, - RL_ATTACHMENT_CUBEMAP_POSITIVE_Y, - RL_ATTACHMENT_CUBEMAP_NEGATIVE_Y, - RL_ATTACHMENT_CUBEMAP_POSITIVE_Z, - RL_ATTACHMENT_CUBEMAP_NEGATIVE_Z, - RL_ATTACHMENT_TEXTURE2D = 100, - RL_ATTACHMENT_RENDERBUFFER = 200, -} rlFramebufferAttachTextureType; - -// 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) - 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[4]; // OpenGL Vertex Buffer Objects id (4 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 just 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; - -#if defined(__STDC__) && __STDC_VERSION__ >= 199901L - #include -#elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE) - // Boolean type - typedef enum bool { false, true } 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 - -// 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 formats (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_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, just pixel aproximation - 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_CUSTOM // Belnd textures using custom src/dst factors (use SetBlendModeCustom()) -} 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_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; - -//------------------------------------------------------------------------------------ -// 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 lattest 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(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 - -//------------------------------------------------------------------------------------ -// 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 -#if defined(GRAPHICS_API_OPENGL_11) -RLAPI void rlEnableStatePointer(int vertexAttribType, void *buffer); // Enable attribute state pointer -RLAPI void rlDisableStatePointer(int vertexAttribType); // Disable attribute state pointer -#endif - -// 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) - -// 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 void rlActiveDrawBuffers(int count); // Activate multiple draw color buffers - -// 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 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 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) - -//------------------------------------------------------------------------------------ -// 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-inititialize rlgl (buffers, shaders, textures) -RLAPI void rlLoadExtensions(void *loader); // Load OpenGL extensions (loader function required) -RLAPI int rlGetVersion(void); // Get current OpenGL version -RLAPI int rlGetFramebufferWidth(void); // Get default framebuffer width -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(void *buffer, int size, bool dynamic); // Load a vertex buffer attribute -RLAPI unsigned int rlLoadVertexBufferElement(void *buffer, int size, bool dynamic); // Load a new attributes element buffer -RLAPI void rlUpdateVertexBuffer(unsigned int bufferId, void *data, int dataSize, int offset); // Update GPU buffer with new data -RLAPI void rlUnloadVertexArray(unsigned int vaoId); -RLAPI void rlUnloadVertexBuffer(unsigned int vboId); -RLAPI void rlSetVertexAttribute(unsigned int index, int compSize, int type, bool normalized, int stride, void *pointer); -RLAPI void rlSetVertexAttributeDivisor(unsigned int index, int divisor); -RLAPI void rlSetVertexAttributeDefault(int locIndex, const void *value, int attribType, int count); // Set vertex attribute default value -RLAPI void rlDrawVertexArray(int offset, int count); -RLAPI void rlDrawVertexArrayElements(int offset, int count, void *buffer); -RLAPI void rlDrawVertexArrayInstanced(int offset, int count, int instances); -RLAPI void rlDrawVertexArrayElementsInstanced(int offset, int count, void *buffer, int instances); - -// Textures management -RLAPI unsigned int rlLoadTexture(void *data, int width, int height, int format, int mipmapCount); // Load texture in GPU -RLAPI unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer); // Load depth texture/renderbuffer (to be attached to fbo) -RLAPI unsigned int rlLoadTextureCubemap(void *data, int size, int format); // Load texture cubemap -RLAPI void rlUpdateTexture(unsigned int id, int offsetX, int offsetY, int width, int height, int format, const void *data); // Update GPU texture with new data -RLAPI void rlGetGlTextureFormats(int format, int *glInternalFormat, int *glFormat, 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(int width, int height); // Load an empty framebuffer -RLAPI void rlFramebufferAttach(unsigned int fboId, 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 - -// Shaders management -RLAPI unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings -RLAPI unsigned int rlCompileShader(const char *shaderCode, int type); // Compile custom shader and return shader id (type: RL_VERTEX_SHADER, RL_FRAGMENT_SHADER, RL_COMPUTE_SHADER) -RLAPI unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId); // Load custom shader program -RLAPI void rlUnloadShaderProgram(unsigned int id); // Unload shader program -RLAPI int rlGetLocationUniform(unsigned int shaderId, const char *uniformName); // Get shader location uniform -RLAPI int rlGetLocationAttrib(unsigned int shaderId, const char *attribName); // Get shader location attribute -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 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 unsigned int rlLoadComputeShaderProgram(unsigned int shaderId); // Load compute shader program -RLAPI void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ); // Dispatch compute shader (equivalent to *draw* for graphics pilepine) - -// Shader buffer storage object management (ssbo) -RLAPI unsigned int rlLoadShaderBuffer(unsigned long long 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 rlUpdateShaderBufferElements(unsigned int id, const void *data, unsigned long long dataSize, unsigned long long offset); // Update SSBO buffer data -RLAPI unsigned long long rlGetShaderBufferSize(unsigned int id); // Get SSBO buffer size -RLAPI void rlReadShaderBufferElements(unsigned int id, void *dest, unsigned long long count, unsigned long long offset); // Bind SSBO buffer -RLAPI void rlBindShaderBuffer(unsigned int id, unsigned int index); // Copy SSBO buffer data - -// Buffer management -RLAPI void rlCopyBuffersElements(unsigned int destId, unsigned int srcId, unsigned long long destOffset, unsigned long long srcOffset, unsigned long long count); // Copy SSBO buffer data -RLAPI void rlBindImageTexture(unsigned int id, unsigned int index, unsigned int format, int 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) - -#if defined(GRAPHICS_API_OPENGL_11) - #if defined(__APPLE__) - #include // OpenGL 1.1 library for OSX - #include // OpenGL extensions library - #else - // APIENTRY for OpenGL function pointer declarations is required - #ifndef 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 - -#if defined(GRAPHICS_API_OPENGL_33) - #if defined(__APPLE__) - #include // OpenGL 3 library for OSX - #include // OpenGL 3 extensions library for OSX - #else - #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 -#endif - -#if defined(GRAPHICS_API_OPENGL_ES2) - #define GL_GLEXT_PROTOTYPES - //#include // EGL library -> not required, platform layer - #include // OpenGL ES 2.0 library - #include // OpenGL ES 2.0 extensions library - - // 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) - #if defined(PLATFORM_RPI) || 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: malloc(), 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 - -#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 - #define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER - #define GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER -#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" // Binded by default to shader location: 0 -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD - #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1 -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL - #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2 -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR - #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3 -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT - #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4 -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 - #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5 -#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 - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) -typedef struct rlglData { - rlRenderBatch *currentBatch; // Current render batch - rlRenderBatch defaultBatch; // Default internal render batch - - 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 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 - - int currentBlendMode; // Blending mode active - int glBlendSrcFactor; // Blending source factor - int glBlendDstFactor; // Blending destination factor - int glBlendEquation; // Blending equation - - int framebufferWidth; // Default framebuffer width - int framebufferHeight; // Default 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_WEBGL_depth_texture, GL_OES_depth_texture) - bool texFloat32; // float textures support (32 bit per channel) (GL_OES_texture_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; - -typedef void *(*rlglLoadProc)(const char *name); // OpenGL extension functions loader signature (same as GLADloadproc) - -#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) -static rlglData RLGL = { 0 }; -#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 - -#if defined(GRAPHICS_API_OPENGL_ES2) -// NOTE: VAO functionality is exposed through extensions (OES) -static PFNGLGENVERTEXARRAYSOESPROC glGenVertexArrays = NULL; -static PFNGLBINDVERTEXARRAYOESPROC glBindVertexArray = NULL; -static PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArrays = NULL; - -// NOTE: Instancing functionality could also be available through extension -static PFNGLDRAWARRAYSINSTANCEDEXTPROC glDrawArraysInstanced = NULL; -static PFNGLDRAWELEMENTSINSTANCEDEXTPROC glDrawElementsInstanced = NULL; -static PFNGLVERTEXATTRIBDIVISOREXTPROC glVertexAttribDivisor = NULL; -#endif - -//---------------------------------------------------------------------------------- -// Module specific 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 defined(RLGL_SHOW_GL_DETAILS_INFO) -static char *rlGetCompressedFormatName(int format); // Get compressed format official GL identifier name -#endif // RLGL_SHOW_GL_DETAILS_INFO -#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 -#if defined(GRAPHICS_API_OPENGL_11) -static int rlGenTextureMipmapsData(unsigned char *data, int baseWidth, int baseHeight); // Generate mipmaps data on CPU side -static unsigned char *rlGenNextMipmapData(unsigned char *srcData, int srcWidth, int srcHeight); // Generate next mipmap level on CPU side -#endif -static int rlGetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture) -// Auxiliar matrix math functions -static Matrix rlMatrixIdentity(void); // Get identity matrix -static Matrix rlMatrixMultiply(Matrix left, Matrix right); // Multiply two matrices - -//---------------------------------------------------------------------------------- -// 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(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 lattest 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 = { - 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 - }; - - // NOTE: We transpose matrix with 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: We transpose matrix with 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 = { - 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 - }; - - // NOTE: We transpose matrix with multiplication order - *RLGL.State.currentMatrix = rlMatrixMultiply(matScale, *RLGL.State.currentMatrix); -} - -// Multiply the current matrix by another matrix -void rlMultMatrixf(float *matf) -{ - // Matrix creation from array - 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(*RLGL.State.currentMatrix, mat); -} - -// 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 dependant - 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); -} - -//---------------------------------------------------------------------------------- -// 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() { 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].vertexCount = 0; - RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId = RLGL.State.defaultTextureId; - } -} - -// Finish vertex providing -void rlEnd(void) -{ - // NOTE: Depth increment is dependant 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); - - // Verify internal buffers limits - // NOTE: This check is combined with usage of rlCheckRenderBatchLimit() - if (RLGL.State.vertexCounter >= (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4 - 4)) - { - // WARNING: If we are between rlPushMatrix() and rlPopMatrix() and we need to force a rlDrawRenderBatch(), - // we need to call rlPopMatrix() before to recover *RLGL.State.currentMatrix (RLGL.State.modelview) for the next forced draw call! - // If we have multiple matrix pushed, it will require "RLGL.State.stackCounter" pops before launching the draw - for (int i = RLGL.State.stackCounter; i >= 0; i--) rlPopMatrix(); - rlDrawRenderBatch(RLGL.currentBatch); - } -} - -// 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; - } - - // Verify that current vertex buffer elements limit has not been reached - if (RLGL.State.vertexCounter < (RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4)) - { - // 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; - - // TODO: Add current normal - // By default rlVertexBuffer type does not store normals - - // 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++; - } - else TRACELOG(RL_LOG_ERROR, "RLGL: Batch elements overflow"); -} - -// 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) -{ - RLGL.State.normalx = x; - RLGL.State.normaly = y; - RLGL.State.normalz = z; -} - -// 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, we force a draw call and next batch starts - if (RLGL.State.vertexCounter >= - RLGL.currentBatch->vertexBuffer[RLGL.currentBatch->currentBuffer].elementCount*4) - { - rlDrawRenderBatch(RLGL.currentBatch); - } -#endif - } - else - { -#if defined(GRAPHICS_API_OPENGL_11) - rlEnableTexture(id); -#else - 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++; - } - } - - 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) - 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, 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; - default: break; - } - - glBindTexture(GL_TEXTURE_2D, 0); -} - -// 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(RLGL_RENDER_TEXTURES_HINT) - glBindFramebuffer(GL_FRAMEBUFFER, id); -#endif -} - -// Disable rendering to texture -void rlDisableFramebuffer(void) -{ -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) - glBindFramebuffer(GL_FRAMEBUFFER, 0); -#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(RLGL_RENDER_TEXTURES_HINT)) - // NOTE: Maximum number of draw buffers supported is implementation dependant, - // 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(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(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); } - -// 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 -} - -// 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; -} - -// 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() -{ -#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) - { - 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_CUSTOM: glBlendFunc(RLGL.State.glBlendSrcFactor, RLGL.State.glBlendDstFactor); glBlendEquation(RLGL.State.glBlendEquation); break; - default: break; - } - - RLGL.State.currentBlendMode = mode; - } -#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) - RLGL.State.glBlendSrcFactor = glSrcFactor; - RLGL.State.glBlendDstFactor = glDstFactor; - RLGL.State.glBlendEquation = glEquation; -#endif -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition - OpenGL Debug -//---------------------------------------------------------------------------------- -#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) && defined(GRAPHICS_API_OPENGL_43) -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(LOG_WARNING, "GL: OpenGL debug message: %s", message); - TRACELOG(LOG_WARNING, " > Type: %s", msgType); - TRACELOG(LOG_WARNING, " > Source = %s", msgSource); - TRACELOG(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) -{ - // Enable OpenGL debug context if required -#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) && defined(GRAPHICS_API_OPENGL_43) - 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); // TODO: Filter message - - // 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); - - 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 - RLGL.defaultBatch = rlLoadRenderBatch(RL_DEFAULT_BATCH_BUFFERS, RL_DEFAULT_BATCH_BUFFER_ELEMENTS); - 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 - - // 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 - - // Init state: Cubemap seamless -#if defined(GRAPHICS_API_OPENGL_33) - glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Seamless cubemaps (not supported on OpenGL ES 2.0) -#endif - -#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) || defined(GRAPHICS_API_OPENGL_ES2) - // Store screen size into global variables - RLGL.State.framebufferWidth = width; - RLGL.State.framebufferHeight = height; - - TRACELOG(RL_LOG_INFO, "RLGL: Default OpenGL state initialized successfully"); - //---------------------------------------------------------- -#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) -} - -// 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 -} - -// 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 !defined(__APPLE__) - if (gladLoadGL((GLADloadfunc)loader) == 0) TRACELOG(RL_LOG_WARNING, "GLAD: Cannot load OpenGL extensions"); - else TRACELOG(RL_LOG_INFO, "GLAD: OpenGL extensions loaded successfully"); - #endif - - // Get number of supported extensions - GLint numExt = 0; - glGetIntegerv(GL_NUM_EXTENSIONS, &numExt); - TRACELOG(RL_LOG_INFO, "GL: Supported extensions count: %i", numExt); - -#if defined(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 - - // 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.texDepth = true; - RLGL.ExtSupported.maxDepthBits = 32; - RLGL.ExtSupported.texAnisoFilter = true; - RLGL.ExtSupported.texMirrorClamp = true; - #if defined(GRAPHICS_API_OPENGL_43) - if (GLAD_GL_ARB_compute_shader) RLGL.ExtSupported.computeShader = true; - if (GLAD_GL_ARB_shader_storage_buffer_object) RLGL.ExtSupported.ssbo = true; - #endif - #if !defined(__APPLE__) - // NOTE: With GLAD, we can check if an extension is supported using the GLAD_GL_xxx booleans - if (GLAD_GL_EXT_texture_compression_s3tc) RLGL.ExtSupported.texCompDXT = true; // Texture compression: DXT - if (GLAD_GL_ARB_ES3_compatibility) RLGL.ExtSupported.texCompETC2 = true; // Texture compression: ETC2/EAC - #endif -#endif // GRAPHICS_API_OPENGL_33 - -#if defined(GRAPHICS_API_OPENGL_ES2) - // Get supported extensions list - GLint numExt = 0; - const char **extList = RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB) - const char *extensions = (const char *)glGetString(GL_EXTENSIONS); // One big const string - - // NOTE: We have to duplicate string because glGetString() returns a const string - int size = strlen(extensions) + 1; // Get extensions string size in bytes - char *extensionsDup = (char *)RL_CALLOC(size, sizeof(char)); - strcpy(extensionsDup, extensions); - extList[numExt] = extensionsDup; - - for (int i = 0; i < size; i++) - { - if (extensionsDup[i] == ' ') - { - extensionsDup[i] = '\0'; - numExt++; - extList[numExt] = &extensionsDup[i + 1]; - } - } - - TRACELOG(RL_LOG_INFO, "GL: Supported extensions count: %i", numExt); - -#if defined(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 (strcmp(extList[i], (const char *)"GL_ANGLE_instanced_arrays") == 0) // Web ANGLE - { - glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedANGLE"); - glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedANGLE"); - glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorANGLE"); - - if ((glDrawArraysInstanced != NULL) && (glDrawElementsInstanced != NULL) && (glVertexAttribDivisor != NULL)) RLGL.ExtSupported.instancing = true; - } - else - { - if ((strcmp(extList[i], (const char *)"GL_EXT_draw_instanced") == 0) && // Standard EXT - (strcmp(extList[i], (const char *)"GL_EXT_instanced_arrays") == 0)) - { - glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawArraysInstancedEXT"); - glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDEXTPROC)((rlglLoadProc)loader)("glDrawElementsInstancedEXT"); - glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISOREXTPROC)((rlglLoadProc)loader)("glVertexAttribDivisorEXT"); - - 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; - - // Check depth texture support - if ((strcmp(extList[i], (const char *)"GL_OES_depth_texture") == 0) || - (strcmp(extList[i], (const char *)"GL_WEBGL_depth_texture") == 0)) RLGL.ExtSupported.texDepth = true; - - if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) RLGL.ExtSupported.maxDepthBits = 24; - if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) RLGL.ExtSupported.maxDepthBits = 32; - - // 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) - // 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 defined(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); - - /* - // Following capabilities are only supported by OpenGL 4.3 or greater - 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); - */ -#else // RLGL_SHOW_GL_DETAILS_INFO - - // Show some basic info about GL supported features - #if defined(GRAPHICS_API_OPENGL_ES2) - 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)"); - #endif - 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 // RLGL_SHOW_GL_DETAILS_INFO - -#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 -} - -// Get current OpenGL version -int rlGetVersion(void) -{ - int glVersion = 0; -#if defined(GRAPHICS_API_OPENGL_11) - glVersion = OPENGL_11; -#endif -#if defined(GRAPHICS_API_OPENGL_21) - #if defined(__APPLE__) - glVersion = OPENGL_33; // NOTE: Force OpenGL 3.3 on OSX - #else - glVersion = OPENGL_21; - #endif -#elif defined(GRAPHICS_API_OPENGL_33) - glVersion = OPENGL_33; -#endif -#if defined(GRAPHICS_API_OPENGL_43) - glVersion = OPENGL_43; -#endif -#if defined(GRAPHICS_API_OPENGL_ES2) - glVersion = OPENGL_ES_20; -#endif - return glVersion; -} - -// 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 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_MALLOC(numBuffers*sizeof(rlVertexBuffer)); - - for (int i = 0; i < numBuffers; i++) - { - batch.vertexBuffer[i].elementCount = bufferElements; - - batch.vertexBuffer[i].vertices = (float *)RL_MALLOC(bufferElements*3*4*sizeof(float)); // 3 float by vertex, 4 vertex by quad - batch.vertexBuffer[i].texcoords = (float *)RL_MALLOC(bufferElements*2*4*sizeof(float)); // 2 float by texcoord, 4 texcoord by quad - batch.vertexBuffer[i].colors = (unsigned char *)RL_MALLOC(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_MALLOC(bufferElements*6*sizeof(unsigned int)); // 6 int by quad (indices) -#endif -#if defined(GRAPHICS_API_OPENGL_ES2) - batch.vertexBuffer[i].indices = (unsigned short *)RL_MALLOC(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 < (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 color buffer (shader-location = 3) - glGenBuffers(1, &batch.vertexBuffer[i].vboId[2]); - glBindBuffer(GL_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[2]); - 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[3]); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch.vertexBuffer[i].vboId[3]); -#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_MALLOC(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(0); - glDisableVertexAttribArray(1); - glDisableVertexAttribArray(2); - glDisableVertexAttribArray(3); - 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]); - - // 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].colors); - RL_FREE(batch.vertexBuffer[i].indices); - } - - // Unload arrays - RL_FREE(batch.vertexBuffer); - RL_FREE(batch.draws); -#endif -} - -// Draw render batch -// NOTE: We require a pointer to reset batch and increase current buffer (multi-buffer) -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) - // TODO: If no data changed on the CPU arrays --> No need to re-update GPU arrays (change flag required) - if (RLGL.State.vertexCounter > 0) - { - // Activate elements VAO - if (RLGL.ExtSupported.vao) glBindVertexArray(batch->vertexBuffer[batch->currentBuffer].vaoId); - - // 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 - - // Colors buffer - glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[2]); - 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), you can call first glBufferData() with NULL pointer before glMapBuffer(). - // If you do 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 - // Probably this code could be moved somewhere else... - // 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); - float matMVPfloat[16] = { - matMVP.m0, matMVP.m1, matMVP.m2, matMVP.m3, - matMVP.m4, matMVP.m5, matMVP.m6, matMVP.m7, - matMVP.m8, matMVP.m9, matMVP.m10, matMVP.m11, - matMVP.m12, matMVP.m13, matMVP.m14, matMVP.m15 - }; - glUniformMatrix4fv(RLGL.State.currentShaderLocs[RL_SHADER_LOC_MATRIX_MVP], 1, false, matMVPfloat); - - 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: color (shader-location = 3) - glBindBuffer(GL_ARRAY_BUFFER, batch->vertexBuffer[batch->currentBuffer].vboId[2]); - 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[3]); - } - - // 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 binded 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) - // We need to define the number of indices to be processed: 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 - } - //------------------------------------------------------------------------------------------------------------ - - // 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)) - { - int currentMode = RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode; - int currentTexture = RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].textureId; - - overflow = true; - rlDrawRenderBatch(RLGL.currentBatch); // NOTE: Stereo rendering is checked inside - - // Restore state of last batch so we can continue adding vertices - 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(void *data, int width, int height, int format, int mipmapCount) -{ - glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding - - unsigned int id = 0; - - // 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) - { - 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 - - // Load the different mipmap levels - for (int i = 0; i < mipmapCount; i++) - { - unsigned int mipSize = rlGetPixelDataSize(mipWidth, mipHeight, format); - - int glInternalFormat, glFormat, glType; - rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); - - TRACELOGD("TEXTURE: Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset); - - if (glInternalFormat != -1) - { - if (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) glTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, glFormat, glType, (unsigned char *)data + mipOffset); -#if !defined(GRAPHICS_API_OPENGL_11) - else glCompressedTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, mipSize, (unsigned char *)data + mipOffset); -#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; - - // 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, just the way it's used -#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); - } -#endif - - // At this point we have the texture 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/WEBGL_depth_texture extensions -unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer) -{ - unsigned int id = 0; - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - // In case depth textures not supported, we force renderbuffer usage - if (!RLGL.ExtSupported.texDepth) useRenderBuffer = true; - - // NOTE: We let 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) - 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 (!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); - } -#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(void *data, int size, int format) -{ - unsigned int id = 0; - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - unsigned int dataSize = rlGetPixelDataSize(size, size, format); - - glGenTextures(1, &id); - glBindTexture(GL_TEXTURE_CUBE_MAP, id); - - int glInternalFormat, glFormat, glType; - rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); - - if (glInternalFormat != -1) - { - // Load cubemap faces - for (unsigned int i = 0; i < 6; i++) - { - if (data == NULL) - { - if (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) - { - if (format == RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32) - { - // Instead of using a sized internal texture format (GL_RGB16F, GL_RGB32F), we let the driver to choose the better format for us (GL_RGB) - if (RLGL.ExtSupported.texFloat32) glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, size, size, 0, GL_RGB, GL_FLOAT, NULL); - else TRACELOG(RL_LOG_WARNING, "TEXTURES: Cubemap requested format not supported"); - } - else if ((format == RL_PIXELFORMAT_UNCOMPRESSED_R32) || (format == RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32)) TRACELOG(RL_LOG_WARNING, "TEXTURES: Cubemap requested format not supported"); - else glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, size, size, 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 + i, 0, glInternalFormat, size, size, 0, glFormat, glType, (unsigned char *)data + i*dataSize); - else glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, size, size, 0, dataSize, (unsigned char *)data + i*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 - } - } - - // Set cubemap texture sampling parameters - 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 -// NOTE: We don't 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); - - int glInternalFormat, glFormat, glType; - rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); - - if ((glInternalFormat != -1) && (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB)) - { - glTexSubImage2D(GL_TEXTURE_2D, 0, offsetX, offsetY, width, height, glFormat, glType, (unsigned char *)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, int *glInternalFormat, int *glFormat, int *glType) -{ - *glInternalFormat = -1; - *glFormat = -1; - *glType = -1; - - 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) - 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 - #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; - #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 -void rlGenTextureMipmaps(unsigned int id, int width, int height, int format, int *mipmaps) -{ - 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 defined(GRAPHICS_API_OPENGL_11) - if (texIsPOT) - { - // WARNING: Manual mipmap generation only works for RGBA 32bit textures! - if (format == RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) - { - // Retrieve texture data from VRAM - void *texData = rlReadTexturePixels(id, width, height, format); - - // NOTE: Texture data size is reallocated to fit mipmaps data - // NOTE: CPU mipmap generation only supports RGBA 32bit data - int mipmapCount = rlGenTextureMipmapsData(texData, width, height); - - int size = width*height*4; - int offset = size; - - int mipWidth = width/2; - int mipHeight = height/2; - - // Load the mipmaps - for (int level = 1; level < mipmapCount; level++) - { - glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, mipWidth, mipHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)texData + offset); - - size = mipWidth*mipHeight*4; - offset += size; - - mipWidth /= 2; - mipHeight /= 2; - } - - *mipmaps = mipmapCount + 1; - RL_FREE(texData); // Once mipmaps have been generated and data has been uploaded to GPU VRAM, we can discard RAM data - - TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] Mipmaps generated manually on CPU side, total: %i", id, *mipmaps); - } - else TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] Failed to generate mipmaps for provided texture format", id); - } -#endif -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - if ((texIsPOT) || (RLGL.ExtSupported.texNPOT)) - { - //glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorythm: GL_FASTEST, GL_NICEST, GL_DONT_CARE - glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate Trilinear filtering for mipmaps - - #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); - } -#endif - else TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] Failed to generate mipmaps", id); - - glBindTexture(GL_TEXTURE_2D, 0); -} - - -// 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, we can retrieve some texture info (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); - - int glInternalFormat, glFormat, glType; - rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); - unsigned int size = rlGetPixelDataSize(width, height, format); - - if ((glInternalFormat != -1) && (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB)) - { - pixels = RL_MALLOC(size); - 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() - // We are using Option 1, just need to care for texture format on retrieval - // NOTE: This behaviour could be conditioned by graphic driver... - unsigned int fboId = rlLoadFramebuffer(width, height); - - 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); - - // We read data as RGBA because FBO texture is configured as RGBA, despite binding another texture format - pixels = (unsigned char *)RL_MALLOC(rlGetPixelDataSize(width, height, RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)); - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // Clean up temporal fbo - rlUnloadFramebuffer(fboId); -#endif - - return pixels; -} - - -// Read screen pixel data (color buffer) -unsigned char *rlReadScreenPixels(int width, int height) -{ - unsigned char *screenData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char)); - - // NOTE 1: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer - // NOTE 2: We are getting alpha channel! Be careful, it can be transparent if not cleared properly! - glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, screenData); - - // Flip image vertically! - unsigned char *imgData = (unsigned char *)RL_MALLOC(width*height*4*sizeof(unsigned char)); - - for (int y = height - 1; y >= 0; y--) - { - for (int x = 0; x < (width*4); x++) - { - imgData[((height - 1) - y)*width*4 + x] = screenData[(y*width*4) + x]; // Flip line - - // Set alpha component value to 255 (no trasparent image retrieval) - // NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it! - if (((x + 1)%4) == 0) imgData[((height - 1) - y)*width*4 + x] = 255; - } - } - - RL_FREE(screenData); - - 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(int width, int height) -{ - unsigned int fboId = 0; - -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) - glGenFramebuffers(1, &fboId); // Create the framebuffer object - glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind any framebuffer -#endif - - return fboId; -} - -// Attach color buffer texture to an fbo (unloads previous attachment) -// NOTE: Attach type: 0-Color, 1-Depth renderbuffer, 2-Depth texture -void rlFramebufferAttach(unsigned int fboId, unsigned int texId, int attachType, int texType, int mipLevel) -{ -#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT) - glBindFramebuffer(GL_FRAMEBUFFER, fboId); - - 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(RLGL_RENDER_TEXTURES_HINT) - 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(RLGL_RENDER_TEXTURES_HINT) - - // Query depth attachment to automatically delete texture/renderbuffer - int depthType = 0, depthId = 0; - glBindFramebuffer(GL_FRAMEBUFFER, id); // Bind framebuffer to query depth texture type - glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &depthType); - 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_RENDERBUFFER) 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(void *buffer, int size, bool dynamic) -{ - unsigned int id = 0; - -#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(void *buffer, int size, bool dynamic) -{ - unsigned int id = 0; - -#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, 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, 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, void *buffer) -{ - glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (unsigned short *)buffer + offset); -} - -// 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, 0, count, instances); -#endif -} - -// Draw vertex array elements instanced -void rlDrawVertexArrayElementsInstanced(int offset, int count, void *buffer, int instances) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glDrawElementsInstanced(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (unsigned short *)buffer + offset, instances); -#endif -} - -#if defined(GRAPHICS_API_OPENGL_11) -// Enable vertex state pointer -void rlEnableStatePointer(int vertexAttribType, void *buffer) -{ - 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; - } -} - -// Disable vertex state pointer -void rlDisableStatePointer(int vertexAttribType) -{ - glDisableClientState(vertexAttribType); -} -#endif - -// Load vertex array object (VAO) -unsigned int rlLoadVertexArray(void) -{ - unsigned int vaoId = 0; -#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, void *pointer) -{ -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - glVertexAttribPointer(index, compSize, type, normalized, stride, pointer); -#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 shader from code strings -// NOTE: If shader string is NULL, using default vertex/fragment shaders -unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode) -{ - unsigned int id = 0; - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - unsigned int vertexShaderId = RLGL.State.defaultVShaderId; - unsigned int fragmentShaderId = RLGL.State.defaultFShaderId; - - if (vsCode != NULL) vertexShaderId = rlCompileShader(vsCode, GL_VERTEX_SHADER); - if (fsCode != NULL) fragmentShaderId = rlCompileShader(fsCode, GL_FRAGMENT_SHADER); - - if ((vertexShaderId == RLGL.State.defaultVShaderId) && (fragmentShaderId == RLGL.State.defaultFShaderId)) id = RLGL.State.defaultShaderId; - else - { - id = rlLoadShaderProgram(vertexShaderId, fragmentShaderId); - - if (vertexShaderId != RLGL.State.defaultVShaderId) - { - // Detach shader before deletion to make sure memory is freed - glDetachShader(id, vertexShaderId); - glDeleteShader(vertexShaderId); - } - if (fragmentShaderId != RLGL.State.defaultFShaderId) - { - // Detach shader before deletion to make sure memory is freed - glDetachShader(id, fragmentShaderId); - glDeleteShader(fragmentShaderId); - } - - if (id == 0) - { - TRACELOG(RL_LOG_WARNING, "SHADER: Failed to load custom shader code"); - id = RLGL.State.defaultShaderId; - } - } - - // 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; - - TRACELOGD("SHADER: [ID %i] Active uniform (%s) set at location: %i", id, name, glGetUniformLocation(id, name)); - } -#endif - - return id; -} - -// Compile custom shader and return shader id -unsigned int rlCompileShader(const char *shaderCode, int type) -{ - unsigned int shader = 0; - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - shader = glCreateShader(type); - glShaderSource(shader, 1, &shaderCode, NULL); - - GLint success = 0; - glCompileShader(shader); - glGetShaderiv(shader, 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", shader); break; - case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to compile fragment shader code", shader); 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", shader); break; - #endif - default: break; - } - - int maxLength = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); - - if (maxLength > 0) - { - int length = 0; - char *log = RL_CALLOC(maxLength, sizeof(char)); - glGetShaderInfoLog(shader, maxLength, &length, log); - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Compile error: %s", shader, log); - RL_FREE(log); - } - } - else - { - switch (type) - { - case GL_VERTEX_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Vertex shader compiled successfully", shader); break; - case GL_FRAGMENT_SHADER: TRACELOG(RL_LOG_INFO, "SHADER: [ID %i] Fragment shader compiled successfully", shader); 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", shader); break; - #endif - default: break; - } - } -#endif - - return shader; -} - -// Load custom shader strings and return program id -unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId) -{ - unsigned int program = 0; - -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - GLint success = 0; - program = glCreateProgram(); - - glAttachShader(program, vShaderId); - glAttachShader(program, fShaderId); - - // NOTE: Default attribute shader locations must be binded before linking - glBindAttribLocation(program, 0, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION); - glBindAttribLocation(program, 1, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD); - glBindAttribLocation(program, 2, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL); - glBindAttribLocation(program, 3, RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR); - glBindAttribLocation(program, 4, RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT); - glBindAttribLocation(program, 5, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2); - - // NOTE: If some attrib name is no found on the shader, it locations becomes -1 - - glLinkProgram(program); - - // NOTE: All uniform variables are intitialised to 0 when a program links - - glGetProgramiv(program, GL_LINK_STATUS, &success); - - if (success == GL_FALSE) - { - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link shader program", program); - - int maxLength = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); - - if (maxLength > 0) - { - int length = 0; - char *log = RL_CALLOC(maxLength, sizeof(char)); - glGetProgramInfoLog(program, maxLength, &length, log); - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", program, log); - RL_FREE(log); - } - - glDeleteProgram(program); - - program = 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", program); - } -#endif - return program; -} - -// 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 -int rlGetLocationUniform(unsigned int shaderId, const char *uniformName) -{ - int location = -1; -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - location = glGetUniformLocation(shaderId, 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 -int rlGetLocationAttrib(unsigned int shaderId, const char *attribName) -{ - int location = -1; -#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2) - location = glGetAttribLocation(shaderId, 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; - 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) - float matfloat[16] = { - mat.m0, mat.m1, mat.m2, mat.m3, - mat.m4, mat.m5, mat.m6, mat.m7, - mat.m8, mat.m9, mat.m10, mat.m11, - mat.m12, mat.m13, mat.m14, mat.m15 - }; - glUniformMatrix4fv(locIndex, 1, false, matfloat); -#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) 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 -} - -// Load compute shader program -unsigned int rlLoadComputeShaderProgram(unsigned int shaderId) -{ - unsigned int program = 0; - -#if defined(GRAPHICS_API_OPENGL_43) - GLint success = 0; - program = glCreateProgram(); - glAttachShader(program, shaderId); - glLinkProgram(program); - - // NOTE: All uniform variables are intitialised to 0 when a program links - - glGetProgramiv(program, GL_LINK_STATUS, &success); - - if (success == GL_FALSE) - { - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Failed to link compute shader program", program); - - int maxLength = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength); - - if (maxLength > 0) - { - int length = 0; - char *log = RL_CALLOC(maxLength, sizeof(char)); - glGetProgramInfoLog(program, maxLength, &length, log); - TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", program, log); - RL_FREE(log); - } - - glDeleteProgram(program); - - program = 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", program); - } -#endif - - return program; -} - -// 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 long long 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); -#endif - - return ssbo; -} - -// Unload shader storage buffer object (SSBO) -void rlUnloadShaderBuffer(unsigned int ssboId) -{ -#if defined(GRAPHICS_API_OPENGL_43) - glDeleteBuffers(1, &ssboId); -#endif -} - -// Update SSBO buffer data -void rlUpdateShaderBufferElements(unsigned int id, const void *data, unsigned long long dataSize, unsigned long long 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 long long rlGetShaderBufferSize(unsigned int id) -{ - long long size = 0; - -#if defined(GRAPHICS_API_OPENGL_43) - glBindBuffer(GL_SHADER_STORAGE_BUFFER, id); - glGetInteger64v(GL_SHADER_STORAGE_BUFFER_SIZE, &size); -#endif - - return (size > 0)? size : 0; -} - -// Read SSBO buffer data -void rlReadShaderBufferElements(unsigned int id, void *dest, unsigned long long count, unsigned long long 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 rlCopyBuffersElements(unsigned int destId, unsigned int srcId, unsigned long long destOffset, unsigned long long srcOffset, unsigned long long 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, unsigned int format, int readonly) -{ -#if defined(GRAPHICS_API_OPENGL_43) - 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); -#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 - // Is this the right order? or should we start with the first stored matrix instead of the last one? - //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) -RLAPI 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) -RLAPI 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(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)0); // Positions - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 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(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)0); // Positions - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(3*sizeof(float))); // Normals - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 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_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 specific 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_ES2) - "#version 100 \n" - "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_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 kept for re-use - RLGL.State.defaultVShaderId = rlCompileShader(defaultVShaderCode, GL_VERTEX_SHADER); // Compile default vertex shader - RLGL.State.defaultFShaderId = rlCompileShader(defaultFShaderCode, GL_FRAGMENT_SHADER); // Compile default fragment shader - - RLGL.State.defaultShaderId = rlLoadShaderProgram(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, "vertexPosition"); - RLGL.State.defaultShaderLocs[RL_SHADER_LOC_VERTEX_TEXCOORD01] = glGetAttribLocation(RLGL.State.defaultShaderId, "vertexTexCoord"); - RLGL.State.defaultShaderLocs[RL_SHADER_LOC_VERTEX_COLOR] = glGetAttribLocation(RLGL.State.defaultShaderId, "vertexColor"); - - // Set default shader locations: uniform locations - RLGL.State.defaultShaderLocs[RL_SHADER_LOC_MATRIX_MVP] = glGetUniformLocation(RLGL.State.defaultShaderId, "mvp"); - RLGL.State.defaultShaderLocs[RL_SHADER_LOC_COLOR_DIFFUSE] = glGetUniformLocation(RLGL.State.defaultShaderId, "colDiffuse"); - RLGL.State.defaultShaderLocs[RL_SHADER_LOC_MAP_DIFFUSE] = glGetUniformLocation(RLGL.State.defaultShaderId, "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 defined(RLGL_SHOW_GL_DETAILS_INFO) -// Get compressed format official GL identifier name -static char *rlGetCompressedFormatName(int format) -{ - static char compName[64] = { 0 }; - memset(compName, 0, 64); - - switch (format) - { - // GL_EXT_texture_compression_s3tc - case 0x83F0: strcpy(compName, "GL_COMPRESSED_RGB_S3TC_DXT1_EXT"); break; - case 0x83F1: strcpy(compName, "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT"); break; - case 0x83F2: strcpy(compName, "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT"); break; - case 0x83F3: strcpy(compName, "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT"); break; - // GL_3DFX_texture_compression_FXT1 - case 0x86B0: strcpy(compName, "GL_COMPRESSED_RGB_FXT1_3DFX"); break; - case 0x86B1: strcpy(compName, "GL_COMPRESSED_RGBA_FXT1_3DFX"); break; - // GL_IMG_texture_compression_pvrtc - case 0x8C00: strcpy(compName, "GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG"); break; - case 0x8C01: strcpy(compName, "GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG"); break; - case 0x8C02: strcpy(compName, "GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG"); break; - case 0x8C03: strcpy(compName, "GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG"); break; - // GL_OES_compressed_ETC1_RGB8_texture - case 0x8D64: strcpy(compName, "GL_ETC1_RGB8_OES"); break; - // GL_ARB_texture_compression_rgtc - case 0x8DBB: strcpy(compName, "GL_COMPRESSED_RED_RGTC1"); break; - case 0x8DBC: strcpy(compName, "GL_COMPRESSED_SIGNED_RED_RGTC1"); break; - case 0x8DBD: strcpy(compName, "GL_COMPRESSED_RG_RGTC2"); break; - case 0x8DBE: strcpy(compName, "GL_COMPRESSED_SIGNED_RG_RGTC2"); break; - // GL_ARB_texture_compression_bptc - case 0x8E8C: strcpy(compName, "GL_COMPRESSED_RGBA_BPTC_UNORM_ARB"); break; - case 0x8E8D: strcpy(compName, "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB"); break; - case 0x8E8E: strcpy(compName, "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB"); break; - case 0x8E8F: strcpy(compName, "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB"); break; - // GL_ARB_ES3_compatibility - case 0x9274: strcpy(compName, "GL_COMPRESSED_RGB8_ETC2"); break; - case 0x9275: strcpy(compName, "GL_COMPRESSED_SRGB8_ETC2"); break; - case 0x9276: strcpy(compName, "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2"); break; - case 0x9277: strcpy(compName, "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2"); break; - case 0x9278: strcpy(compName, "GL_COMPRESSED_RGBA8_ETC2_EAC"); break; - case 0x9279: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC"); break; - case 0x9270: strcpy(compName, "GL_COMPRESSED_R11_EAC"); break; - case 0x9271: strcpy(compName, "GL_COMPRESSED_SIGNED_R11_EAC"); break; - case 0x9272: strcpy(compName, "GL_COMPRESSED_RG11_EAC"); break; - case 0x9273: strcpy(compName, "GL_COMPRESSED_SIGNED_RG11_EAC"); break; - // GL_KHR_texture_compression_astc_hdr - case 0x93B0: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_4x4_KHR"); break; - case 0x93B1: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_5x4_KHR"); break; - case 0x93B2: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_5x5_KHR"); break; - case 0x93B3: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_6x5_KHR"); break; - case 0x93B4: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_6x6_KHR"); break; - case 0x93B5: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_8x5_KHR"); break; - case 0x93B6: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_8x6_KHR"); break; - case 0x93B7: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_8x8_KHR"); break; - case 0x93B8: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x5_KHR"); break; - case 0x93B9: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x6_KHR"); break; - case 0x93BA: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x8_KHR"); break; - case 0x93BB: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_10x10_KHR"); break; - case 0x93BC: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_12x10_KHR"); break; - case 0x93BD: strcpy(compName, "GL_COMPRESSED_RGBA_ASTC_12x12_KHR"); break; - case 0x93D0: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR"); break; - case 0x93D1: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR"); break; - case 0x93D2: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR"); break; - case 0x93D3: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR"); break; - case 0x93D4: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR"); break; - case 0x93D5: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR"); break; - case 0x93D6: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR"); break; - case 0x93D7: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR"); break; - case 0x93D8: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR"); break; - case 0x93D9: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR"); break; - case 0x93DA: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR"); break; - case 0x93DB: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR"); break; - case 0x93DC: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR"); break; - case 0x93DD: strcpy(compName, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR"); break; - default: strcpy(compName, "GL_COMPRESSED_UNKNOWN"); break; - } - - return compName; -} -#endif // RLGL_SHOW_GL_DETAILS_INFO - -#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 - -#if defined(GRAPHICS_API_OPENGL_11) -// Mipmaps data is generated after image data -// NOTE: Only works with RGBA (4 bytes) data! -static int rlGenTextureMipmapsData(unsigned char *data, int baseWidth, int baseHeight) -{ - int mipmapCount = 1; // Required mipmap levels count (including base level) - int width = baseWidth; - int height = baseHeight; - int size = baseWidth*baseHeight*4; // Size in bytes (will include mipmaps...), RGBA only - - // Count mipmap levels required - while ((width != 1) && (height != 1)) - { - width /= 2; - height /= 2; - - TRACELOGD("TEXTURE: Next mipmap size: %i x %i", width, height); - - mipmapCount++; - - size += (width*height*4); // Add mipmap size (in bytes) - } - - TRACELOGD("TEXTURE: Total mipmaps required: %i", mipmapCount); - TRACELOGD("TEXTURE: Total size of data required: %i", size); - - unsigned char *temp = RL_REALLOC(data, size); - - if (temp != NULL) data = temp; - else TRACELOG(RL_LOG_WARNING, "TEXTURE: Failed to re-allocate required mipmaps memory"); - - width = baseWidth; - height = baseHeight; - size = (width*height*4); // RGBA: 4 bytes - - // Generate mipmaps - // NOTE: Every mipmap data is stored after data (RGBA - 4 bytes) - unsigned char *image = (unsigned char *)RL_MALLOC(width*height*4); - unsigned char *mipmap = NULL; - int offset = 0; - - for (int i = 0; i < size; i += 4) - { - image[i] = data[i]; - image[i + 1] = data[i + 1]; - image[i + 2] = data[i + 2]; - image[i + 3] = data[i + 3]; - } - - TRACELOGD("TEXTURE: Mipmap base size (%ix%i)", width, height); - - for (int mip = 1; mip < mipmapCount; mip++) - { - mipmap = rlGenNextMipmapData(image, width, height); - - offset += (width*height*4); // Size of last mipmap - - width /= 2; - height /= 2; - size = (width*height*4); // Mipmap size to store after offset - - // Add mipmap to data - for (int i = 0; i < size; i += 4) - { - data[offset + i] = mipmap[i]; - data[offset + i + 1] = mipmap[i + 1]; - data[offset + i + 2] = mipmap[i + 2]; - data[offset + i + 3] = mipmap[i + 3]; - } - - RL_FREE(image); - - image = mipmap; - mipmap = NULL; - } - - RL_FREE(mipmap); // free mipmap data - - return mipmapCount; -} - -// Manual mipmap generation (basic scaling algorithm) -static unsigned char *rlGenNextMipmapData(unsigned char *srcData, int srcWidth, int srcHeight) -{ - int x2 = 0; - int y2 = 0; - unsigned char prow[4]; - unsigned char pcol[4]; - - int width = srcWidth/2; - int height = srcHeight/2; - - unsigned char *mipmap = (unsigned char *)RL_MALLOC(width*height*4); - - // Scaling algorithm works perfectly (box-filter) - for (int y = 0; y < height; y++) - { - y2 = 2*y; - - for (int x = 0; x < width; x++) - { - x2 = 2*x; - - prow[0] = (srcData[(y2*srcWidth + x2)*4 + 0] + srcData[(y2*srcWidth + x2 + 1)*4 + 0])/2; - prow[1] = (srcData[(y2*srcWidth + x2)*4 + 1] + srcData[(y2*srcWidth + x2 + 1)*4 + 1])/2; - prow[2] = (srcData[(y2*srcWidth + x2)*4 + 2] + srcData[(y2*srcWidth + x2 + 1)*4 + 2])/2; - prow[3] = (srcData[(y2*srcWidth + x2)*4 + 3] + srcData[(y2*srcWidth + x2 + 1)*4 + 3])/2; - - pcol[0] = (srcData[((y2 + 1)*srcWidth + x2)*4 + 0] + srcData[((y2 + 1)*srcWidth + x2 + 1)*4 + 0])/2; - pcol[1] = (srcData[((y2 + 1)*srcWidth + x2)*4 + 1] + srcData[((y2 + 1)*srcWidth + x2 + 1)*4 + 1])/2; - pcol[2] = (srcData[((y2 + 1)*srcWidth + x2)*4 + 2] + srcData[((y2 + 1)*srcWidth + x2 + 1)*4 + 2])/2; - pcol[3] = (srcData[((y2 + 1)*srcWidth + x2)*4 + 3] + srcData[((y2 + 1)*srcWidth + x2 + 1)*4 + 3])/2; - - mipmap[(y*width + x)*4 + 0] = (prow[0] + pcol[0])/2; - mipmap[(y*width + x)*4 + 1] = (prow[1] + pcol[1])/2; - mipmap[(y*width + x)*4 + 2] = (prow[2] + pcol[2])/2; - mipmap[(y*width + x)*4 + 3] = (prow[3] + pcol[3])/2; - } - } - - TRACELOGD("TEXTURE: Mipmap generated successfully (%ix%i)", width, height); - - return mipmap; -} -#endif // GRAPHICS_API_OPENGL_11 - -// 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_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: bpp = 4; 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: bpp = 8; break; - case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break; - default: break; - } - - dataSize = width*height*bpp/8; // Total data size in bytes - - // Most compressed formats works on 4x4 blocks, - // if texture is smaller, minimum dataSize is 8 or 16 - if ((width < 4) && (height < 4)) - { - if ((format >= RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8; - else if ((format >= RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16; - } - - return dataSize; -} - -// Auxiliar math functions - -// Get identity matrix -static Matrix rlMatrixIdentity(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; -} - -// 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; -} - -#endif // RLGL_IMPLEMENTATION diff --git a/include/rmem.h b/include/rmem.h deleted file mode 100644 index 43005cf..0000000 --- a/include/rmem.h +++ /dev/null @@ -1,751 +0,0 @@ -/********************************************************************************************** -* -* rmem - raylib memory pool and objects pool -* -* A quick, efficient, and minimal free list and arena-based allocator -* -* PURPOSE: -* - A quicker, efficient memory allocator alternative to 'malloc' and friends. -* - Reduce the possibilities of memory leaks for beginner developers using Raylib. -* - Being able to flexibly range check memory if necessary. -* -* CONFIGURATION: -* -* #define RMEM_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. -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2019 Kevin 'Assyrianic' Yonan (@assyrianic) and reviewed by 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 RMEM_H -#define RMEM_H - -#include -#include - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- -#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED) - #define RMEMAPI __declspec(dllexport) // We are building library as a Win32 shared library (.dll) -#elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED) - #define RMEMAPI __declspec(dllimport) // We are using library as a Win32 shared library (.dll) -#else - #define RMEMAPI // We are building or using library as a static library (or Linux shared library) -#endif - -#define RMEM_VERSION "v1.3" // changelog at bottom of header. - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- - -// Memory Pool -typedef struct MemNode MemNode; -struct MemNode { - size_t size; - MemNode *next, *prev; -}; - -// Freelist implementation -typedef struct AllocList { - MemNode *head, *tail; - size_t len; -} AllocList; - -// Arena allocator. -typedef struct Arena { - uintptr_t mem, offs; - size_t size; -} Arena; - - -enum { - MEMPOOL_BUCKET_SIZE = 8, - MEMPOOL_BUCKET_BITS = (sizeof(uintptr_t) >> 1) + 1, - MEM_SPLIT_THRESHOLD = sizeof(uintptr_t) * 4 -}; - -typedef struct MemPool { - AllocList large, buckets[MEMPOOL_BUCKET_SIZE]; - Arena arena; -} MemPool; - - -// Object Pool -typedef struct ObjPool { - uintptr_t mem, offs; - size_t objSize, freeBlocks, memSize; -} ObjPool; - - -// Double-Ended Stack aka Deque -typedef struct BiStack { - uintptr_t mem, front, back; - size_t size; -} BiStack; - - -#if defined(__cplusplus) -extern "C" { // Prevents name mangling of functions -#endif - -//------------------------------------------------------------------------------------ -// Functions Declaration - Memory Pool -//------------------------------------------------------------------------------------ -RMEMAPI MemPool CreateMemPool(size_t bytes); -RMEMAPI MemPool CreateMemPoolFromBuffer(void *buf, size_t bytes); -RMEMAPI void DestroyMemPool(MemPool *mempool); - -RMEMAPI void *MemPoolAlloc(MemPool *mempool, size_t bytes); -RMEMAPI void *MemPoolRealloc(MemPool *mempool, void *ptr, size_t bytes); -RMEMAPI void MemPoolFree(MemPool *mempool, void *ptr); -RMEMAPI void MemPoolCleanUp(MemPool *mempool, void **ptrref); -RMEMAPI void MemPoolReset(MemPool *mempool); -RMEMAPI size_t GetMemPoolFreeMemory(const MemPool mempool); - -//------------------------------------------------------------------------------------ -// Functions Declaration - Object Pool -//------------------------------------------------------------------------------------ -RMEMAPI ObjPool CreateObjPool(size_t objsize, size_t len); -RMEMAPI ObjPool CreateObjPoolFromBuffer(void *buf, size_t objsize, size_t len); -RMEMAPI void DestroyObjPool(ObjPool *objpool); - -RMEMAPI void *ObjPoolAlloc(ObjPool *objpool); -RMEMAPI void ObjPoolFree(ObjPool *objpool, void *ptr); -RMEMAPI void ObjPoolCleanUp(ObjPool *objpool, void **ptrref); - -//------------------------------------------------------------------------------------ -// Functions Declaration - Double-Ended Stack -//------------------------------------------------------------------------------------ -RMEMAPI BiStack CreateBiStack(size_t len); -RMEMAPI BiStack CreateBiStackFromBuffer(void *buf, size_t len); -RMEMAPI void DestroyBiStack(BiStack *destack); - -RMEMAPI void *BiStackAllocFront(BiStack *destack, size_t len); -RMEMAPI void *BiStackAllocBack(BiStack *destack, size_t len); - -RMEMAPI void BiStackResetFront(BiStack *destack); -RMEMAPI void BiStackResetBack(BiStack *destack); -RMEMAPI void BiStackResetAll(BiStack *destack); - -RMEMAPI intptr_t BiStackMargins(BiStack destack); - -#ifdef __cplusplus -} -#endif - -#endif // RMEM_H - -/*********************************************************************************** -* -* RMEM IMPLEMENTATION -* -************************************************************************************/ - -#if defined(RMEM_IMPLEMENTATION) - -#include // Required for: -#include // Required for: -#include // Required for: - -//---------------------------------------------------------------------------------- -// Defines and Macros -//---------------------------------------------------------------------------------- - -// Make sure restrict type qualifier for pointers is defined -// NOTE: Not supported by C++, it is a C only keyword -#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) || defined(_MSC_VER) - #ifndef restrict - #define restrict __restrict - #endif -#endif - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -// ... - -//---------------------------------------------------------------------------------- -// Module specific Functions Declaration -//---------------------------------------------------------------------------------- -static inline size_t __AlignSize(const size_t size, const size_t align) -{ - return (size + (align - 1)) & -align; -} - -static MemNode *__SplitMemNode(MemNode *const node, const size_t bytes) -{ - uintptr_t n = ( uintptr_t )node; - MemNode *const r = ( MemNode* )(n + (node->size - bytes)); - node->size -= bytes; - r->size = bytes; - return r; -} - -static void __InsertMemNodeBefore(AllocList *const list, MemNode *const insert, MemNode *const curr) -{ - insert->next = curr; - if (curr->prev==NULL) list->head = insert; - else - { - insert->prev = curr->prev; - curr->prev->next = insert; - } - curr->prev = insert; -} - -static void __ReplaceMemNode(MemNode *const old, MemNode *const replace) -{ - replace->prev = old->prev; - replace->next = old->next; - if( old->prev != NULL ) - old->prev->next = replace; - if( old->next != NULL ) - old->next->prev = replace; -} - - -static MemNode *__RemoveMemNode(AllocList *const list, MemNode *const node) -{ - if (node->prev != NULL) node->prev->next = node->next; - else - { - list->head = node->next; - if (list->head != NULL) list->head->prev = NULL; - else list->tail = NULL; - } - - if (node->next != NULL) node->next->prev = node->prev; - else - { - list->tail = node->prev; - if (list->tail != NULL) list->tail->next = NULL; - else list->head = NULL; - } - list->len--; - return node; -} - -static MemNode *__FindMemNode(AllocList *const list, const size_t bytes) -{ - for (MemNode *node = list->head; node != NULL; node = node->next) - { - if (node->size < bytes) continue; - // close in size - reduce fragmentation by not splitting. - else if (node->size <= bytes + MEM_SPLIT_THRESHOLD) return __RemoveMemNode(list, node); - else return __SplitMemNode(node, bytes); - } - return NULL; -} - -static void __InsertMemNode(MemPool *const mempool, AllocList *const list, MemNode *const node, const bool is_bucket) -{ - if (list->head == NULL) - { - list->head = node; - list->len++; - } - else - { - for (MemNode *iter = list->head; iter != NULL; iter = iter->next) - { - if (( uintptr_t )iter == mempool->arena.offs) - { - mempool->arena.offs += iter->size; - __RemoveMemNode(list, iter); - iter = list->head; - if (iter == NULL) { - list->head = node; - return; - } - } - const uintptr_t inode = ( uintptr_t )node; - const uintptr_t iiter = ( uintptr_t )iter; - const uintptr_t iter_end = iiter + iter->size; - const uintptr_t node_end = inode + node->size; - if (iter==node) return; - else if (iter < node) - { - // node was coalesced prior. - if (iter_end > inode) return; - else if (iter_end==inode && !is_bucket) - { - // if we can coalesce, do so. - iter->size += node->size; - return; - } - else if (iter->next == NULL) - { - // we reached the end of the free list -> append the node - iter->next = node; - node->prev = iter; - list->len++; - return; - } - } - else if (iter > node) - { - // Address sort, lowest to highest aka ascending order. - if (iiter < node_end) return; - else if (iter==list->head && !is_bucket) - { - if (iter_end==inode) iter->size += node->size; - else if (node_end==iiter) - { - node->size += list->head->size; - node->next = list->head->next; - node->prev = NULL; - list->head = node; - } - else - { - node->next = iter; - node->prev = NULL; - iter->prev = node; - list->head = node; - list->len++; - } - return; - } - else if (iter_end==inode && !is_bucket) - { - // if we can coalesce, do so. - iter->size += node->size; - return; - } - else - { - __InsertMemNodeBefore(list, node, iter); - list->len++; - return; - } - } - } - } -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Memory Pool -//---------------------------------------------------------------------------------- - -MemPool CreateMemPool(const size_t size) -{ - MemPool mempool = { 0 }; - - if (size == 0) return mempool; - else - { - // Align the mempool size to at least the size of an alloc node. - uint8_t *const restrict buf = malloc(size*sizeof *buf); - if (buf==NULL) return mempool; - else - { - mempool.arena.size = size; - mempool.arena.mem = ( uintptr_t )buf; - mempool.arena.offs = mempool.arena.mem + mempool.arena.size; - return mempool; - } - } -} - -MemPool CreateMemPoolFromBuffer(void *const restrict buf, const size_t size) -{ - MemPool mempool = { 0 }; - if ((size == 0) || (buf == NULL) || (size <= sizeof(MemNode))) return mempool; - else - { - mempool.arena.size = size; - mempool.arena.mem = ( uintptr_t )buf; - mempool.arena.offs = mempool.arena.mem + mempool.arena.size; - return mempool; - } -} - -void DestroyMemPool(MemPool *const restrict mempool) -{ - if (mempool->arena.mem == 0) return; - else - { - void *const restrict ptr = ( void* )mempool->arena.mem; - free(ptr); - *mempool = (MemPool){ 0 }; - } -} - -void *MemPoolAlloc(MemPool *const mempool, const size_t size) -{ - if ((size == 0) || (size > mempool->arena.size)) return NULL; - else - { - MemNode *new_mem = NULL; - const size_t ALLOC_SIZE = __AlignSize(size + sizeof *new_mem, sizeof(intptr_t)); - const size_t BUCKET_SLOT = (ALLOC_SIZE >> MEMPOOL_BUCKET_BITS) - 1; - - // If the size is small enough, let's check if our buckets has a fitting memory block. - if (BUCKET_SLOT < MEMPOOL_BUCKET_SIZE) - { - new_mem = __FindMemNode(&mempool->buckets[BUCKET_SLOT], ALLOC_SIZE); - } - else if (mempool->large.head != NULL) - { - new_mem = __FindMemNode(&mempool->large, ALLOC_SIZE); - } - - if (new_mem == NULL) - { - // not enough memory to support the size! - if ((mempool->arena.offs - ALLOC_SIZE) < mempool->arena.mem) return NULL; - else - { - // Couldn't allocate from a freelist, allocate from available mempool. - // Subtract allocation size from the mempool. - mempool->arena.offs -= ALLOC_SIZE; - - // Use the available mempool space as the new node. - new_mem = ( MemNode* )mempool->arena.offs; - new_mem->size = ALLOC_SIZE; - } - } - - // Visual of the allocation block. - // -------------- - // | mem size | lowest addr of block - // | next node | 12 byte (32-bit) header - // | prev node | 24 byte (64-bit) header - // |------------| - // | alloc'd | - // | memory | - // | space | highest addr of block - // -------------- - new_mem->next = new_mem->prev = NULL; - uint8_t *const restrict final_mem = ( uint8_t* )new_mem + sizeof *new_mem; - return memset(final_mem, 0, new_mem->size - sizeof *new_mem); - } -} - -void *MemPoolRealloc(MemPool *const restrict mempool, void *const ptr, const size_t size) -{ - if (size > mempool->arena.size) return NULL; - // NULL ptr should make this work like regular Allocation. - else if (ptr == NULL) return MemPoolAlloc(mempool, size); - else if ((uintptr_t)ptr - sizeof(MemNode) < mempool->arena.mem) return NULL; - else - { - MemNode *const node = ( MemNode* )(( uint8_t* )ptr - sizeof *node); - const size_t NODE_SIZE = sizeof *node; - uint8_t *const resized_block = MemPoolAlloc(mempool, size); - if (resized_block == NULL) return NULL; - else - { - MemNode *const resized = ( MemNode* )(resized_block - sizeof *resized); - memmove(resized_block, ptr, (node->size > resized->size)? (resized->size - NODE_SIZE) : (node->size - NODE_SIZE)); - MemPoolFree(mempool, ptr); - return resized_block; - } - } -} - -void MemPoolFree(MemPool *const restrict mempool, void *const ptr) -{ - const uintptr_t p = ( uintptr_t )ptr; - if ((ptr == NULL) || (p - sizeof(MemNode) < mempool->arena.mem)) return; - else - { - // Behind the actual pointer data is the allocation info. - const uintptr_t block = p - sizeof(MemNode); - MemNode *const mem_node = ( MemNode* )block; - const size_t BUCKET_SLOT = (mem_node->size >> MEMPOOL_BUCKET_BITS) - 1; - - // Make sure the pointer data is valid. - if ((block < mempool->arena.offs) || - ((block - mempool->arena.mem) > mempool->arena.size) || - (mem_node->size == 0) || - (mem_node->size > mempool->arena.size)) return; - // If the mem_node is right at the arena offs, then merge it back to the arena. - else if (block == mempool->arena.offs) - { - mempool->arena.offs += mem_node->size; - } - else - { - // try to place it into bucket or large freelist. - struct AllocList *const l = (BUCKET_SLOT < MEMPOOL_BUCKET_SIZE) ? &mempool->buckets[BUCKET_SLOT] : &mempool->large; - __InsertMemNode(mempool, l, mem_node, (BUCKET_SLOT < MEMPOOL_BUCKET_SIZE)); - } - } -} - -void MemPoolCleanUp(MemPool *const restrict mempool, void **const ptrref) -{ - if ((ptrref == NULL) || (*ptrref == NULL)) return; - else - { - MemPoolFree(mempool, *ptrref); - *ptrref = NULL; - } -} - -size_t GetMemPoolFreeMemory(const MemPool mempool) -{ - size_t total_remaining = mempool.arena.offs - mempool.arena.mem; - - for (MemNode *n=mempool.large.head; n != NULL; n = n->next) total_remaining += n->size; - - for (size_t i=0; inext) total_remaining += n->size; - - return total_remaining; -} - -void MemPoolReset(MemPool *const mempool) -{ - mempool->large.head = mempool->large.tail = NULL; - mempool->large.len = 0; - for (size_t i = 0; i < MEMPOOL_BUCKET_SIZE; i++) - { - mempool->buckets[i].head = mempool->buckets[i].tail = NULL; - mempool->buckets[i].len = 0; - } - mempool->arena.offs = mempool->arena.mem + mempool->arena.size; -} - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Object Pool -//---------------------------------------------------------------------------------- - -ObjPool CreateObjPool(const size_t objsize, const size_t len) -{ - ObjPool objpool = { 0 }; - if ((len == 0) || (objsize == 0)) return objpool; - else - { - const size_t aligned_size = __AlignSize(objsize, sizeof(size_t)); - uint8_t *const restrict buf = calloc(len, aligned_size); - if (buf == NULL) return objpool; - objpool.objSize = aligned_size; - objpool.memSize = objpool.freeBlocks = len; - objpool.mem = ( uintptr_t )buf; - - for (size_t i=0; imem == 0) return; - else - { - void *const restrict ptr = ( void* )objpool->mem; - free(ptr); - *objpool = (ObjPool){0}; - } -} - -void *ObjPoolAlloc(ObjPool *const objpool) -{ - if (objpool->freeBlocks > 0) - { - // For first allocation, head points to the very first index. - // Head = &pool[0]; - // ret = Head == ret = &pool[0]; - size_t *const restrict block = ( size_t* )objpool->offs; - objpool->freeBlocks--; - - // after allocating, we set head to the address of the index that *Head holds. - // Head = &pool[*Head * pool.objsize]; - objpool->offs = (objpool->freeBlocks != 0)? objpool->mem + (*block*objpool->objSize) : 0; - return memset(block, 0, objpool->objSize); - } - else return NULL; -} - -void ObjPoolFree(ObjPool *const restrict objpool, void *const ptr) -{ - uintptr_t block = (uintptr_t)ptr; - if ((ptr == NULL) || (block < objpool->mem) || (block > objpool->mem + objpool->memSize*objpool->objSize)) return; - else - { - // When we free our pointer, we recycle the pointer space to store the previous index and then we push it as our new head. - // *p = index of Head in relation to the buffer; - // Head = p; - size_t *const restrict index = ( size_t* )block; - *index = (objpool->offs != 0)? (objpool->offs - objpool->mem)/objpool->objSize : objpool->memSize; - objpool->offs = block; - objpool->freeBlocks++; - } -} - -void ObjPoolCleanUp(ObjPool *const restrict objpool, void **const restrict ptrref) -{ - if (ptrref == NULL) return; - else - { - ObjPoolFree(objpool, *ptrref); - *ptrref = NULL; - } -} - - -//---------------------------------------------------------------------------------- -// Module Functions Definition - Double-Ended Stack -//---------------------------------------------------------------------------------- -BiStack CreateBiStack(const size_t len) -{ - BiStack destack = { 0 }; - if (len == 0) return destack; - - uint8_t *const buf = malloc(len*sizeof *buf); - if (buf==NULL) return destack; - destack.size = len; - destack.mem = ( uintptr_t )buf; - destack.front = destack.mem; - destack.back = destack.mem + len; - return destack; -} - -BiStack CreateBiStackFromBuffer(void *const buf, const size_t len) -{ - BiStack destack = { 0 }; - if (len == 0 || buf == NULL) return destack; - else - { - destack.size = len; - destack.mem = destack.front = ( uintptr_t )buf; - destack.back = destack.mem + len; - return destack; - } -} - -void DestroyBiStack(BiStack *const restrict destack) -{ - if (destack->mem == 0) return; - else - { - uint8_t *const restrict buf = ( uint8_t* )destack->mem; - free(buf); - *destack = (BiStack){0}; - } -} - -void *BiStackAllocFront(BiStack *const restrict destack, const size_t len) -{ - if (destack->mem == 0) return NULL; - else - { - const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t)); - // front end arena is too high! - if (destack->front + ALIGNED_LEN >= destack->back) return NULL; - else - { - uint8_t *const restrict ptr = ( uint8_t* )destack->front; - destack->front += ALIGNED_LEN; - return ptr; - } - } -} - -void *BiStackAllocBack(BiStack *const restrict destack, const size_t len) -{ - if (destack->mem == 0) return NULL; - else - { - const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t)); - // back end arena is too low - if (destack->back - ALIGNED_LEN <= destack->front) return NULL; - else - { - destack->back -= ALIGNED_LEN; - uint8_t *const restrict ptr = ( uint8_t* )destack->back; - return ptr; - } - } -} - -void BiStackResetFront(BiStack *const destack) -{ - if (destack->mem == 0) return; - else destack->front = destack->mem; -} - -void BiStackResetBack(BiStack *const destack) -{ - if (destack->mem == 0) return; - else destack->back = destack->mem + destack->size; -} - -void BiStackResetAll(BiStack *const destack) -{ - BiStackResetBack(destack); - BiStackResetFront(destack); -} - -inline intptr_t BiStackMargins(const BiStack destack) -{ - return destack.back - destack.front; -} - -#endif // RMEM_IMPLEMENTATION - -/******* - * Changelog - * v1.0: First Creation. - * v1.1: bug patches for the mempool and addition of object pool. - * v1.2: addition of bidirectional arena. - * v1.3: - * optimizations of allocators. - * renamed 'Stack' to 'Arena'. - * replaced certain define constants with an anonymous enum. - * refactored MemPool to no longer require active or deferred defragging. - ********/ diff --git a/include/utils.h b/include/utils.h deleted file mode 100644 index c9b3318..0000000 --- a/include/utils.h +++ /dev/null @@ -1,81 +0,0 @@ -/********************************************************************************************** -* -* raylib.utils - Some common utility functions -* -* -* LICENSE: zlib/libpng -* -* Copyright (c) 2014-2021 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 UTILS_H -#define UTILS_H - -#if defined(PLATFORM_ANDROID) - #include // Required for: FILE - #include // Required for: AAssetManager -#endif - -#if defined(SUPPORT_TRACELOG) - #define TRACELOG(level, ...) TraceLog(level, __VA_ARGS__) - - #if defined(SUPPORT_TRACELOG_DEBUG) - #define TRACELOGD(...) TraceLog(LOG_DEBUG, __VA_ARGS__) - #else - #define TRACELOGD(...) (void)0 - #endif -#else - #define TRACELOG(level, ...) (void)0 - #define TRACELOGD(...) (void)0 -#endif - -//---------------------------------------------------------------------------------- -// Some basic Defines -//---------------------------------------------------------------------------------- -#if defined(PLATFORM_ANDROID) - #define fopen(name, mode) android_fopen(name, mode) -#endif - -//---------------------------------------------------------------------------------- -// Types and Structures Definition -//---------------------------------------------------------------------------------- -//... - -//---------------------------------------------------------------------------------- -// Global Variables Definition -//---------------------------------------------------------------------------------- -// Nop... - -//---------------------------------------------------------------------------------- -// Module Functions Declaration -//---------------------------------------------------------------------------------- -#ifdef __cplusplus -extern "C" { // Prevents name mangling of functions -#endif - -#if defined(PLATFORM_ANDROID) -void InitAssetManager(AAssetManager *manager, const char *dataPath); // Initialize asset manager from android app -FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen() -> Read-only! -#endif - -#ifdef __cplusplus -} -#endif - -#endif // UTILS_H