diff --git a/.gitignore b/.gitignore index 566e67e..7680460 100644 --- a/.gitignore +++ b/.gitignore @@ -16,25 +16,15 @@ gencpp.hpp gencpp.cpp -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -[Ww][Ii][Nn]32/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ -[Ll]ogs/ -vc140.pdb +**/*.lib +**/*.pdb +**/*.exe +**/*.dll +release/** # Unreal **/Unreal/*.h **/Unreal/*.cpp ! **/Unreal/validate.unreal.cpp +project/auxillary/vis_ast/dependencies/temp diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index f2775d2..6e9762e 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -12,7 +12,8 @@ "GEN_TIME", "GEN_IMPLEMENTATION", // "GEN_DONT_USE_NAMESPACE" - "GEN_INTELLISENSE_DIRECTIVES" + "GEN_INTELLISENSE_DIRECTIVES", + "INTELLISENSE_DIRECTIVES" ], "windowsSdkVersion": "10.0.19041.0", "compilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.29.30133/bin/HostX64/x64/cl.exe", @@ -31,7 +32,8 @@ "GEN_TIME", "GEN_IMPLEMENTATION", // "GEN_DONT_USE_NAMESPACE" - "GEN_INTELLISENSE_DIRECTIVES" + "GEN_INTELLISENSE_DIRECTIVES", + "INTELLISENSE_DIRECTIVES" ], "windowsSdkVersion": "10.0.19041.0", "compilerPath": "C:/Users/Ed/scoop/apps/llvm/current/bin/clang++.exe", diff --git a/.vscode/launch.json b/.vscode/launch.json index ae30b68..0790fd6 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -40,6 +40,15 @@ "args": [], "cwd": "${workspaceFolder}/singleheader/", "visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis" + }, + { + "type": "cppvsdbg", + "request": "launch", + "name": "Debug raylib refactor vsdbg", + "program": "${workspaceFolder}/project/auxillary/vis_ast/dependencies/raylib/build/raylib_refactor.exe", + "args": [], + "cwd": "${workspaceFolder}/project/auxillary/vis_ast/dependencies/temp/raylib-master/src/", + "visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis" } ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 4d693b5..e298a3c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,7 +28,9 @@ "functional": "cpp", "vector": "cpp", "list": "cpp", - "xhash": "cpp" + "xhash": "cpp", + "glfw3.h": "c", + "stdbool.h": "c" }, "C_Cpp.intelliSenseEngineFallback": "disabled", "mesonbuild.configureOnOpen": true, diff --git a/project/auxillary/vis_ast/build.ps1 b/project/auxillary/vis_ast/build.ps1 new file mode 100644 index 0000000..9cb2028 --- /dev/null +++ b/project/auxillary/vis_ast/build.ps1 @@ -0,0 +1,106 @@ +Clear-Host + +$path_root = git rev-parse --show-toplevel +$path_scripts = Join-Path $path_root 'scripts' + +$target_arch = Join-Path $path_scripts 'helpers/target_arch.psm1' +$devshell = Join-Path $path_scripts 'helpers/devshell.ps1' +$format_cpp = Join-Path $path_scripts 'helpers/format_cpp.psm1' +$incremental_checks = Join-Path $path_scripts 'helpers/incremental_checks.ps1' +$vendor_toolchain = Join-Path $path_scripts 'helpers/vendor_toolchain.ps1' + +$path_project = Join-Path $path_root 'project' +$path_aux = Join-Path $path_project 'auxillary' +$path_vis_root = Join-Path $path_aux 'vis_ast' +$path_binaries = Join-Path $path_vis_root 'binaries' +$path_build = Join-Path $path_vis_root 'build' +$path_code = Join-Path $path_vis_root 'code' +$path_win32 = Join-Path $path_code 'win32' + +Import-Module $target_arch +Import-Module $format_cpp + +#region Arguments +$vendor = $null +$optimize = $null +$debug = $null +$analysis = $false +$dev = $false +$verbose = $null +$platform = $null +$module_specified = $false + +[array] $vendors = @( "clang", "msvc" ) + +# This is a really lazy way of parsing the args, could use actual params down the line... + +if ( $args ) { $args | ForEach-Object { +switch ($_){ + { $_ -in $vendors } { $vendor = $_; break } + "optimize" { $optimize = $true } + "debug" { $debug = $true } + "analysis" { $analysis = $true } + "dev" { $dev = $true } + "verbose" { $verbose = $true } + "platform" { $platform = $true; $module_specified = $true } +} +}} +#endregion Argument + +if ( -not $module_specified ) +{ + $platform = $true +} + +# Load up toolchain configuraion +. $vendor_toolchain +. $incremental_checks + +write-host "Building Vis AST with $vendor" + +if ( (Test-Path $path_build) -eq $false ) { + New-Item $path_build -ItemType Directory +} + +if ( (Test-Path $path_binaries) -eq $false ) { + New-Item $path_binaries -ItemType Directory +} + +$includes = @( + $paht_code +) + +# Microsoft +$lib_gdi32 = 'Gdi32.lib' +$lib_xinput = 'Xinput.lib' +$lib_user32 = 'User32.lib' +$lib_winmm = 'Winmm.lib' + +$stack_size = 1024 * 1024 * 4 + +$compiler_args = @( + ($flag_define + 'UNICODE'), + ($flag_define + '_UNICODE') + ( $flag_define + 'INTELLISENSE_DIRECTIVES=0'), + # ($flag_set_stack_size + $stack_size) + $flag_wall + $flag_warnings_as_errors + $flag_optimize_intrinsics +) + +if ( $dev ) { + $compiler_args += ( $flag_define + 'Build_Development=1' ) +} +else { + $compiler_args += ( $flag_define + 'Build_Development=0' ) +} + +$linker_args = @( + $flag_link_win_subsystem_windows, + $flag_link_optiiize_references +) + +$unit = join-path $path_code 'vis_ast_windows.cpp' +$executable = join-path $path_binaries 'vis_ast.exe' + +$build_result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable diff --git a/project/auxillary/vis_ast/clean.ps1 b/project/auxillary/vis_ast/clean.ps1 new file mode 100644 index 0000000..e69de29 diff --git a/project/auxillary/vis_ast/code/platform/macros.hpp b/project/auxillary/vis_ast/code/platform/macros.hpp new file mode 100644 index 0000000..656bb0d --- /dev/null +++ b/project/auxillary/vis_ast/code/platform/macros.hpp @@ -0,0 +1,24 @@ +#if INTELLISENSE_DIRECTIVES +#include "vendor/compiler.hpp" +#endif + +#define global static // Global variables +#define internal static // Internal linkage +#define local_persist static // Local Persisting variables + +#define api_c extern "C" + +#define ccast( type, value ) ( const_cast< type >( (value) ) ) +#define pcast( type, value ) ( * reinterpret_cast< type* >( & ( value ) ) ) +#define rcast( type, value ) reinterpret_cast< type >( value ) +#define scast( type, value ) static_cast< type >( value ) + +#define do_once() for ( local_persist b32 once = true; once; once = false ) +#define stmt( ... ) do { __VA_ARGS__; } while ( 0 ) + +#define array_count( array ) ( sizeof( array ) / sizeof( ( array )[0] ) ) + +#define kilobytes( x ) ( ( x ) * ( s64 )( 1024 ) ) +#define megabytes( x ) ( kilobytes( x ) * ( s64 )( 1024 ) ) +#define gigabytes( x ) ( megabytes( x ) * ( s64 )( 1024 ) ) +#define terabytes( x ) ( gigabytes( x ) * ( s64 )( 1024 ) ) diff --git a/project/auxillary/vis_ast/code/platform/vendor/arch.hpp b/project/auxillary/vis_ast/code/platform/vendor/arch.hpp new file mode 100644 index 0000000..076b6f7 --- /dev/null +++ b/project/auxillary/vis_ast/code/platform/vendor/arch.hpp @@ -0,0 +1,9 @@ +// Platform architecture + +#if defined( _WIN64 ) || defined( __x86_64__ ) || defined( _M_X64 ) || defined( __64BIT__ ) || defined( __powerpc64__ ) || defined( __ppc64__ ) || defined( __aarch64__ ) +# ifndef ARCH_64_BIT +# define ARCH_64_BIT 1 +# endif +#else +# error A 32-bit architecture is not supported +#endif diff --git a/project/auxillary/vis_ast/code/platform/vendor/compiler.hpp b/project/auxillary/vis_ast/code/platform/vendor/compiler.hpp new file mode 100644 index 0000000..45244c6 --- /dev/null +++ b/project/auxillary/vis_ast/code/platform/vendor/compiler.hpp @@ -0,0 +1,21 @@ +// Platform compiler + +#if defined( _MSC_VER ) +# define Compiler_MSVC 1 +#elif defined( __clang__ ) +# define Compiler_Clang 1 +#else +# error "Unknown compiler" +#endif + +#if defined( __has_attribute ) +# define HAS_ATTRIBUTE( attribute ) __has_attribute( attribute ) +#else +# define HAS_ATTRIBUTE( attribute ) ( 0 ) +#endif + +#ifdef Compiler_Clang +# define compiler_decorated_func_name __PRETTY_NAME__ +#elif defined(Compiler_MSVC) +# define compiler_decorated_func_name __FUNCDNAME__ +#endif diff --git a/project/auxillary/vis_ast/code/platform/vendor/compiler_ignores.hpp b/project/auxillary/vis_ast/code/platform/vendor/compiler_ignores.hpp new file mode 100644 index 0000000..c73f782 --- /dev/null +++ b/project/auxillary/vis_ast/code/platform/vendor/compiler_ignores.hpp @@ -0,0 +1,34 @@ +#pragma once +#if INTELLISENSE_DIRECTIVES +#include "compiler.hpp" +#endif + +#ifdef Compiler_MSVC +#pragma warning( disable: 4201 ) // Support for non-standard nameless struct or union extesnion +#pragma warning( disable: 4100 ) // Support for unreferenced formal parameters +#pragma warning( disable: 4800 ) // Support implicit conversion to bools +#pragma warning( disable: 4365 ) // Support for signed/unsigned mismatch auto-conversion +#pragma warning( disable: 4189 ) // Support for unused variables +#pragma warning( disable: 4514 ) // Support for unused inline functions +#pragma warning( disable: 4505 ) // Support for unused static functions +#pragma warning( disable: 5045 ) // Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified +#pragma warning( disable: 5264 ) // Support for 'const' variables unused +#pragma warning( disable: 4820 ) // Support auto-adding padding to structs +#pragma warning( disable: 4711 ) // Support automatic inline expansion +#pragma warning( disable: 4710 ) // Support automatic inline expansion +#pragma warning( disable: 4805 ) // Support comparisons of s32 to bool. +#pragma warning( disable: 5246 ) // Support for initialization of subobject without braces. +#endif + +#ifdef Compiler_Clang +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-const-variable" +#pragma clang diagnostic ignored "-Wswitch" +#pragma clang diagnostic ignored "-Wunused-variable" +#pragma clang diagnostic ignored "-Wunused-local-typedef" +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wvarargs" +#pragma clang diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wunused-but-set-variable" +#pragma clang diagnostic ignored "-Wmissing-braces" +#endif diff --git a/project/auxillary/vis_ast/code/platform/vendor/os.hpp b/project/auxillary/vis_ast/code/platform/vendor/os.hpp new file mode 100644 index 0000000..e754a18 --- /dev/null +++ b/project/auxillary/vis_ast/code/platform/vendor/os.hpp @@ -0,0 +1,21 @@ +// Platform OS detection + +#if defined( _WIN32 ) || defined( _WIN64 ) +# ifndef System_Windows +# define System_Windows 1 +# endif +#elif defined( __APPLE__ ) && defined( __MACH__ ) +# ifndef System_MacOS +# define System_MacOS 1 +# endif +#elif defined( __unix__ ) +# if defined( __linux__ ) +# ifndef System_Linux +# define System_linux 1 +# endif +# else +# error This UNIX operating system is not supported +# endif +#else +# error This operating system is not supported +#endif diff --git a/project/auxillary/vis_ast/code/platform/win32/launch.cpp b/project/auxillary/vis_ast/code/platform/win32/launch.cpp new file mode 100644 index 0000000..deb5982 --- /dev/null +++ b/project/auxillary/vis_ast/code/platform/win32/launch.cpp @@ -0,0 +1,8 @@ +#if INTELLISENSE_DIRECTIVES +#include "win32.hpp" +#endif + +int __stdcall WinMain( HINSTANCE instance, HINSTANCE prev_instance, char* commandline, int num_cmd_show) +{ + return 0; +} diff --git a/project/auxillary/vis_ast/code/platform/win32/types.hpp b/project/auxillary/vis_ast/code/platform/win32/types.hpp new file mode 100644 index 0000000..f890f66 --- /dev/null +++ b/project/auxillary/vis_ast/code/platform/win32/types.hpp @@ -0,0 +1 @@ +using HINSTANCE = void*; \ No newline at end of file diff --git a/project/auxillary/vis_ast/code/vis_ast_windows.cpp b/project/auxillary/vis_ast/code/vis_ast_windows.cpp new file mode 100644 index 0000000..5ff9902 --- /dev/null +++ b/project/auxillary/vis_ast/code/vis_ast_windows.cpp @@ -0,0 +1,10 @@ +#include "platform/vendor/arch.hpp" +#include "platform/vendor/compiler.hpp" +#include "platform/vendor/compiler_ignores.hpp" +#include "platform/vendor/os.hpp" + +#include "platform/macros.hpp" + +#include "platform/win32/types.hpp" + +#include "platform/win32/launch.cpp" diff --git a/project/auxillary/vis_ast/dependencies/raylib/include/config.h b/project/auxillary/vis_ast/dependencies/raylib/include/config.h new file mode 100644 index 0000000..2663db4 --- /dev/null +++ b/project/auxillary/vis_ast/dependencies/raylib/include/config.h @@ -0,0 +1,226 @@ +/********************************************************************************************** + * + * raylib configuration flags + * + * This file defines all the configuration flags for the different raylib modules + * + * LICENSE: zlib/libpng + * + * Copyright (c) 2018-2023 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. + * + **********************************************************************************************/ + +#ifndef CONFIG_H +#define RL_CONFIG_H + +//------------------------------------------------------------------------------------ +// Module selection - Some modules could be avoided +// Mandatory modules: rcore, rlgl, utils +//------------------------------------------------------------------------------------ +#define RL_SUPPORT_MODULE_RSHAPES 1 +#define RL_SUPPORT_MODULE_RTEXTURES 1 +#define RL_SUPPORT_MODULE_RTEXT 1 // WARNING: It requires SUPPORT_MODULE_RTEXTURES to load sprite font textures +#define RL_SUPPORT_MODULE_RMODELS 1 +#define RL_SUPPORT_MODULE_RAUDIO 1 + +//------------------------------------------------------------------------------------ +// Module: rcore - Configuration Flags +//------------------------------------------------------------------------------------ +// Camera module is included (rcamera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital +#define RL_SUPPORT_CAMERA_SYSTEM 1 +// Gestures module is included (rgestures.h) to support gestures detection: tap, hold, swipe, drag +#define RL_SUPPORT_GESTURES_SYSTEM 1 +// Mouse gestures are directly mapped like touches and processed by gestures system +#define RL_SUPPORT_MOUSE_GESTURES 1 +// Reconfigure standard input to receive key inputs, works with SSH connection. +#define RL_SUPPORT_SSH_KEYBOARD_RPI 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 RL_SUPPORT_WINMM_HIGHRES_TIMER 1 +// Use busy wait loop for timing sync, if not defined, a high-resolution timer is set up 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 RL_SUPPORT_PARTIALBUSY_WAIT_LOOP 1 +// Allow automatic screen capture of current screen pressing F12, defined in KeyCallback() +#define RL_SUPPORT_SCREEN_CAPTURE 1 +// Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback() +#define RL_SUPPORT_GIF_RECORDING 1 +// Support CompressData() and DecompressData() functions +#define RL_SUPPORT_COMPRESSION_API 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 timing + PollInputEvents() +// Enabling this flag allows manual control of the frame processes, use at your own risk +// #define SUPPORT_CUSTOM_FRAME_CONTROL 1 + +// rcore: Configuration values +//------------------------------------------------------------------------------------ +#define RL_MAX_FILEPATH_CAPACITY 8192 // Maximum file paths capacity +#define RL_MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value) + +#define RL_MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported +#define RL_MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported +#define RL_MAX_GAMEPADS 4 // Maximum number of gamepads supported +#define RL_MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad) +#define RL_MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad) +#define RL_MAX_TOUCH_POINTS 8 // Maximum number of touch points supported +#define RL_MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue +#define RL_MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue + +#define RL_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 + + + + +// 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 + + + +//------------------------------------------------------------------------------------ +// Module: rshapes - Configuration Flags +//------------------------------------------------------------------------------------ +// Use QUADS instead of TRIANGLES for drawing when possible +// Some lines-based shapes could still use lines +#define RL_SUPPORT_QUADS_DRAW_MODE 1 + + +//------------------------------------------------------------------------------------ +// Module: rtextures - Configuration Flags +//------------------------------------------------------------------------------------ +// Selecte desired fileformats to be supported for image data loading +#define RL_SUPPORT_FILEFORMAT_PNG 1 +// #define SUPPORT_FILEFORMAT_BMP 1 +// #define SUPPORT_FILEFORMAT_TGA 1 +// #define SUPPORT_FILEFORMAT_JPG 1 +#define RL_SUPPORT_FILEFORMAT_GIF 1 +#define RL_SUPPORT_FILEFORMAT_QOI 1 +// #define SUPPORT_FILEFORMAT_PSD 1 +#define RL_SUPPORT_FILEFORMAT_DDS 1 +// #define SUPPORT_FILEFORMAT_HDR 1 +// #define SUPPORT_FILEFORMAT_PIC 1 +// #define SUPPORT_FILEFORMAT_KTX 1 +// #define SUPPORT_FILEFORMAT_ASTC 1 +// #define SUPPORT_FILEFORMAT_PKM 1 +// #define SUPPORT_FILEFORMAT_PVR 1 +// #define SUPPORT_FILEFORMAT_SVG 1 + +// Support image export functionality (.png, .bmp, .tga, .jpg, .qoi) +#define RL_SUPPORT_IMAGE_EXPORT 1 +// Support procedural image generation functionality (gradient, spot, perlin-noise, cellular) +#define RL_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 RL_SUPPORT_IMAGE_MANIPULATION 1 + + +//------------------------------------------------------------------------------------ +// Module: rtext - 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 RL_SUPPORT_DEFAULT_FONT 1 +// Selected desired font fileformats to be supported for loading +#define RL_SUPPORT_FILEFORMAT_FNT 1 +#define RL_SUPPORT_FILEFORMAT_TTF 1 + +// Support text management functions +// If not defined, still some functions are supported: TextLength(), TextFormat() +#define RL_SUPPORT_TEXT_MANIPULATION 1 + +// On font atlas image generation [GenImageFontAtlas()], add a 3x3 pixels white rectangle +// at the bottom-right corner of the atlas. It can be useful to for shapes drawing, to allow +// drawing text and shapes with a single draw call [SetShapesTexture()]. +#define RL_SUPPORT_FONT_ATLAS_WHITE_REC 1 + +// rtext: Configuration values +//------------------------------------------------------------------------------------ +#define RL_MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions: +// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit() +#define RL_MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit() + + +//------------------------------------------------------------------------------------ +// Module: rmodels - Configuration Flags +//------------------------------------------------------------------------------------ +// Selected desired model fileformats to be supported for loading +#define RL_SUPPORT_FILEFORMAT_OBJ 1 +#define RL_SUPPORT_FILEFORMAT_MTL 1 +#define RL_SUPPORT_FILEFORMAT_IQM 1 +#define RL_SUPPORT_FILEFORMAT_GLTF 1 +#define RL_SUPPORT_FILEFORMAT_VOX 1 +#define RL_SUPPORT_FILEFORMAT_M3D 1 +// Support procedural mesh generation functions, uses external par_shapes.h library +// NOTE: Some generated meshes DO NOT include generated texture coordinates +#define RL_SUPPORT_MESH_GENERATION 1 + +// rmodels: Configuration values +//------------------------------------------------------------------------------------ +#define RL_MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported +#define RL_MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh + +//------------------------------------------------------------------------------------ +// Module: raudio - Configuration Flags +//------------------------------------------------------------------------------------ +// Desired audio fileformats to be supported for loading +#define RL_SUPPORT_FILEFORMAT_WAV 1 +#define RL_SUPPORT_FILEFORMAT_OGG 1 +#define RL_SUPPORT_FILEFORMAT_MP3 1 +#define RL_SUPPORT_FILEFORMAT_QOA 1 +// #define SUPPORT_FILEFORMAT_FLAC 1 +#define RL_SUPPORT_FILEFORMAT_XM 1 +#define RL_SUPPORT_FILEFORMAT_MOD 1 + +// raudio: Configuration values +//------------------------------------------------------------------------------------ +#define RL_AUDIO_DEVICE_FORMAT ma_format_f32 // Device output format (miniaudio: float-32bit) +#define RL_AUDIO_DEVICE_CHANNELS 2 // Device output channels: stereo +#define RL_AUDIO_DEVICE_SAMPLE_RATE 0 // Device sample rate (device default) + +#define RL_MAX_AUDIO_BUFFER_POOL_CHANNELS 16 // Maximum number of audio pool channels + +//------------------------------------------------------------------------------------ +// Module: utils - Configuration Flags +//------------------------------------------------------------------------------------ +// Standard file io library (stdio.h) included +#define RL_SUPPORT_STANDARD_FILEIO 1 +// Show TRACELOG() output messages +// NOTE: By default LOG_DEBUG traces not shown +#define RL_SUPPORT_TRACELOG 1 +// #define SUPPORT_TRACELOG_DEBUG 1 + +// utils: Configuration values +//------------------------------------------------------------------------------------ +#define RL_MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message + +#endif +// CONFIG_H diff --git a/project/auxillary/vis_ast/dependencies/raylib/include/raylib.h b/project/auxillary/vis_ast/dependencies/raylib/include/raylib.h new file mode 100644 index 0000000..2bdcac2 --- /dev/null +++ b/project/auxillary/vis_ast/dependencies/raylib/include/raylib.h @@ -0,0 +1,1995 @@ +/********************************************************************************************** + * + * raylib v4.6-dev - 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 algorithm + * [rcore] sdefl (Micha Mettke) for DEFLATE compression algorithm + * [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) + * [rmodels] Model3D (bzt) for models loading (M3D, https://bztsrc.gitlab.io/model3d) + * [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-2023 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 + +#include +// Required for: va_list - Only used by TraceLogCallback + + +// 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 ) +#if defined( __TINYC__ ) +#define RL___declspec( x ) __attribute__( ( x ) ) +#endif +#elif defined( USE_LIBTYPE_SHARED ) +#endif +#endif + +#ifndef RLAPI +#endif + +//---------------------------------------------------------------------------------- +// Some basic Defines +//---------------------------------------------------------------------------------- +#ifndef PI +#define RL_PI 3.14159265358979323846f +#endif +#ifndef DEG2RAD +#define RL_DEG2RAD ( PI / 180.0f ) +#endif +#ifndef RAD2DEG +#define RL_RAD2DEG ( 180.0f / PI ) +#endif + +// Allow custom memory allocators +// NOTE: Require recompiling raylib sources +#ifndef RL_MALLOC +#endif +#ifndef RL_CALLOC +#endif +#ifndef RL_REALLOC +#endif +#ifndef RL_FREE +#endif + +// NOTE: MSVC C++ compiler does not support compound literals (C99 feature) +// Plain structures in C++ (without constructors) can be initialized with { } +// This is called aggregate initialization (C++11 feature) +#if defined( __cplusplus ) +#define RL_CLITERAL( type ) type +#else +#define RL_CLITERAL( type ) ( type ) +#endif + +// Some compilers (mostly macos clang) default to C++98, +// where aggregate initialization can't be used +// So, give a more clear error stating how to fix this +#if ! defined( _MSC_VER ) && ( defined( __cplusplus ) && __cplusplus < 201103L ) +#error "C++11 or later is required. Add -std=c++11" +#endif + +// NOTE: 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 + +// Some Basic Colors +// NOTE: Custom raylib color palette for amazing visuals on WHITE background +#define RL_LIGHTGRAY \ + CLITERAL( Color ) \ + { \ + 200, 200, 200, 255 \ + } // Light Gray +#define RL_GRAY \ + CLITERAL( Color ) \ + { \ + 130, 130, 130, 255 \ + } // Gray +#define RL_DARKGRAY \ + CLITERAL( Color ) \ + { \ + 80, 80, 80, 255 \ + } // Dark Gray +#define RL_YELLOW \ + CLITERAL( Color ) \ + { \ + 253, 249, 0, 255 \ + } // Yellow +#define RL_GOLD \ + CLITERAL( Color ) \ + { \ + 255, 203, 0, 255 \ + } // Gold +#define RL_ORANGE \ + CLITERAL( Color ) \ + { \ + 255, 161, 0, 255 \ + } // Orange +#define RL_PINK \ + CLITERAL( Color ) \ + { \ + 255, 109, 194, 255 \ + } // Pink +#define RL_RED \ + CLITERAL( Color ) \ + { \ + 230, 41, 55, 255 \ + } // Red +#define RL_MAROON \ + CLITERAL( Color ) \ + { \ + 190, 33, 55, 255 \ + } // Maroon +#define RL_GREEN \ + CLITERAL( Color ) \ + { \ + 0, 228, 48, 255 \ + } // Green +#define RL_LIME \ + CLITERAL( Color ) \ + { \ + 0, 158, 47, 255 \ + } // Lime +#define RL_DARKGREEN \ + CLITERAL( Color ) \ + { \ + 0, 117, 44, 255 \ + } // Dark Green +#define RL_SKYBLUE \ + CLITERAL( Color ) \ + { \ + 102, 191, 255, 255 \ + } // Sky Blue +#define RL_BLUE \ + CLITERAL( Color ) \ + { \ + 0, 121, 241, 255 \ + } // Blue +#define RL_DARKBLUE \ + CLITERAL( Color ) \ + { \ + 0, 82, 172, 255 \ + } // Dark Blue +#define RL_PURPLE \ + CLITERAL( Color ) \ + { \ + 200, 122, 255, 255 \ + } // Purple +#define RL_VIOLET \ + CLITERAL( Color ) \ + { \ + 135, 60, 190, 255 \ + } // Violet +#define RL_DARKPURPLE \ + CLITERAL( Color ) \ + { \ + 112, 31, 126, 255 \ + } // Dark Purple +#define RL_BEIGE \ + CLITERAL( Color ) \ + { \ + 211, 176, 131, 255 \ + } // Beige +#define RL_BROWN \ + CLITERAL( Color ) \ + { \ + 127, 106, 79, 255 \ + } // Brown +#define RL_DARKBROWN \ + CLITERAL( Color ) \ + { \ + 76, 63, 47, 255 \ + } // Dark Brown + +#define RL_WHITE \ + CLITERAL( Color ) \ + { \ + 255, 255, 255, 255 \ + } // White +#define RL_BLACK \ + CLITERAL( Color ) \ + { \ + 0, 0, 0, 255 \ + } // Black +#define RL_BLANK \ + CLITERAL( Color ) \ + { \ + 0, 0, 0, 0 \ + } // Blank (Transparent) +#define RL_MAGENTA \ + CLITERAL( Color ) \ + { \ + 255, 0, 255, 255 \ + } // Magenta +#define RL_RAYWHITE \ + CLITERAL( Color ) \ + { \ + 245, 245, 245, 255 \ + } // My own White (raylib logo) + +//---------------------------------------------------------------------------------- +// Structures Definition +//---------------------------------------------------------------------------------- +// Boolean type +#if ( defined( __STDC__ ) && __STDC_VERSION__ >= 199901L ) || ( defined( _MSC_VER ) && _MSC_VER >= 1800 ) +#include +#elif ! defined( __cplusplus ) && ! defined( bool ) +typedef enum bool +{ + False = 0, + True = ! false +} bool; +#endif + +// Vector2, 2 components +typedef struct Vector2 +{ + f32 x; // Vector x component + f32 y; // Vector y component + +} Vector2; + +// Vector3, 3 components +typedef struct Vector3 +{ + f32 x; // Vector x component + f32 y; // Vector y component + f32 z; // Vector z component + +} Vector3; + +// Vector4, 4 components +typedef struct Vector4 +{ + f32 x; // Vector x component + f32 y; // Vector y component + f32 z; // Vector z component + f32 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 +{ + f32 m0, m4, m8, m12; // Matrix first row (4 components) + f32 m1, m5, m9, m13; // Matrix second row (4 components) + f32 m2, m6, m10, m14; // Matrix third row (4 components) + f32 m3, m7, m11, m15; // Matrix fourth row (4 components) + +} Matrix; + +// Color, 4 components, R8G8B8A8 (32bit) +typedef struct Color +{ + u8 r; // Color red value + u8 g; // Color green value + u8 b; // Color blue value + u8 a; // Color alpha value + +} Color; + +// Rectangle, 4 components +typedef struct Rectangle +{ + f32 x; // Rectangle top-left corner position x + f32 y; // Rectangle top-left corner position y + f32 width; // Rectangle width + f32 height; // Rectangle height + +} Rectangle; + +// Image, pixel data stored in CPU memory (RAM) +typedef struct Image +{ + void* data; // Image raw data + s32 width; // Image base width + s32 height; // Image base height + s32 mipmaps; // Mipmap levels, 1 by default + s32 format; // Data format (PixelFormat type) + +} Image; + +// Texture, tex data stored in GPU memory (VRAM) +typedef struct Texture +{ + u32 id; // OpenGL texture id + s32 width; // Texture base width + s32 height; // Texture base height + s32 mipmaps; // Mipmap levels, 1 by default + s32 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 +{ + u32 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 + s32 left; // Left border offset + s32 top; // Top border offset + s32 right; // Right border offset + s32 bottom; // Bottom border offset + s32 layout; // Layout of the n-patch: 3x3, 1x3 or 3x1 + +} NPatchInfo; + +// GlyphInfo, font characters glyphs info +typedef struct GlyphInfo +{ + s32 value; // Character value (Unicode) + s32 offsetX; // Character offset X when drawing + s32 offsetY; // Character offset Y when drawing + s32 advanceX; // Character advance position X + Image image; // Character image data + +} GlyphInfo; + +// Font, font texture and GlyphInfo array data +typedef struct Font +{ + s32 baseSize; // Base size (default chars height) + s32 glyphCount; // Number of glyph characters + s32 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) + f32 fovy; // Camera field-of-view aperture in Y (degrees) in perspective, used as near plane width in orthographic + s32 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) + f32 rotation; // Camera rotation in degrees + f32 zoom; // Camera zoom (scaling), should be 1.0f by default + +} Camera2D; + +// Mesh, vertex data and vao/vbo +typedef struct Mesh +{ + s32 vertexCount; // Number of vertices stored in arrays + s32 triangleCount; // Number of triangles stored (indexed or not) + + // Vertex attributes data + f32* vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0) + f32* texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) + f32* texcoords2; // Vertex texture second coordinates (UV - 2 components per vertex) (shader-location = 5) + f32* normals; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2) + f32* tangents; // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4) + u8* colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3) + u8* indices; // Vertex indices (in case vertex data comes indexed) + + // Animation vertex data + f32* animVertices; // Animated vertex positions (after bones transformations) + f32* animNormals; // Animated normals (after bones transformations) + u8* boneIds; // Vertex bone ids, max 255 bone ids, up to 4 bones influence by vertex (skinning) + f32* boneWeights; // Vertex bone weight, up to 4 bones influence by vertex (skinning) + + // OpenGL identifiers + u32 vaoId; // OpenGL Vertex Array Object id + unsigned int* vboId; // OpenGL Vertex Buffer Objects id (default vertex data) + +} Mesh; + +// Shader +typedef struct Shader +{ + u32 id; // Shader program id + s32* locs; // Shader locations array (RL_MAX_SHADER_LOCATIONS) + +} Shader; + +// MaterialMap +typedef struct MaterialMap +{ + Texture2D texture; // Material map texture + Color color; // Material map color + f32 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) + f32 params; // Material generic parameters (if required) + +} Material; + +// Transform, vertex 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 + s32 parent; // Bone parent + +} BoneInfo; + +// Model, meshes, materials and animation data +typedef struct Model +{ + Matrix transform; // Local transform matrix + + s32 meshCount; // Number of meshes + s32 materialCount; // Number of materials + Mesh* meshes; // Meshes array + Material* materials; // Materials array + s32* meshMaterial; // Mesh material number + + // Animation data + s32 boneCount; // Number of bones + BoneInfo* bones; // Bones information (skeleton) + Transform* bindPose; // Bones base transformation (pose) + +} Model; + +// ModelAnimation +typedef struct ModelAnimation +{ + s32 boneCount; // Number of bones + s32 frameCount; // Number of animation frames + BoneInfo* bones; // Bones information (skeleton) + Transform** framePoses; // Poses array by frame + char name[ 32 ]; // Animation name + +} 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? + f32 distance; // Distance to the nearest hit + Vector3 point; // Point of the nearest hit + Vector3 normal; // Surface normal of hit + +} RayCollision; + +// BoundingBox +typedef struct BoundingBox +{ + Vector3 min; // Minimum vertex box-corner + Vector3 max; // Maximum vertex box-corner + +} BoundingBox; + +// Wave, audio wave data +typedef struct Wave +{ + u32 frameCount; // Total number of frames (considering channels) + u32 sampleRate; // Frequency (samples per second) + u32 sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + u32 channels; // Number of channels (1-mono, 2-stereo, ...) + void* data; // Buffer data pointer + +} Wave; + +// Opaque structs declaration +// NOTE: Actual structs are defined internally in raudio module +typedef struct rAudioBuffer rAudioBuffer; +typedef struct rAudioProcessor rAudioProcessor; + +// AudioStream, custom audio stream +typedef struct AudioStream +{ + rAudioBuffer* buffer; // Pointer to internal data used by the audio system + rAudioProcessor* processor; // Pointer to internal data processor, useful for audio effects + + u32 sampleRate; // Frequency (samples per second) + u32 sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported) + u32 channels; // Number of channels (1-mono, 2-stereo, ...) + +} AudioStream; + +// Sound +typedef struct Sound +{ + AudioStream stream; // Audio stream + u32 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 + u32 frameCount; // Total number of frames (considering channels) + bool looping; // Music looping enable + + s32 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 +{ + s32 hResolution; // Horizontal resolution in pixels + s32 vResolution; // Vertical resolution in pixels + f32 hScreenSize; // Horizontal size in meters + f32 vScreenSize; // Vertical size in meters + f32 vScreenCenter; // Screen center in meters + f32 eyeToScreenDistance; // Distance between eye and display in meters + f32 lensSeparationDistance; // Lens separation distance in meters + f32 interpupillaryDistance; // IPD (distance between pupils) in meters + f32 lensDistortionValues; // Lens distortion constant parameters + f32 chromaAbCorrection; // 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) + f32 leftLensCenter; // VR left lens center + f32 rightLensCenter; // VR right lens center + f32 leftScreenCenter; // VR left screen center + f32 rightScreenCenter; // VR right screen center + f32 scale; // VR distortion scale + f32 scaleIn; // VR distortion scale in + +} VrStereoConfig; + +// File path list +typedef struct FilePathList +{ + u32 capacity; // Filepaths max entries + u32 count; // Filepaths entries count + char** paths; // Filepaths entries + +} FilePathList; + +//---------------------------------------------------------------------------------- +// Enumerators Definition +//---------------------------------------------------------------------------------- +// System/Window config flags +// NOTE: Every bit registers one state (use it with bit masks) +// By default all flags are set to 0 +typedef enum +{ + Flag_Vsync_Hint = 0x00000040, // Set to try enabling V-Sync on GPU + Flag_Fullscreen_Mode = 0x00000002, // Set to run program in fullscreen + Flag_Window_Resizable = 0x00000004, // Set to allow resizable window + Flag_Window_Undecorated = 0x00000008, // Set to disable window decoration (frame and buttons) + Flag_Window_Hidden = 0x00000080, // Set to hide window + Flag_Window_Minimized = 0x00000200, // Set to minimize window (iconify) + Flag_Window_Maximized = 0x00000400, // Set to maximize window (expanded to monitor) + Flag_Window_Unfocused = 0x00000800, // Set to window non focused + Flag_Window_Topmost = 0x00001000, // Set to window always on top + Flag_Window_Always_Run = 0x00000100, // Set to allow windows running while minimized + Flag_Window_Transparent = 0x00000010, // Set to allow transparent framebuffer + Flag_Window_Highdpi = 0x00002000, // Set to support HighDPI + Flag_Window_Mouse_Passthrough = 0x00004000, // Set to support mouse passthrough, only supported when FLAG_WINDOW_UNDECORATED + Flag_Borderless_Windowed_Mode = 0x00008000, // Set to run program in borderless windowed mode + Flag_Msaa_4x_Hint = 0x00000020, // Set to try enabling MSAA 4X + Flag_Interlaced_Hint = 0x00010000 // set to try enabling interlaced video format (for v3d) + +} ConfigFlags; + +// Trace log level +// NOTE: Organized by priority level +typedef enum +{ + Log_All = 0, // Display all logs + Log_Trace, // Trace logging, intended for internal use only + Log_Debug, // Debug logging, used for internal debugging, it should be disabled on release builds + Log_Info, // Info logging, used for program execution info + Log_Warning, // Warning logging, used on recoverable failures + Log_Error, // Error logging, used on unrecoverable failures + Log_Fatal, // Fatal logging, used to abort program: exit(EXIT_FAILURE) + Log_None // disable logging + +} TraceLogLevel; + +// Keyboard keys (US keyboard layout) +// NOTE: Use GetKeyPressed() to allow redefining +// required keys for alternative layouts +typedef enum +{ + Key_Null = 0, // Key: NULL, used for no key pressed + // Alphanumeric keys + Key_Apostrophe = 39, // Key: ' + Key_Comma = 44, // Key: , + Key_Minus = 45, // Key: - + Key_Period = 46, // Key: . + Key_Slash = 47, // Key: / + Key_Zero = 48, // Key: 0 + Key_One = 49, // Key: 1 + Key_Two = 50, // Key: 2 + Key_Three = 51, // Key: 3 + Key_Four = 52, // Key: 4 + Key_Five = 53, // Key: 5 + Key_Six = 54, // Key: 6 + Key_Seven = 55, // Key: 7 + Key_Eight = 56, // Key: 8 + Key_Nine = 57, // Key: 9 + Key_Semicolon = 59, // Key: ; + Key_Equal = 61, // Key: = + Key_A = 65, // Key: A | a + Key_B = 66, // Key: B | b + Key_C = 67, // Key: C | c + Key_D = 68, // Key: D | d + Key_E = 69, // Key: E | e + Key_F = 70, // Key: F | f + Key_G = 71, // Key: G | g + Key_H = 72, // Key: H | h + Key_I = 73, // Key: I | i + Key_J = 74, // Key: J | j + Key_K = 75, // Key: K | k + Key_L = 76, // Key: L | l + Key_M = 77, // Key: M | m + Key_N = 78, // Key: N | n + Key_O = 79, // Key: O | o + Key_P = 80, // Key: P | p + Key_Q = 81, // Key: Q | q + Key_R = 82, // Key: R | r + Key_S = 83, // Key: S | s + Key_T = 84, // Key: T | t + Key_U = 85, // Key: U | u + Key_V = 86, // Key: V | v + Key_W = 87, // Key: W | w + Key_X = 88, // Key: X | x + Key_Y = 89, // Key: Y | y + Key_Z = 90, // Key: Z | z + Key_Left_Bracket = 91, // Key: [ + Key_Backslash = 92, // Key: '\' + Key_Right_Bracket = 93, // Key: ] + Key_Grave = 96, // Key: ` + // Function keys + Key_Space = 32, // Key: Space + Key_Escape = 256, // Key: Esc + Key_Enter = 257, // Key: Enter + Key_Tab = 258, // Key: Tab + Key_Backspace = 259, // Key: Backspace + Key_Insert = 260, // Key: Ins + Key_Delete = 261, // Key: Del + Key_Right = 262, // Key: Cursor right + Key_Left = 263, // Key: Cursor left + Key_Down = 264, // Key: Cursor down + Key_Up = 265, // Key: Cursor up + Key_Page_Up = 266, // Key: Page up + Key_Page_Down = 267, // Key: Page down + Key_Home = 268, // Key: Home + Key_End = 269, // Key: End + Key_Caps_Lock = 280, // Key: Caps lock + Key_Scroll_Lock = 281, // Key: Scroll down + Key_Num_Lock = 282, // Key: Num lock + Key_Print_Screen = 283, // Key: Print screen + Key_Pause = 284, // Key: Pause + Key_F1 = 290, // Key: F1 + Key_F2 = 291, // Key: F2 + Key_F3 = 292, // Key: F3 + Key_F4 = 293, // Key: F4 + Key_F5 = 294, // Key: F5 + Key_F6 = 295, // Key: F6 + Key_F7 = 296, // Key: F7 + Key_F8 = 297, // Key: F8 + Key_F9 = 298, // Key: F9 + Key_F10 = 299, // Key: F10 + Key_F11 = 300, // Key: F11 + Key_F12 = 301, // Key: F12 + Key_Left_Shift = 340, // Key: Shift left + Key_Left_Control = 341, // Key: Control left + Key_Left_Alt = 342, // Key: Alt left + Key_Left_Super = 343, // Key: Super left + Key_Right_Shift = 344, // Key: Shift right + Key_Right_Control = 345, // Key: Control right + Key_Right_Alt = 346, // Key: Alt right + Key_Right_Super = 347, // Key: Super right + Key_Kb_Menu = 348, // Key: KB menu + // Keypad keys + Key_Kp_0 = 320, // Key: Keypad 0 + Key_Kp_1 = 321, // Key: Keypad 1 + Key_Kp_2 = 322, // Key: Keypad 2 + Key_Kp_3 = 323, // Key: Keypad 3 + Key_Kp_4 = 324, // Key: Keypad 4 + Key_Kp_5 = 325, // Key: Keypad 5 + Key_Kp_6 = 326, // Key: Keypad 6 + Key_Kp_7 = 327, // Key: Keypad 7 + Key_Kp_8 = 328, // Key: Keypad 8 + Key_Kp_9 = 329, // Key: Keypad 9 + Key_Kp_Decimal = 330, // Key: Keypad . + Key_Kp_Divide = 331, // Key: Keypad / + Key_Kp_Multiply = 332, // Key: Keypad * + Key_Kp_Subtract = 333, // Key: Keypad - + Key_Kp_Add = 334, // Key: Keypad + + Key_Kp_Enter = 335, // Key: Keypad Enter + Key_Kp_Equal = 336, // Key: Keypad = + // Android key buttons + Key_Back = 4, // Key: Android back button + Key_Menu = 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 RL_MOUSE_LEFT_BUTTON MOUSE_BUTTON_LEFT +#define RL_MOUSE_RIGHT_BUTTON MOUSE_BUTTON_RIGHT +#define RL_MOUSE_MIDDLE_BUTTON MOUSE_BUTTON_MIDDLE + +// Mouse buttons +typedef enum +{ + Mouse_Button_Left = 0, // Mouse button left + Mouse_Button_Right = 1, // Mouse button right + Mouse_Button_Middle = 2, // Mouse button middle (pressed wheel) + Mouse_Button_Side = 3, // Mouse button side (advanced mouse device) + Mouse_Button_Extra = 4, // Mouse button extra (advanced mouse device) + Mouse_Button_Forward = 5, // Mouse button forward (advanced mouse device) + Mouse_Button_Back = 6, // Mouse button back (advanced mouse device) + +} MouseButton; + +// Mouse cursor +typedef enum +{ + Mouse_Cursor_Default = 0, // Default pointer shape + Mouse_Cursor_Arrow = 1, // Arrow shape + Mouse_Cursor_Ibeam = 2, // Text writing cursor shape + Mouse_Cursor_Crosshair = 3, // Cross shape + Mouse_Cursor_Pointing_Hand = 4, // Pointing hand cursor + Mouse_Cursor_Resize_Ew = 5, // Horizontal resize/move arrow shape + Mouse_Cursor_Resize_Ns = 6, // Vertical resize/move arrow shape + Mouse_Cursor_Resize_Nwse = 7, // Top-left to bottom-right diagonal resize/move arrow shape + Mouse_Cursor_Resize_Nesw = 8, // The top-right to bottom-left diagonal resize/move arrow shape + Mouse_Cursor_Resize_All = 9, // The omnidirectional resize/move cursor shape + Mouse_Cursor_Not_Allowed = 10 // the operation-not-allowed shape + +} MouseCursor; + +// Gamepad buttons +typedef enum +{ + Gamepad_Button_Unknown = 0, // Unknown button, 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 RL_MATERIAL_MAP_DIFFUSE MATERIAL_MAP_ALBEDO +#define RL_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 RL_SHADER_LOC_MAP_DIFFUSE SHADER_LOC_MAP_ALBEDO +#define RL_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_Uncompressed_R16, // 16 bpp (1 channel - half float) + Pixelformat_Uncompressed_R16g16b16, // 16*3 bpp (3 channels - half float) + Pixelformat_Uncompressed_R16g16b16a16, // 16*4 bpp (4 channels - half float) + Pixelformat_Compressed_Dxt1_Rgb, // 4 bpp (no alpha) + Pixelformat_Compressed_Dxt1_Rgba, // 4 bpp (1 bit alpha) + Pixelformat_Compressed_Dxt3_Rgba, // 8 bpp + Pixelformat_Compressed_Dxt5_Rgba, // 8 bpp + Pixelformat_Compressed_Etc1_Rgb, // 4 bpp + Pixelformat_Compressed_Etc2_Rgb, // 4 bpp + Pixelformat_Compressed_Etc2_Eac_Rgba, // 8 bpp + Pixelformat_Compressed_Pvrt_Rgb, // 4 bpp + Pixelformat_Compressed_Pvrt_Rgba, // 4 bpp + Pixelformat_Compressed_Astc_4x4_Rgba, // 8 bpp + Pixelformat_Compressed_Astc_8x8_Rgba // 2 bpp + +} PixelFormat; + +// Texture parameters: filter mode +// NOTE 1: Filtering considers mipmaps if available in the texture +// NOTE 2: Filter is accordingly set for minification and magnification +typedef enum +{ + Texture_Filter_Point = 0, // No filter, just pixel approximation + Texture_Filter_Bilinear, // Linear filtering + Texture_Filter_Trilinear, // Trilinear filtering (linear with mipmaps) + Texture_Filter_Anisotropic_4x, // Anisotropic filtering 4x + Texture_Filter_Anisotropic_8x, // Anisotropic filtering 8x + Texture_Filter_Anisotropic_16x, // Anisotropic filtering 16x + +} TextureFilter; + +// Texture parameters: wrap mode +typedef enum +{ + Texture_Wrap_Repeat = 0, // Repeats texture in tiled mode + Texture_Wrap_Clamp, // Clamps texture to edge pixel in tiled mode + Texture_Wrap_Mirror_Repeat, // Mirrors and repeats the texture in tiled mode + Texture_Wrap_Mirror_Clamp // mirrors and clamps to border the texture in tiled mode + +} TextureWrap; + +// Cubemap layouts +typedef enum +{ + Cubemap_Layout_Auto_Detect = 0, // Automatically detect layout type + Cubemap_Layout_Line_Vertical, // Layout is defined by a vertical line with faces + Cubemap_Layout_Line_Horizontal, // Layout is defined by a horizontal line with faces + Cubemap_Layout_Cross_Three_By_Four, // Layout is defined by a 3x4 cross with cubemap faces + Cubemap_Layout_Cross_Four_By_Three, // Layout is defined by a 4x3 cross with cubemap faces + Cubemap_Layout_Panorama // layout is defined by a panorama image (equirrectangular 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_Alpha_Premultiply, // Blend premultiplied textures considering alpha + Blend_Custom, // Blend textures using custom src/dst factors (use rlSetBlendFactors()) + Blend_Custom_Separate // blend textures using custom rgb/alpha separate src/dst factors (use rlsetblendfactorsseparate()) + +} BlendMode; + +// Gesture +// NOTE: Provided as bit-wise flags to enable only desired gestures +typedef enum +{ + Gesture_None = 0, // No gesture + Gesture_Tap = 1, // Tap gesture + Gesture_Doubletap = 2, // Double tap gesture + Gesture_Hold = 4, // Hold gesture + Gesture_Drag = 8, // Drag gesture + Gesture_Swipe_Right = 16, // Swipe right gesture + Gesture_Swipe_Left = 32, // Swipe left gesture + Gesture_Swipe_Up = 64, // Swipe up gesture + Gesture_Swipe_Down = 128, // Swipe down gesture + Gesture_Pinch_In = 256, // Pinch in gesture + Gesture_Pinch_Out = 512 // pinch out gesture + +} Gesture; + +// Camera system modes +typedef enum +{ + Camera_Custom = 0, // 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: These callbacks are intended for advance users +typedef void ( *TraceLogCallback )( int logLevel, char const* text, va_list args ); // Logging: Redirect trace log messages +typedef unsigned char* ( *LoadFileDataCallback )( char const* fileName, int* dataSize ); // FileIO: Load binary data +typedef bool ( *SaveFileDataCallback )( char const* fileName, void* data, int dataSize ); // FileIO: Save binary data +typedef char* ( *LoadFileTextCallback )( char const* fileName ); // FileIO: Load text data +typedef bool ( *SaveFileTextCallback )( char const* fileName, char* text ); // FileIO: Save text data + +//------------------------------------------------------------------------------------ +// Global Variables Definition +//------------------------------------------------------------------------------------ +// It's lonely here... + +//------------------------------------------------------------------------------------ +// Window and Graphics Device Functions (Module: core) +//------------------------------------------------------------------------------------ + +#if defined( __cplusplus ) +namespace raylib +{ + extern "C" + { +// Prevents name mangling of functions +#endif + + // Window-related functions + RLAPI void init_window( s32 width, s32 height, char const* title ); // Initialize window and OpenGL context + RLAPI void close_window( void ); // Close window and unload OpenGL context + RLAPI bool window_should_close( void ); // Check if application should close (KEY_ESCAPE pressed or windows close icon clicked) + RLAPI bool is_window_ready( void ); // Check if window has been initialized successfully + RLAPI bool is_window_fullscreen( void ); // Check if window is currently fullscreen + RLAPI bool is_window_hidden( void ); // Check if window is currently hidden (only PLATFORM_DESKTOP) + RLAPI bool is_window_minimized( void ); // Check if window is currently minimized (only PLATFORM_DESKTOP) + RLAPI bool is_window_maximized( void ); // Check if window is currently maximized (only PLATFORM_DESKTOP) + RLAPI bool is_window_focused( void ); // Check if window is currently focused (only PLATFORM_DESKTOP) + RLAPI bool is_window_resized( void ); // Check if window has been resized last frame + RLAPI bool is_window_state( u32 flag ); // Check if one specific window flag is enabled + RLAPI void set_window_state( u32 flags ); // Set window configuration state using flags (only PLATFORM_DESKTOP) + RLAPI void clear_window_state( u32 flags ); // Clear window configuration state flags + RLAPI void toggle_fullscreen( void ); // Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP) + RLAPI void toggle_borderless_windowed( void ); // Toggle window state: borderless windowed (only PLATFORM_DESKTOP) + RLAPI void maximize_window( void ); // Set window state: maximized, if resizable (only PLATFORM_DESKTOP) + RLAPI void minimize_window( void ); // Set window state: minimized, if resizable (only PLATFORM_DESKTOP) + RLAPI void restore_window( void ); // Set window state: not minimized/maximized (only PLATFORM_DESKTOP) + RLAPI void set_window_icon( Image image ); // Set icon for window (single image, RGBA 32bit, only PLATFORM_DESKTOP) + RLAPI void set_window_icons( Image* images, s32 count ); // Set icon for window (multiple images, RGBA 32bit, only PLATFORM_DESKTOP) + RLAPI void set_window_title( char const* title ); // Set title for window (only PLATFORM_DESKTOP and PLATFORM_WEB) + RLAPI void set_window_position( s32 x, s32 y ); // Set window position on screen (only PLATFORM_DESKTOP) + RLAPI void set_window_monitor( s32 monitor ); // Set monitor for the current window + RLAPI void set_window_min_size( s32 width, s32 height ); // Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE) + RLAPI void set_window_max_size( s32 width, s32 height ); // Set window maximum dimensions (for FLAG_WINDOW_RESIZABLE) + RLAPI void set_window_size( s32 width, s32 height ); // Set window dimensions + RLAPI void set_window_opacity( f32 opacity ); // Set window opacity [0.0f..1.0f] (only PLATFORM_DESKTOP) + RLAPI void set_window_focused( void ); // Set window focused (only PLATFORM_DESKTOP) + RLAPI void* get_window_handle( void ); // Get native window handle + RLAPI int get_screen_width( void ); // Get current screen width + RLAPI int get_screen_height( void ); // Get current screen height + RLAPI int get_render_width( void ); // Get current render width (it considers HiDPI) + RLAPI int get_render_height( void ); // Get current render height (it considers HiDPI) + RLAPI int get_monitor_count( void ); // Get number of connected monitors + RLAPI int get_current_monitor( void ); // Get current connected monitor + RLAPI Vector2 get_monitor_position( s32 monitor ); // Get specified monitor position + RLAPI int get_monitor_width( s32 monitor ); // Get specified monitor width (current video mode used by monitor) + RLAPI int get_monitor_height( s32 monitor ); // Get specified monitor height (current video mode used by monitor) + RLAPI int get_monitor_physical_width( s32 monitor ); // Get specified monitor physical width in millimetres + RLAPI int get_monitor_physical_height( s32 monitor ); // Get specified monitor physical height in millimetres + RLAPI int get_monitor_refresh_rate( s32 monitor ); // Get specified monitor refresh rate + RLAPI Vector2 get_window_position( void ); // Get window position XY on monitor + RLAPI Vector2 get_window_scale_dpi( void ); // Get window scale DPI factor + RLAPI char const* get_monitor_name( s32 monitor ); // Get the human-readable, UTF-8 encoded name of the specified monitor + RLAPI void set_clipboard_text( char const* text ); // Set clipboard text content + RLAPI char const* get_clipboard_text( void ); // Get clipboard text content + RLAPI void enable_event_waiting( void ); // Enable waiting for events on EndDrawing(), no automatic event polling + RLAPI void disable_event_waiting( void ); // Disable waiting for events on EndDrawing(), automatic events polling + + // Cursor-related functions + RLAPI void show_cursor( void ); // Shows cursor + RLAPI void hide_cursor( void ); // Hides cursor + RLAPI bool is_cursor_hidden( void ); // Check if cursor is not visible + RLAPI void enable_cursor( void ); // Enables cursor (unlock cursor) + RLAPI void disable_cursor( void ); // Disables cursor (lock cursor) + RLAPI bool is_cursor_on_screen( void ); // Check if cursor is on the screen + + // Drawing-related functions + RLAPI void clear_background( Color color ); // Set background color (framebuffer clear color) + RLAPI void begin_drawing( void ); // Setup canvas (framebuffer) to start drawing + RLAPI void end_drawing( void ); // End canvas drawing and swap buffers (double buffering) + RLAPI void begin_mode_2d( Camera2D camera ); // Begin 2D mode with custom camera (2D) + RLAPI void end_mode_2d( void ); // Ends 2D mode with custom camera + RLAPI void begin_mode_3d( Camera3D camera ); // Begin 3D mode with custom camera (3D) + RLAPI void end_mode_3d( void ); // Ends 3D mode and returns to default 2D orthographic mode + RLAPI void begin_texture_mode( RenderTexture2D target ); // Begin drawing to render texture + RLAPI void end_texture_mode( void ); // Ends drawing to render texture + RLAPI void begin_shader_mode( Shader shader ); // Begin custom shader drawing + RLAPI void end_shader_mode( void ); // End custom shader drawing (use default shader) + RLAPI void begin_blend_mode( s32 mode ); // Begin blending mode (alpha, additive, multiplied, subtract, custom) + RLAPI void end_blend_mode( void ); // End blending mode (reset to default: alpha blending) + RLAPI void begin_scissor_mode( s32 x, s32 y, s32 width, s32 height ); // Begin scissor mode (define screen area for following drawing) + RLAPI void end_scissor_mode( void ); // End scissor mode + RLAPI void begin_vr_stereo_mode( VrStereoConfig config ); // Begin stereo rendering (requires VR simulator) + RLAPI void end_vr_stereo_mode( void ); // End stereo rendering (requires VR simulator) + + // VR stereo config functions for VR simulator + RLAPI VrStereoConfig load_vr_stereo_config( VrDeviceInfo device ); // Load VR stereo config for VR simulator device parameters + RLAPI void unload_vr_stereo_config( VrStereoConfig config ); // Unload VR stereo config + + // Shader management functions + // NOTE: Shader functionality is not available on OpenGL 1.1 + RLAPI Shader load_shader( char const* vsFileName, char const* fsFileName ); // Load shader from files and bind default locations + RLAPI Shader load_shader_from_memory( char const* vsCode, char const* fsCode ); // Load shader from code strings and bind default locations + RLAPI bool is_shader_ready( Shader shader ); // Check if a shader is ready + RLAPI int get_shader_location( Shader shader, char const* uniformName ); // Get shader uniform location + RLAPI int get_shader_location_attrib( Shader shader, char const* attribName ); // Get shader attribute location + RLAPI void set_shader_value( Shader shader, s32 locIndex, void const* value, s32 uniformType ); // Set shader uniform value + RLAPI void set_shader_value_v( Shader shader, s32 locIndex, void const* value, s32 uniformType, s32 count ); // Set shader uniform value vector + RLAPI void set_shader_value_matrix( Shader shader, s32 locIndex, Matrix mat ); // Set shader uniform value (matrix 4x4) + RLAPI void set_shader_value_texture( Shader shader, s32 locIndex, Texture2D texture ); // Set shader uniform value for texture (sampler2d) + RLAPI void unload_shader( Shader shader ); // Unload shader from GPU memory (VRAM) + + // Screen-space-related functions + RLAPI Ray get_mouse_ray( Vector2 mousePosition, Camera camera ); // Get a ray trace from mouse position + RLAPI Matrix get_camera_matrix( Camera camera ); // Get camera transform matrix (view matrix) + RLAPI Matrix get_camera_matrix_2d( Camera2D camera ); // Get camera 2d transform matrix + RLAPI Vector2 get_world_to_screen( Vector3 position, Camera camera ); // Get the screen space position for a 3d world space position + RLAPI Vector2 get_screen_to_world_2d( Vector2 position, Camera2D camera ); // Get the world space position for a 2d camera screen space position + RLAPI Vector2 get_world_to_screen_ex( Vector3 position, Camera camera, s32 width, s32 height ); // Get size position for a 3d world space position + RLAPI Vector2 get_world_to_screen_2d( Vector2 position, Camera2D camera ); // Get the screen space position for a 2d camera world space position + + // Timing-related functions + RLAPI void set_target_fps( s32 fps ); // Set target FPS (maximum) + RLAPI float get_frame_time( void ); // Get time in seconds for last frame drawn (delta time) + RLAPI double get_time( void ); // Get elapsed time in seconds since InitWindow() + RLAPI int get_fps( void ); // Get current FPS + + // 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 timing + PollInputEvents() + // To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL + RLAPI void swap_screen_buffer( void ); // Swap back buffer with front buffer (screen drawing) + RLAPI void poll_input_events( void ); // Register all input events + RLAPI void wait_time( double seconds ); // Wait for some time (halt program execution) + + // Misc. functions + RLAPI int get_random_value( s32 min, s32 max ); // Get a random value between min and max (both included) + RLAPI void set_random_seed( u32 seed ); // Set the seed for the random number generator + RLAPI void take_screenshot( char const* fileName ); // Takes a screenshot of current screen (filename extension defines format) + RLAPI void set_config_flags( u32 flags ); // Setup init configuration flags (view FLAGS) + RLAPI void open_url( char const* url ); // Open URL with default system browser (if available) + + // NOTE: Following functions implemented in module [utils] + //------------------------------------------------------------------ + RLAPI void trace_log( s32 logLevel, char const* text, ... ); // Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...) + RLAPI void set_trace_log_level( s32 logLevel ); // Set the current threshold (minimum) log level + RLAPI void* mem_alloc( u32 size ); // Internal memory allocator + RLAPI void* mem_realloc( void* ptr, u32 size ); // Internal memory reallocator + RLAPI void mem_free( void* ptr ); // Internal memory free + + // Set custom callbacks + // WARNING: Callbacks setup is intended for advance users + RLAPI void set_trace_log_callback( TraceLogCallback callback ); // Set custom trace log + RLAPI void set_load_file_data_callback( LoadFileDataCallback callback ); // Set custom file binary data loader + RLAPI void set_save_file_data_callback( SaveFileDataCallback callback ); // Set custom file binary data saver + RLAPI void set_load_file_text_callback( LoadFileTextCallback callback ); // Set custom file text data loader + RLAPI void set_save_file_text_callback( SaveFileTextCallback callback ); // Set custom file text data saver + + // Files management functions + RLAPI unsigned char* load_file_data( char const* fileName, s32* dataSize ); // Load file data as byte array (read) + RLAPI void unload_file_data( u8* data ); // Unload file data allocated by LoadFileData() + RLAPI bool save_file_data( char const* fileName, void* data, s32 dataSize ); // Save data to file from byte array (write), returns true on success + RLAPI bool export_data_as_code( unsigned char const* data, s32 dataSize, char const* fileName ); // Export data to code (.h), returns true on success + RLAPI char* load_file_text( char const* fileName ); // Load text data from file (read), returns a '\0' terminated string + RLAPI void unload_file_text( char* text ); // Unload file text data allocated by LoadFileText() + RLAPI bool + save_file_text( char const* fileName, char* text ); // Save text data to file (write), string must be '\0' terminated, returns true on success + //------------------------------------------------------------------ + + // File system functions + RLAPI bool file_exists( char const* fileName ); // Check if file exists + RLAPI bool directory_exists( char const* dirPath ); // Check if a directory path exists + RLAPI bool is_file_extension( char const* fileName, char const* ext ); // Check file extension (including point: .png, .wav) + RLAPI int get_file_length( char const* fileName ); // Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h) + RLAPI char const* get_file_extension( char const* fileName ); // Get pointer to extension for a filename string (includes dot: '.png') + RLAPI char const* get_file_name( char const* filePath ); // Get pointer to filename for a path string + RLAPI char const* get_file_name_without_ext( char const* filePath ); // Get filename string without extension (uses static string) + RLAPI char const* get_directory_path( char const* filePath ); // Get full path for a given fileName with path (uses static string) + RLAPI char const* get_prev_directory_path( char const* dirPath ); // Get previous directory path for a given path (uses static string) + RLAPI char const* get_working_directory( void ); // Get current working directory (uses static string) + RLAPI char const* get_application_directory( void ); // Get the directory of the running application (uses static string) + RLAPI bool change_directory( char const* dir ); // Change working directory, return true on success + RLAPI bool is_path_file( char const* path ); // Check if a given path is a file or a directory + RLAPI FilePathList load_directory_files( char const* dirPath ); // Load directory filepaths + RLAPI FilePathList load_directory_files_ex( + char const* basePath, + char const* filter, + bool scanSubdirs + ); // Load directory filepaths with extension filtering and recursive directory scan + RLAPI void unload_directory_files( FilePathList files ); // Unload filepaths + RLAPI bool is_file_dropped( void ); // Check if a file has been dropped into window + RLAPI FilePathList load_dropped_files( void ); // Load dropped filepaths + RLAPI void unload_dropped_files( FilePathList files ); // Unload dropped filepaths + RLAPI long get_file_mod_time( char const* fileName ); // Get file modification time (last write time) + + // Compression/Encoding functionality + RLAPI unsigned char* + compress_data( unsigned char const* data, s32 dataSize, s32* compDataSize ); // Compress data (DEFLATE algorithm), memory must be MemFree() + RLAPI unsigned char* decompress_data( + unsigned char const* compData, + s32 compDataSize, + s32* dataSize + ); // Decompress data (DEFLATE algorithm), memory must be MemFree() + RLAPI char* encode_data_base64( unsigned char const* data, s32 dataSize, s32* outputSize ); // Encode data to Base64 string, memory must be MemFree() + RLAPI unsigned char* decode_data_base64( unsigned char const* data, s32* outputSize ); // Decode Base64 string data, memory must be MemFree() + + //------------------------------------------------------------------------------------ + // Input Handling Functions (Module: core) + //------------------------------------------------------------------------------------ + + // Input-related functions: keyboard + RLAPI bool is_key_pressed( s32 key ); // Check if a key has been pressed once + RLAPI bool is_key_pressed_repeat( s32 key ); // Check if a key has been pressed again (Only PLATFORM_DESKTOP) + RLAPI bool is_key_down( s32 key ); // Check if a key is being pressed + RLAPI bool is_key_released( s32 key ); // Check if a key has been released once + RLAPI bool is_key_up( s32 key ); // Check if a key is NOT being pressed + RLAPI int get_key_pressed( void ); // Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty + RLAPI int get_char_pressed( void ); // Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty + RLAPI void set_exit_key( s32 key ); // Set a custom key to exit program (default is ESC) + + // Input-related functions: gamepads + RLAPI bool is_gamepad_available( s32 gamepad ); // Check if a gamepad is available + RLAPI char const* get_gamepad_name( s32 gamepad ); // Get gamepad internal name id + RLAPI bool is_gamepad_button_pressed( s32 gamepad, s32 button ); // Check if a gamepad button has been pressed once + RLAPI bool is_gamepad_button_down( s32 gamepad, s32 button ); // Check if a gamepad button is being pressed + RLAPI bool is_gamepad_button_released( s32 gamepad, s32 button ); // Check if a gamepad button has been released once + RLAPI bool is_gamepad_button_up( s32 gamepad, s32 button ); // Check if a gamepad button is NOT being pressed + RLAPI int get_gamepad_button_pressed( void ); // Get the last gamepad button pressed + RLAPI int get_gamepad_axis_count( s32 gamepad ); // Get gamepad axis count for a gamepad + RLAPI float get_gamepad_axis_movement( s32 gamepad, s32 axis ); // Get axis movement value for a gamepad axis + RLAPI int set_gamepad_mappings( char const* mappings ); // Set internal gamepad mappings (SDL_GameControllerDB) + + // Input-related functions: mouse + RLAPI bool is_mouse_button_pressed( s32 button ); // Check if a mouse button has been pressed once + RLAPI bool is_mouse_button_down( s32 button ); // Check if a mouse button is being pressed + RLAPI bool is_mouse_button_released( s32 button ); // Check if a mouse button has been released once + RLAPI bool is_mouse_button_up( s32 button ); // Check if a mouse button is NOT being pressed + RLAPI int get_mouse_x( void ); // Get mouse position X + RLAPI int get_mouse_y( void ); // Get mouse position Y + RLAPI Vector2 get_mouse_position( void ); // Get mouse position XY + RLAPI Vector2 get_mouse_delta( void ); // Get mouse delta between frames + RLAPI void set_mouse_position( s32 x, s32 y ); // Set mouse position XY + RLAPI void set_mouse_offset( s32 offsetX, s32 offsetY ); // Set mouse offset + RLAPI void set_mouse_scale( f32 scaleX, f32 scaleY ); // Set mouse scaling + RLAPI float get_mouse_wheel_move( void ); // Get mouse wheel movement for X or Y, whichever is larger + RLAPI Vector2 get_mouse_wheel_move_v( void ); // Get mouse wheel movement for both X and Y + RLAPI void set_mouse_cursor( s32 cursor ); // Set mouse cursor + + // Input-related functions: touch + RLAPI int get_touch_x( void ); // Get touch position X for touch point 0 (relative to screen size) + RLAPI int get_touch_y( void ); // Get touch position Y for touch point 0 (relative to screen size) + RLAPI Vector2 get_touch_position( s32 index ); // Get touch position XY for a touch point index (relative to screen size) + RLAPI int get_touch_point_id( s32 index ); // Get touch point identifier for given index + RLAPI int get_touch_point_count( void ); // Get number of touch points + + //------------------------------------------------------------------------------------ + // Gestures and Touch Handling Functions (Module: rgestures) + //------------------------------------------------------------------------------------ + RLAPI void set_gestures_enabled( u32 flags ); // Enable a set of gestures using flags + RLAPI bool is_gesture_detected( u32 gesture ); // Check if a gesture have been detected + RLAPI int get_gesture_detected( void ); // Get latest detected gesture + RLAPI float get_gesture_hold_duration( void ); // Get gesture hold time in milliseconds + RLAPI Vector2 get_gesture_drag_vector( void ); // Get gesture drag vector + RLAPI float get_gesture_drag_angle( void ); // Get gesture drag angle + RLAPI Vector2 get_gesture_pinch_vector( void ); // Get gesture pinch delta + RLAPI float get_gesture_pinch_angle( void ); // Get gesture pinch angle + + //------------------------------------------------------------------------------------ + // Camera System Functions (Module: rcamera) + //------------------------------------------------------------------------------------ + RLAPI void update_camera( Camera* camera, s32 mode ); // Update camera position for selected mode + RLAPI void update_camera_pro( Camera* camera, Vector3 movement, Vector3 rotation, f32 zoom ); // Update camera movement/rotation + + //------------------------------------------------------------------------------------ + // Basic Shapes Drawing Functions (Module: shapes) + //------------------------------------------------------------------------------------ + // Set texture and rectangle to be used on shapes drawing + // NOTE: It can be useful when using basic shapes and one single font, + // defining a font char white rectangle would allow drawing everything in a single draw call + RLAPI void set_shapes_texture( Texture2D texture, Rectangle source ); // Set texture and rectangle to be used on shapes drawing + + // Basic shapes drawing functions + RLAPI void draw_pixel( s32 posX, s32 posY, Color color ); // Draw a pixel + RLAPI void draw_pixel_v( Vector2 position, Color color ); // Draw a pixel (Vector version) + RLAPI void draw_line( s32 startPosX, s32 startPosY, s32 endPosX, s32 endPosY, Color color ); // Draw a line + RLAPI void draw_line_v( Vector2 startPos, Vector2 endPos, Color color ); // Draw a line (Vector version) + RLAPI void draw_line_ex( Vector2 startPos, Vector2 endPos, f32 thick, Color color ); // Draw a line defining thickness + RLAPI void draw_line_bezier( Vector2 startPos, Vector2 endPos, f32 thick, Color color ); // Draw a line using cubic-bezier curves in-out + RLAPI void draw_line_bezier_quad( Vector2 startPos, Vector2 endPos, Vector2 controlPos, f32 thick, Color color ); // Draw line using quadratic bezier + // curves with a control point + RLAPI void draw_line_bezier_cubic( + Vector2 startPos, + Vector2 endPos, + Vector2 startControlPos, + Vector2 endControlPos, + f32 thick, + Color color + ); // Draw line using cubic bezier curves with 2 control points + RLAPI void draw_line_bspline( Vector2* points, s32 pointCount, f32 thick, Color color ); // Draw a B-Spline line, minimum 4 points + RLAPI void draw_line_catmull_rom( Vector2* points, s32 pointCount, f32 thick, Color color ); // Draw a Catmull Rom spline line, minimum 4 points + RLAPI void draw_line_strip( Vector2* points, s32 pointCount, Color color ); // Draw lines sequence + RLAPI void draw_circle( s32 centerX, s32 centerY, f32 radius, Color color ); // Draw a color-filled circle + RLAPI void draw_circle_sector( Vector2 center, f32 radius, f32 startAngle, f32 endAngle, s32 segments, Color color ); // Draw a piece of a circle + RLAPI void + draw_circle_sector_lines( Vector2 center, f32 radius, f32 startAngle, f32 endAngle, s32 segments, Color color ); // Draw circle sector outline + RLAPI void draw_circle_gradient( s32 centerX, s32 centerY, f32 radius, Color color1, Color color2 ); // Draw a gradient-filled circle + RLAPI void draw_circle_v( Vector2 center, f32 radius, Color color ); // Draw a color-filled circle (Vector version) + RLAPI void draw_circle_lines( s32 centerX, s32 centerY, f32 radius, Color color ); // Draw circle outline + RLAPI void draw_circle_lines_v( Vector2 center, f32 radius, Color color ); // Draw circle outline (Vector version) + RLAPI void draw_ellipse( s32 centerX, s32 centerY, f32 radiusH, f32 radiusV, Color color ); // Draw ellipse + RLAPI void draw_ellipse_lines( s32 centerX, s32 centerY, f32 radiusH, f32 radiusV, Color color ); // Draw ellipse outline + RLAPI void draw_ring( Vector2 center, f32 innerRadius, f32 outerRadius, f32 startAngle, f32 endAngle, s32 segments, Color color ); // Draw ring + RLAPI void draw_ring_lines( Vector2 center, f32 innerRadius, f32 outerRadius, f32 startAngle, f32 endAngle, s32 segments, Color color ); // Draw ring + // outline + RLAPI void draw_rectangle( s32 posX, s32 posY, s32 width, s32 height, Color color ); // Draw a color-filled rectangle + RLAPI void draw_rectangle_v( Vector2 position, Vector2 size, Color color ); // Draw a color-filled rectangle (Vector version) + RLAPI void draw_rectangle_rec( Rectangle rec, Color color ); // Draw a color-filled rectangle + RLAPI void draw_rectangle_pro( Rectangle rec, Vector2 origin, f32 rotation, Color color ); // Draw a color-filled rectangle with pro parameters + RLAPI void + draw_rectangle_gradient_v( s32 posX, s32 posY, s32 width, s32 height, Color color1, Color color2 ); // Draw a vertical-gradient-filled rectangle + RLAPI void draw_rectangle_gradient_h( s32 posX, s32 posY, s32 width, s32 height, Color color1, Color color2 ); // Draw a horizontal-gradient-filled + // rectangle + RLAPI void draw_rectangle_gradient_ex( Rectangle rec, Color col1, Color col2, Color col3, Color col4 ); // Draw a gradient-filled rectangle with + // custom vertex colors + RLAPI void draw_rectangle_lines( s32 posX, s32 posY, s32 width, s32 height, Color color ); // Draw rectangle outline + RLAPI void draw_rectangle_lines_ex( Rectangle rec, f32 lineThick, Color color ); // Draw rectangle outline with extended parameters + RLAPI void draw_rectangle_rounded( Rectangle rec, f32 roundness, s32 segments, Color color ); // Draw rectangle with rounded edges + RLAPI void draw_rectangle_rounded_lines( Rectangle rec, f32 roundness, s32 segments, f32 lineThick, Color color ); // Draw rectangle with rounded + // edges outline + RLAPI void draw_triangle( Vector2 v1, Vector2 v2, Vector2 v3, Color color ); // Draw a color-filled triangle (vertex in counter-clockwise order!) + RLAPI void draw_triangle_lines( Vector2 v1, Vector2 v2, Vector2 v3, Color color ); // Draw triangle outline (vertex in counter-clockwise order!) + RLAPI void draw_triangle_fan( Vector2* points, s32 pointCount, Color color ); // Draw a triangle fan defined by points (first vertex is the center) + RLAPI void draw_triangle_strip( Vector2* points, s32 pointCount, Color color ); // Draw a triangle strip defined by points + RLAPI void draw_poly( Vector2 center, s32 sides, f32 radius, f32 rotation, Color color ); // Draw a regular polygon (Vector version) + RLAPI void draw_poly_lines( Vector2 center, s32 sides, f32 radius, f32 rotation, Color color ); // Draw a polygon outline of n sides + RLAPI void draw_poly_lines_ex( Vector2 center, s32 sides, f32 radius, f32 rotation, f32 lineThick, Color color ); // Draw a polygon outline of n + // sides with extended parameters + + // Basic shapes collision detection functions + RLAPI bool check_collision_recs( Rectangle rec1, Rectangle rec2 ); // Check collision between two rectangles + RLAPI bool check_collision_circles( Vector2 center1, f32 radius1, Vector2 center2, f32 radius2 ); // Check collision between two circles + RLAPI bool check_collision_circle_rec( Vector2 center, f32 radius, Rectangle rec ); // Check collision between circle and rectangle + RLAPI bool check_collision_point_rec( Vector2 point, Rectangle rec ); // Check if point is inside rectangle + RLAPI bool check_collision_point_circle( Vector2 point, Vector2 center, f32 radius ); // Check if point is inside circle + RLAPI bool check_collision_point_triangle( Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3 ); // Check if point is inside a triangle + RLAPI bool check_collision_point_poly( + Vector2 point, + Vector2* points, + s32 pointCount + ); // Check if point is within a polygon described by array of vertices + RLAPI bool check_collision_lines( + 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 check_collision_point_line( + Vector2 point, + Vector2 p1, + Vector2 p2, + s32 threshold + ); // Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] + RLAPI Rectangle get_collision_rec( Rectangle rec1, Rectangle rec2 ); // Get collision rectangle for two rectangles collision + + //------------------------------------------------------------------------------------ + // Texture Loading and Drawing Functions (Module: textures) + //------------------------------------------------------------------------------------ + + // Image loading functions + // NOTE: These functions do not require GPU access + RLAPI Image load_image( char const* fileName ); // Load image from file into CPU memory (RAM) + RLAPI Image load_image_raw( char const* fileName, s32 width, s32 height, s32 format, s32 headerSize ); // Load image from RAW file data + RLAPI Image load_image_svg( char const* fileNameOrString, s32 width, s32 height ); // Load image from SVG file data or string with specified size + RLAPI Image load_image_anim( char const* fileName, s32* frames ); // Load image sequence from file (frames appended to image.data) + RLAPI Image load_image_from_memory( + char const* fileType, + unsigned char const* fileData, + s32 dataSize + ); // Load image from memory buffer, fileType refers to extension: i.e. '.png' + RLAPI Image load_image_from_texture( Texture2D texture ); // Load image from GPU texture data + RLAPI Image load_image_from_screen( void ); // Load image from screen buffer and (screenshot) + RLAPI bool is_image_ready( Image image ); // Check if an image is ready + RLAPI void unload_image( Image image ); // Unload image from CPU memory (RAM) + RLAPI bool export_image( Image image, char const* fileName ); // Export image data to file, returns true on success + RLAPI unsigned char* export_image_to_memory( Image image, char const* fileType, s32* fileSize ); // Export image to memory buffer + RLAPI bool + export_image_as_code( Image image, char const* fileName ); // Export image as code file defining an array of bytes, returns true on success + + // Image generation functions + RLAPI Image gen_image_color( s32 width, s32 height, Color color ); // Generate image: plain color + RLAPI Image gen_image_gradient_linear( s32 width, s32 height, s32 direction, Color start, Color end ); // Generate image: linear gradient, direction + // in degrees [0..360], 0=Vertical gradient + RLAPI Image gen_image_gradient_radial( s32 width, s32 height, f32 density, Color inner, Color outer ); // Generate image: radial gradient + RLAPI Image gen_image_gradient_square( s32 width, s32 height, f32 density, Color inner, Color outer ); // Generate image: square gradient + RLAPI Image gen_image_checked( s32 width, s32 height, s32 checksX, s32 checksY, Color col1, Color col2 ); // Generate image: checked + RLAPI Image gen_image_white_noise( s32 width, s32 height, f32 factor ); // Generate image: white noise + RLAPI Image gen_image_perlin_noise( s32 width, s32 height, s32 offsetX, s32 offsetY, f32 scale ); // Generate image: perlin noise + RLAPI Image gen_image_cellular( s32 width, s32 height, s32 tileSize ); // Generate image: cellular algorithm, bigger tileSize means bigger cells + RLAPI Image gen_image_text( s32 width, s32 height, char const* text ); // Generate image: grayscale image from text data + + // Image manipulation functions + RLAPI Image image_copy( Image image ); // Create an image duplicate (useful for transformations) + RLAPI Image image_from_image( Image image, Rectangle rec ); // Create an image from another image piece + RLAPI Image image_text( char const* text, s32 fontSize, Color color ); // Create an image from text (default font) + RLAPI Image image_text_ex( Font font, char const* text, f32 fontSize, f32 spacing, Color tint ); // Create an image from text (custom sprite font) + RLAPI void image_format( Image* image, s32 newFormat ); // Convert image data to desired format + RLAPI void image_to_pot( Image* image, Color fill ); // Convert image to POT (power-of-two) + RLAPI void image_crop( Image* image, Rectangle crop ); // Crop an image to a defined rectangle + RLAPI void image_alpha_crop( Image* image, f32 threshold ); // Crop image depending on alpha value + RLAPI void image_alpha_clear( Image* image, Color color, f32 threshold ); // Clear alpha channel to desired color + RLAPI void image_alpha_mask( Image* image, Image alphaMask ); // Apply alpha mask to image + RLAPI void image_alpha_premultiply( Image* image ); // Premultiply alpha channel + RLAPI void image_blur_gaussian( Image* image, s32 blurSize ); // Apply Gaussian blur using a box blur approximation + RLAPI void image_resize( Image* image, s32 newWidth, s32 newHeight ); // Resize image (Bicubic scaling algorithm) + RLAPI void image_resize_nn( Image* image, s32 newWidth, s32 newHeight ); // Resize image (Nearest-Neighbor scaling algorithm) + RLAPI void + image_resize_canvas( Image* image, s32 newWidth, s32 newHeight, s32 offsetX, s32 offsetY, Color fill ); // Resize canvas and fill with color + RLAPI void image_mipmaps( Image* image ); // Compute all mipmap levels for a provided image + RLAPI void image_dither( Image* image, s32 rBpp, s32 gBpp, s32 bBpp, s32 aBpp ); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) + RLAPI void image_flip_vertical( Image* image ); // Flip image vertically + RLAPI void image_flip_horizontal( Image* image ); // Flip image horizontally + RLAPI void image_rotate( Image* image, s32 degrees ); // Rotate image by input angle in degrees (-359 to 359) + RLAPI void image_rotate_cw( Image* image ); // Rotate image clockwise 90deg + RLAPI void image_rotate_ccw( Image* image ); // Rotate image counter-clockwise 90deg + RLAPI void image_color_tint( Image* image, Color color ); // Modify image color: tint + RLAPI void image_color_invert( Image* image ); // Modify image color: invert + RLAPI void image_color_grayscale( Image* image ); // Modify image color: grayscale + RLAPI void image_color_contrast( Image* image, f32 contrast ); // Modify image color: contrast (-100 to 100) + RLAPI void image_color_brightness( Image* image, s32 brightness ); // Modify image color: brightness (-255 to 255) + RLAPI void image_color_replace( Image* image, Color color, Color replace ); // Modify image color: replace color + RLAPI Color* load_image_colors( Image image ); // Load color data from image as a Color array (RGBA - 32bit) + RLAPI Color* + load_image_palette( Image image, s32 maxPaletteSize, s32* colorCount ); // Load colors palette from image as a Color array (RGBA - 32bit) + RLAPI void unload_image_colors( Color* colors ); // Unload color data loaded with LoadImageColors() + RLAPI void unload_image_palette( Color* colors ); // Unload colors palette loaded with LoadImagePalette() + RLAPI Rectangle get_image_alpha_border( Image image, f32 threshold ); // Get image alpha border rectangle + RLAPI Color get_image_color( Image image, s32 x, s32 y ); // Get image pixel color at (x, y) position + + // Image drawing functions + // NOTE: Image software-rendering functions (CPU) + RLAPI void image_clear_background( Image* dst, Color color ); // Clear image background with given color + RLAPI void image_draw_pixel( Image* dst, s32 posX, s32 posY, Color color ); // Draw pixel within an image + RLAPI void image_draw_pixel_v( Image* dst, Vector2 position, Color color ); // Draw pixel within an image (Vector version) + RLAPI void image_draw_line( Image* dst, s32 startPosX, s32 startPosY, s32 endPosX, s32 endPosY, Color color ); // Draw line within an image + RLAPI void image_draw_line_v( Image* dst, Vector2 start, Vector2 end, Color color ); // Draw line within an image (Vector version) + RLAPI void image_draw_circle( Image* dst, s32 centerX, s32 centerY, s32 radius, Color color ); // Draw a filled circle within an image + RLAPI void image_draw_circle_v( Image* dst, Vector2 center, s32 radius, Color color ); // Draw a filled circle within an image (Vector version) + RLAPI void image_draw_circle_lines( Image* dst, s32 centerX, s32 centerY, s32 radius, Color color ); // Draw circle outline within an image + RLAPI void image_draw_circle_lines_v( Image* dst, Vector2 center, s32 radius, Color color ); // Draw circle outline within an image (Vector version) + RLAPI void image_draw_rectangle( Image* dst, s32 posX, s32 posY, s32 width, s32 height, Color color ); // Draw rectangle within an image + RLAPI void image_draw_rectangle_v( Image* dst, Vector2 position, Vector2 size, Color color ); // Draw rectangle within an image (Vector version) + RLAPI void image_draw_rectangle_rec( Image* dst, Rectangle rec, Color color ); // Draw rectangle within an image + RLAPI void image_draw_rectangle_lines( Image* dst, Rectangle rec, s32 thick, Color color ); // Draw rectangle lines within an image + RLAPI void image_draw( Image* dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint ); // Draw a source image within a destination image + // (tint applied to source) + RLAPI void image_draw_text( Image* dst, char const* text, s32 posX, s32 posY, s32 fontSize, Color color ); // Draw text (using default font) within + // an image (destination) + RLAPI void image_draw_text_ex( + Image* dst, + Font font, + char const* text, + Vector2 position, + f32 fontSize, + f32 spacing, + Color tint + ); // Draw text (custom sprite font) within an image (destination) + + // Texture loading functions + // NOTE: These functions require GPU access + RLAPI Texture2D load_texture( char const* fileName ); // Load texture from file into GPU memory (VRAM) + RLAPI Texture2D load_texture_from_image( Image image ); // Load texture from image data + RLAPI TextureCubemap load_texture_cubemap( Image image, s32 layout ); // Load cubemap from image, multiple image cubemap layouts supported + RLAPI RenderTexture2D load_render_texture( s32 width, s32 height ); // Load texture for rendering (framebuffer) + RLAPI bool is_texture_ready( Texture2D texture ); // Check if a texture is ready + RLAPI void unload_texture( Texture2D texture ); // Unload texture from GPU memory (VRAM) + RLAPI bool is_render_texture_ready( RenderTexture2D target ); // Check if a render texture is ready + RLAPI void unload_render_texture( RenderTexture2D target ); // Unload render texture from GPU memory (VRAM) + RLAPI void update_texture( Texture2D texture, void const* pixels ); // Update GPU texture with new data + RLAPI void update_texture_rec( Texture2D texture, Rectangle rec, void const* pixels ); // Update GPU texture rectangle with new data + + // Texture configuration functions + RLAPI void gen_texture_mipmaps( Texture2D* texture ); // Generate GPU mipmaps for a texture + RLAPI void set_texture_filter( Texture2D texture, s32 filter ); // Set texture scaling filter mode + RLAPI void set_texture_wrap( Texture2D texture, s32 wrap ); // Set texture wrapping mode + + // Texture drawing functions + RLAPI void draw_texture( Texture2D texture, s32 posX, s32 posY, Color tint ); // Draw a Texture2D + RLAPI void draw_texture_v( Texture2D texture, Vector2 position, Color tint ); // Draw a Texture2D with position defined as Vector2 + RLAPI void draw_texture_ex( Texture2D texture, Vector2 position, f32 rotation, f32 scale, Color tint ); // Draw a Texture2D with extended parameters + RLAPI void draw_texture_rec( Texture2D texture, Rectangle source, Vector2 position, Color tint ); // Draw a part of a texture defined by a rectangle + RLAPI void draw_texture_pro( + Texture2D texture, + Rectangle source, + Rectangle dest, + Vector2 origin, + f32 rotation, + Color tint + ); // Draw a part of a texture defined by a rectangle with 'pro' parameters + RLAPI void draw_texture_npatch( + Texture2D texture, + NPatchInfo nPatchInfo, + Rectangle dest, + Vector2 origin, + f32 rotation, + Color tint + ); // Draws a texture (or part of it) that stretches or shrinks nicely + + // Color/pixel related functions + RLAPI Color fade( Color color, f32 alpha ); // Get color with alpha applied, alpha goes from 0.0f to 1.0f + RLAPI int color_to_int( Color color ); // Get hexadecimal value for a Color + RLAPI Vector4 color_normalize( Color color ); // Get Color normalized as float [0..1] + RLAPI Color color_from_normalized( Vector4 normalized ); // Get Color from normalized values [0..1] + RLAPI Vector3 color_to_hsv( Color color ); // Get HSV values for a Color, hue [0..360], saturation/value [0..1] + RLAPI Color color_from_hsv( f32 hue, f32 saturation, f32 value ); // Get a Color from HSV values, hue [0..360], saturation/value [0..1] + RLAPI Color color_tint( Color color, Color tint ); // Get color multiplied with another color + RLAPI Color color_brightness( Color color, f32 factor ); // Get color with brightness correction, brightness factor goes from -1.0f to 1.0f + RLAPI Color color_contrast( Color color, f32 contrast ); // Get color with contrast correction, contrast values between -1.0f and 1.0f + RLAPI Color color_alpha( Color color, f32 alpha ); // Get color with alpha applied, alpha goes from 0.0f to 1.0f + RLAPI Color color_alpha_blend( Color dst, Color src, Color tint ); // Get src alpha-blended into dst color with tint + RLAPI Color get_color( u32 hexValue ); // Get Color structure from hexadecimal value + RLAPI Color get_pixel_color( void* srcPtr, s32 format ); // Get Color from a source pixel pointer of certain format + RLAPI void set_pixel_color( void* dstPtr, Color color, s32 format ); // Set color formatted into destination pixel pointer + RLAPI int get_pixel_data_size( s32 width, s32 height, s32 format ); // Get pixel data size in bytes for certain format + + //------------------------------------------------------------------------------------ + // Font Loading and Text Drawing Functions (Module: text) + //------------------------------------------------------------------------------------ + + // Font loading/unloading functions + RLAPI Font get_font_default( void ); // Get the default Font + RLAPI Font load_font( char const* fileName ); // Load font from file into GPU memory (VRAM) + RLAPI Font load_font_ex( + char const* fileName, + s32 fontSize, + s32* codepoints, + s32 codepointCount + ); // Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set + RLAPI Font load_font_from_image( Image image, Color key, s32 firstChar ); // Load font from Image (XNA style) + RLAPI Font load_font_from_memory( + char const* fileType, + unsigned char const* fileData, + s32 dataSize, + s32 fontSize, + s32* codepoints, + s32 codepointCount + ); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf' + RLAPI bool is_font_ready( Font font ); // Check if a font is ready + RLAPI GlyphInfo* + load_font_data( unsigned char const* fileData, s32 dataSize, s32 fontSize, s32* codepoints, s32 codepointCount, s32 type ); // Load font data for + // further use + RLAPI Image gen_image_font_atlas( + GlyphInfo const* glyphs, + Rectangle** glyphRecs, + s32 glyphCount, + s32 fontSize, + s32 padding, + s32 packMethod + ); // Generate image font atlas using chars info + RLAPI void unload_font_data( GlyphInfo* glyphs, s32 glyphCount ); // Unload font chars info data (RAM) + RLAPI void unload_font( Font font ); // Unload font from GPU memory (VRAM) + RLAPI bool export_font_as_code( Font font, char const* fileName ); // Export font as code file, returns true on success + + // Text drawing functions + RLAPI void draw_fps( s32 posX, s32 posY ); // Draw current FPS + RLAPI void draw_text( char const* text, s32 posX, s32 posY, s32 fontSize, Color color ); // Draw text (using default font) + RLAPI void draw_text_ex( Font font, char const* text, Vector2 position, f32 fontSize, f32 spacing, Color tint ); // Draw text using font and + // additional parameters + RLAPI void draw_text_pro( + Font font, + char const* text, + Vector2 position, + Vector2 origin, + f32 rotation, + f32 fontSize, + f32 spacing, + Color tint + ); // Draw text using Font and pro parameters (rotation) + RLAPI void draw_text_codepoint( Font font, s32 codepoint, Vector2 position, f32 fontSize, Color tint ); // Draw one character (codepoint) + RLAPI void draw_text_codepoints( + Font font, + int const* codepoints, + s32 codepointCount, + Vector2 position, + f32 fontSize, + f32 spacing, + Color tint + ); // Draw multiple character (codepoint) + + // Text font info functions + RLAPI void set_text_line_spacing( s32 spacing ); // Set vertical line spacing when drawing with line-breaks + RLAPI int measure_text( char const* text, s32 fontSize ); // Measure string width for default font + RLAPI Vector2 measure_text_ex( Font font, char const* text, f32 fontSize, f32 spacing ); // Measure string size for Font + RLAPI int get_glyph_index( + Font font, + s32 codepoint + ); // Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found + RLAPI GlyphInfo + get_glyph_info( Font font, s32 codepoint ); // Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found + RLAPI Rectangle get_glyph_atlas_rec( + Font font, + s32 codepoint + ); // Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found + + // Text codepoints management functions (unicode characters) + RLAPI char* load_utf8( int const* codepoints, s32 length ); // Load UTF-8 text encoded from codepoints array + RLAPI void unload_utf8( char* text ); // Unload UTF-8 text encoded from codepoints array + RLAPI int* load_codepoints( char const* text, s32* count ); // Load all codepoints from a UTF-8 text string, codepoints count returned by parameter + RLAPI void unload_codepoints( s32* codepoints ); // Unload codepoints data from memory + RLAPI int get_codepoint_count( char const* text ); // Get total number of codepoints in a UTF-8 encoded string + RLAPI int get_codepoint( char const* text, s32* codepointSize ); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure + RLAPI int + get_codepoint_next( char const* text, s32* codepointSize ); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure + RLAPI int get_codepoint_previous( + char const* text, + s32* codepointSize + ); // Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure + RLAPI char const* + codepoint_to_utf8( s32 codepoint, s32* utf8Size ); // Encode one codepoint into UTF-8 byte array (array length returned as parameter) + + // Text strings management functions (no UTF-8 strings, only byte chars) + // NOTE: Some strings allocate memory internally for returned strings, just be careful! + RLAPI int text_copy( char* dst, char const* src ); // Copy one string to another, returns bytes copied + RLAPI bool text_is_equal( char const* text1, char const* text2 ); // Check if two text string are equal + RLAPI unsigned int text_length( char const* text ); // Get text length, checks for '\0' ending + RLAPI char const* text_format( char const* text, ... ); // Text formatting with variables (sprintf() style) + RLAPI char const* text_subtext( char const* text, s32 position, s32 length ); // Get a piece of a text string + RLAPI char* text_replace( char* text, char const* replace, char const* by ); // Replace text string (WARNING: memory must be freed!) + RLAPI char* text_insert( char const* text, char const* insert, s32 position ); // Insert text in a position (WARNING: memory must be freed!) + RLAPI char const* text_join( char const** textList, s32 count, char const* delimiter ); // Join text strings with delimiter + RLAPI char const** text_split( char const* text, char delimiter, s32* count ); // Split text into multiple strings + RLAPI void text_append( char* text, char const* append, s32* position ); // Append text at specific position and move cursor! + RLAPI int text_find_index( char const* text, char const* find ); // Find first text occurrence within a string + RLAPI char const* text_to_upper( char const* text ); // Get upper case version of provided string + RLAPI char const* text_to_lower( char const* text ); // Get lower case version of provided string + RLAPI char const* text_to_pascal( char const* text ); // Get Pascal case notation version of provided string + RLAPI int text_to_integer( char const* 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 draw_line_3d( Vector3 startPos, Vector3 endPos, Color color ); // Draw a line in 3D world space + RLAPI void draw_point_3d( Vector3 position, Color color ); // Draw a point in 3D space, actually a small line + RLAPI void draw_circle_3d( Vector3 center, f32 radius, Vector3 rotationAxis, f32 rotationAngle, Color color ); // Draw a circle in 3D world space + RLAPI void draw_triangle_3d( Vector3 v1, Vector3 v2, Vector3 v3, Color color ); // Draw a color-filled triangle (vertex in counter-clockwise order!) + RLAPI void draw_triangle_strip_3d( Vector3* points, s32 pointCount, Color color ); // Draw a triangle strip defined by points + RLAPI void draw_cube( Vector3 position, f32 width, f32 height, f32 length, Color color ); // Draw cube + RLAPI void draw_cube_v( Vector3 position, Vector3 size, Color color ); // Draw cube (Vector version) + RLAPI void draw_cube_wires( Vector3 position, f32 width, f32 height, f32 length, Color color ); // Draw cube wires + RLAPI void draw_cube_wires_v( Vector3 position, Vector3 size, Color color ); // Draw cube wires (Vector version) + RLAPI void draw_sphere( Vector3 centerPos, f32 radius, Color color ); // Draw sphere + RLAPI void draw_sphere_ex( Vector3 centerPos, f32 radius, s32 rings, s32 slices, Color color ); // Draw sphere with extended parameters + RLAPI void draw_sphere_wires( Vector3 centerPos, f32 radius, s32 rings, s32 slices, Color color ); // Draw sphere wires + RLAPI void draw_cylinder( Vector3 position, f32 radiusTop, f32 radiusBottom, f32 height, s32 slices, Color color ); // Draw a cylinder/cone + RLAPI void + draw_cylinder_ex( Vector3 startPos, Vector3 endPos, f32 startRadius, f32 endRadius, s32 sides, Color color ); // Draw a cylinder with base at + // startPos and top at endPos + RLAPI void + draw_cylinder_wires( Vector3 position, f32 radiusTop, f32 radiusBottom, f32 height, s32 slices, Color color ); // Draw a cylinder/cone wires + RLAPI void draw_cylinder_wires_ex( + Vector3 startPos, + Vector3 endPos, + f32 startRadius, + f32 endRadius, + s32 sides, + Color color + ); // Draw a cylinder wires with base at startPos and top at endPos + RLAPI void draw_capsule( Vector3 startPos, Vector3 endPos, f32 radius, s32 slices, s32 rings, Color color ); // Draw a capsule with the center of its + // sphere caps at startPos and endPos + RLAPI void draw_capsule_wires( + Vector3 startPos, + Vector3 endPos, + f32 radius, + s32 slices, + s32 rings, + Color color + ); // Draw capsule wireframe with the center of its sphere caps at startPos and endPos + RLAPI void draw_plane( Vector3 centerPos, Vector2 size, Color color ); // Draw a plane XZ + RLAPI void draw_ray( Ray ray, Color color ); // Draw a ray line + RLAPI void draw_grid( s32 slices, f32 spacing ); // Draw a grid (centered at (0, 0, 0)) + + //------------------------------------------------------------------------------------ + // Model 3d Loading and Drawing Functions (Module: models) + //------------------------------------------------------------------------------------ + + // Model management functions + RLAPI Model load_model( char const* fileName ); // Load model from files (meshes and materials) + RLAPI Model load_model_from_mesh( Mesh mesh ); // Load model from generated mesh (default material) + RLAPI bool is_model_ready( Model model ); // Check if a model is ready + RLAPI void unload_model( Model model ); // Unload model (including meshes) from memory (RAM and/or VRAM) + RLAPI BoundingBox get_model_bounding_box( Model model ); // Compute model bounding box limits (considers all meshes) + + // Model drawing functions + RLAPI void draw_model( Model model, Vector3 position, f32 scale, Color tint ); // Draw a model (with texture if set) + RLAPI void draw_model_ex( Model model, Vector3 position, Vector3 rotationAxis, f32 rotationAngle, Vector3 scale, Color tint ); // Draw a model with + // extended parameters + RLAPI void draw_model_wires( Model model, Vector3 position, f32 scale, Color tint ); // Draw a model wires (with texture if set) + RLAPI void draw_model_wires_ex( + Model model, + Vector3 position, + Vector3 rotationAxis, + f32 rotationAngle, + Vector3 scale, + Color tint + ); // Draw a model wires (with texture if set) with extended parameters + RLAPI void draw_bounding_box( BoundingBox box, Color color ); // Draw bounding box (wires) + RLAPI void draw_billboard( Camera camera, Texture2D texture, Vector3 position, f32 size, Color tint ); // Draw a billboard texture + RLAPI void + draw_billboard_rec( Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector2 size, Color tint ); // Draw a billboard texture + // defined by source + RLAPI void draw_billboard_pro( + Camera camera, + Texture2D texture, + Rectangle source, + Vector3 position, + Vector3 up, + Vector2 size, + Vector2 origin, + f32 rotation, + Color tint + ); // Draw a billboard texture defined by source and rotation + + // Mesh management functions + RLAPI void upload_mesh( Mesh* mesh, bool dynamic ); // Upload mesh vertex data in GPU and provide VAO/VBO ids + RLAPI void update_mesh_buffer( Mesh mesh, s32 index, void const* data, s32 dataSize, s32 offset ); // Update mesh vertex data in GPU for a specific + // buffer index + RLAPI void unload_mesh( Mesh mesh ); // Unload mesh data from CPU and GPU + RLAPI void draw_mesh( Mesh mesh, Material material, Matrix transform ); // Draw a 3d mesh with material and transform + RLAPI void draw_mesh_instanced( Mesh mesh, Material material, Matrix const* transforms, s32 instances ); // Draw multiple mesh instances with + // material and different transforms + RLAPI bool export_mesh( Mesh mesh, char const* fileName ); // Export mesh data to file, returns true on success + RLAPI BoundingBox get_mesh_bounding_box( Mesh mesh ); // Compute mesh bounding box limits + RLAPI void gen_mesh_tangents( Mesh* mesh ); // Compute mesh tangents + + // Mesh generation functions + RLAPI Mesh gen_mesh_poly( s32 sides, f32 radius ); // Generate polygonal mesh + RLAPI Mesh gen_mesh_plane( f32 width, f32 length, s32 resX, s32 resZ ); // Generate plane mesh (with subdivisions) + RLAPI Mesh gen_mesh_cube( f32 width, f32 height, f32 length ); // Generate cuboid mesh + RLAPI Mesh gen_mesh_sphere( f32 radius, s32 rings, s32 slices ); // Generate sphere mesh (standard sphere) + RLAPI Mesh gen_mesh_hemi_sphere( f32 radius, s32 rings, s32 slices ); // Generate half-sphere mesh (no bottom cap) + RLAPI Mesh gen_mesh_cylinder( f32 radius, f32 height, s32 slices ); // Generate cylinder mesh + RLAPI Mesh gen_mesh_cone( f32 radius, f32 height, s32 slices ); // Generate cone/pyramid mesh + RLAPI Mesh gen_mesh_torus( f32 radius, f32 size, s32 radSeg, s32 sides ); // Generate torus mesh + RLAPI Mesh gen_mesh_knot( f32 radius, f32 size, s32 radSeg, s32 sides ); // Generate trefoil knot mesh + RLAPI Mesh gen_mesh_heightmap( Image heightmap, Vector3 size ); // Generate heightmap mesh from image data + RLAPI Mesh gen_mesh_cubicmap( Image cubicmap, Vector3 cubeSize ); // Generate cubes-based map mesh from image data + + // Material loading/unloading functions + RLAPI Material* load_materials( char const* fileName, s32* materialCount ); // Load materials from model file + RLAPI Material load_material_default( void ); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) + RLAPI bool is_material_ready( Material material ); // Check if a material is ready + RLAPI void unload_material( Material material ); // Unload material from GPU memory (VRAM) + RLAPI void set_material_texture( + Material* material, + s32 mapType, + Texture2D texture + ); // Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) + RLAPI void set_model_mesh_material( Model* model, s32 meshId, s32 materialId ); // Set material for a mesh + + // Model animations loading/unloading functions + RLAPI ModelAnimation* load_model_animations( char const* fileName, s32* animCount ); // Load model animations from file + RLAPI void update_model_animation( Model model, ModelAnimation anim, s32 frame ); // Update model animation pose + RLAPI void unload_model_animation( ModelAnimation anim ); // Unload animation data + RLAPI void unload_model_animations( ModelAnimation* animations, s32 animCount ); // Unload animation array data + RLAPI bool is_model_animation_valid( Model model, ModelAnimation anim ); // Check model animation skeleton match + + // Collision detection functions + RLAPI bool check_collision_spheres( Vector3 center1, f32 radius1, Vector3 center2, f32 radius2 ); // Check collision between two spheres + RLAPI bool check_collision_boxes( BoundingBox box1, BoundingBox box2 ); // Check collision between two bounding boxes + RLAPI bool check_collision_box_sphere( BoundingBox box, Vector3 center, f32 radius ); // Check collision between box and sphere + RLAPI RayCollision get_ray_collision_sphere( Ray ray, Vector3 center, f32 radius ); // Get collision info between ray and sphere + RLAPI RayCollision get_ray_collision_box( Ray ray, BoundingBox box ); // Get collision info between ray and box + RLAPI RayCollision get_ray_collision_mesh( Ray ray, Mesh mesh, Matrix transform ); // Get collision info between ray and mesh + RLAPI RayCollision get_ray_collision_triangle( Ray ray, Vector3 p1, Vector3 p2, Vector3 p3 ); // Get collision info between ray and triangle + RLAPI RayCollision get_ray_collision_quad( Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4 ); // Get collision info between ray and quad + + //------------------------------------------------------------------------------------ + // Audio Loading and Playing Functions (Module: audio) + //------------------------------------------------------------------------------------ + typedef void ( *AudioCallback )( void* bufferData, unsigned int frames ); + + // Audio device management functions + RLAPI void init_audio_device( void ); // Initialize audio device and context + RLAPI void close_audio_device( void ); // Close the audio device and context + RLAPI bool is_audio_device_ready( void ); // Check if audio device has been initialized successfully + RLAPI void set_master_volume( f32 volume ); // Set master volume (listener) + RLAPI float get_master_volume( void ); // Get master volume (listener) + + // Wave/Sound loading/unloading functions + RLAPI Wave load_wave( char const* fileName ); // Load wave data from file + RLAPI Wave load_wave_from_memory( + char const* fileType, + unsigned char const* fileData, + s32 dataSize + ); // Load wave from memory buffer, fileType refers to extension: i.e. '.wav' + RLAPI bool is_wave_ready( Wave wave ); // Checks if wave data is ready + RLAPI Sound load_sound( char const* fileName ); // Load sound from file + RLAPI Sound load_sound_from_wave( Wave wave ); // Load sound from wave data + RLAPI Sound load_sound_alias( Sound source ); // Create a new sound that shares the same sample data as the source sound, does not own the sound data + RLAPI bool is_sound_ready( Sound sound ); // Checks if a sound is ready + RLAPI void update_sound( Sound sound, void const* data, s32 sampleCount ); // Update sound buffer with new data + RLAPI void unload_wave( Wave wave ); // Unload wave data + RLAPI void unload_sound( Sound sound ); // Unload sound + RLAPI void unload_sound_alias( Sound alias ); // Unload a sound alias (does not deallocate sample data) + RLAPI bool export_wave( Wave wave, char const* fileName ); // Export wave data to file, returns true on success + RLAPI bool export_wave_as_code( Wave wave, char const* fileName ); // Export wave sample data to code (.h), returns true on success + + // Wave/Sound management functions + RLAPI void play_sound( Sound sound ); // Play a sound + RLAPI void stop_sound( Sound sound ); // Stop playing a sound + RLAPI void pause_sound( Sound sound ); // Pause a sound + RLAPI void resume_sound( Sound sound ); // Resume a paused sound + RLAPI bool is_sound_playing( Sound sound ); // Check if a sound is currently playing + RLAPI void set_sound_volume( Sound sound, f32 volume ); // Set volume for a sound (1.0 is max level) + RLAPI void set_sound_pitch( Sound sound, f32 pitch ); // Set pitch for a sound (1.0 is base level) + RLAPI void set_sound_pan( Sound sound, f32 pan ); // Set pan for a sound (0.5 is center) + RLAPI Wave wave_copy( Wave wave ); // Copy a wave to a new wave + RLAPI void wave_crop( Wave* wave, s32 initSample, s32 finalSample ); // Crop a wave to defined samples range + RLAPI void wave_format( Wave* wave, s32 sampleRate, s32 sampleSize, s32 channels ); // Convert wave data to desired format + RLAPI float* load_wave_samples( Wave wave ); // Load samples data from wave as a 32bit float data array + RLAPI void unload_wave_samples( f32* samples ); // Unload samples data loaded with LoadWaveSamples() + + // Music management functions + RLAPI Music load_music_stream( char const* fileName ); // Load music stream from file + RLAPI Music load_music_stream_from_memory( char const* fileType, unsigned char const* data, s32 dataSize ); // Load music stream from data + RLAPI bool is_music_ready( Music music ); // Checks if a music stream is ready + RLAPI void unload_music_stream( Music music ); // Unload music stream + RLAPI void play_music_stream( Music music ); // Start music playing + RLAPI bool is_music_stream_playing( Music music ); // Check if music is playing + RLAPI void update_music_stream( Music music ); // Updates buffers for music streaming + RLAPI void stop_music_stream( Music music ); // Stop music playing + RLAPI void pause_music_stream( Music music ); // Pause music playing + RLAPI void resume_music_stream( Music music ); // Resume playing paused music + RLAPI void seek_music_stream( Music music, f32 position ); // Seek music to a position (in seconds) + RLAPI void set_music_volume( Music music, f32 volume ); // Set volume for music (1.0 is max level) + RLAPI void set_music_pitch( Music music, f32 pitch ); // Set pitch for a music (1.0 is base level) + RLAPI void set_music_pan( Music music, f32 pan ); // Set pan for a music (0.5 is center) + RLAPI float get_music_time_length( Music music ); // Get music time length (in seconds) + RLAPI float get_music_time_played( Music music ); // Get current music time played (in seconds) + + // AudioStream management functions + RLAPI AudioStream load_audio_stream( u32 sampleRate, u32 sampleSize, u32 channels ); // Load audio stream (to stream raw audio pcm data) + RLAPI bool is_audio_stream_ready( AudioStream stream ); // Checks if an audio stream is ready + RLAPI void unload_audio_stream( AudioStream stream ); // Unload audio stream and free memory + RLAPI void update_audio_stream( AudioStream stream, void const* data, s32 frameCount ); // Update audio stream buffers with data + RLAPI bool is_audio_stream_processed( AudioStream stream ); // Check if any audio stream buffers requires refill + RLAPI void play_audio_stream( AudioStream stream ); // Play audio stream + RLAPI void pause_audio_stream( AudioStream stream ); // Pause audio stream + RLAPI void resume_audio_stream( AudioStream stream ); // Resume audio stream + RLAPI bool is_audio_stream_playing( AudioStream stream ); // Check if audio stream is playing + RLAPI void stop_audio_stream( AudioStream stream ); // Stop audio stream + RLAPI void set_audio_stream_volume( AudioStream stream, f32 volume ); // Set volume for audio stream (1.0 is max level) + RLAPI void set_audio_stream_pitch( AudioStream stream, f32 pitch ); // Set pitch for audio stream (1.0 is base level) + RLAPI void set_audio_stream_pan( AudioStream stream, f32 pan ); // Set pan for audio stream (0.5 is centered) + RLAPI void set_audio_stream_buffer_size_default( s32 size ); // Default size for new audio streams + RLAPI void set_audio_stream_callback( AudioStream stream, AudioCallback callback ); // Audio thread callback to request new data + + RLAPI void attach_audio_stream_processor( + AudioStream stream, + AudioCallback processor + ); // Attach audio stream processor to stream, receives the samples as s + RLAPI void detach_audio_stream_processor( AudioStream stream, AudioCallback processor ); // Detach audio stream processor from stream + + RLAPI void attach_audio_mixed_processor( AudioCallback processor + ); // Attach audio stream processor to the entire audio pipeline, receives the samples as s + RLAPI void detach_audio_mixed_processor( AudioCallback processor ); // Detach audio stream processor from the entire audio pipeline + +#if defined( __cplusplus ) + } +} +#endif + +#endif +// RAYLIB_H diff --git a/project/auxillary/vis_ast/dependencies/raylib/include/raymath.h b/project/auxillary/vis_ast/dependencies/raylib/include/raymath.h new file mode 100644 index 0000000..0a2073d --- /dev/null +++ b/project/auxillary/vis_ast/dependencies/raylib/include/raymath.h @@ -0,0 +1,2181 @@ +/********************************************************************************************** + * + * raymath v1.5 - Math functions to work with Vector2, Vector3, Matrix and Quaternions + * + * CONVENTIONS: + * - Matrix structure is defined as row-major (memory layout) but parameters naming AND all + * math operations performed by the library consider the structure as it was column-major + * It is like transposed versions of the matrices are used for all the maths + * It benefits some functions making them cache-friendly and also avoids matrix + * transpositions sometimes required by OpenGL + * Example: In memory order, row0 is [m0 m4 m8 m12] but in semantic math row0 is [m0 m1 m2 m3] + * - Functions are always self-contained, no function use another raymath function inside, + * required code is directly re-implemented inside + * - Functions input parameters are always received by value (2 unavoidable exceptions) + * - Functions use always a "result" variable for return + * - Functions are always defined inline + * - Angles are always in radians (DEG2RAD/RAD2DEG macros provided for convenience) + * - No compound literals used to make sure libray is compatible with C++ + * + * CONFIGURATION: + * #define RAYMATH_IMPLEMENTATION + * Generates the implementation of the library into the included file. + * If not defined, the library is in header only mode and can be included in other headers + * or source files without problems. But only ONE file should hold the implementation. + * + * #define RAYMATH_STATIC_INLINE + * Define static inline functions code, so #include header suffices for use. + * This may use up lots of memory. + * + * + * LICENSE: zlib/libpng + * + * Copyright (c) 2015-2023 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 RL_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 RL_RMAPI __declspec( dllexport ) extern inline // We are building raylib as a Win32 shared library (.dll). +#elif defined( _WIN32 ) && defined( USE_LIBTYPE_SHARED ) +#define RL_RMAPI __declspec( dllimport ) // We are using raylib as a Win32 shared library (.dll) +#else +#define RL_RMAPI extern inline // Provide external definition +#endif +#elif defined( RAYMATH_STATIC_INLINE ) +#define RL_RMAPI static inline // Functions may be inlined, no external out-of-line definition +#else +#if defined( __TINYC__ ) +#define RL_RMAPI static inline // plain inline not supported by tinycc (See issue #435) +#else +#define RL_RMAPI inline // Functions may be inlined or external definition used +#endif +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#ifndef PI +#define RL_PI 3.14159265358979323846f +#endif + +#ifndef EPSILON +#define RL_EPSILON 0.000001f +#endif + +#ifndef DEG2RAD +#define RL_DEG2RAD ( PI / 180.0f ) +#endif + +#ifndef RAD2DEG +#define RL_RAD2DEG ( 180.0f / PI ) +#endif + +// Get float vector for Matrix +#ifndef MatrixToFloat +#define RL_MatrixToFloat( mat ) ( MatrixToFloatV( mat ).v ) +#endif + +// Get float vector for Vector3 +#ifndef Vector3ToFloat +#define RL_Vector3ToFloat( vec ) ( Vector3ToFloatV( vec ).v ) +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +#if ! defined( RL_VECTOR2_TYPE ) +// Vector2 type +typedef struct Vector2 +{ + f32 x; + f32 y; + +} Vector2; +#endif + +#if ! defined( RL_VECTOR3_TYPE ) +// Vector3 type +typedef struct Vector3 +{ + f32 x; + f32 y; + f32 z; + +} Vector3; +#endif + +#if ! defined( RL_VECTOR4_TYPE ) +// Vector4 type +typedef struct Vector4 +{ + f32 x; + f32 y; + f32 z; + f32 w; + +} Vector4; +#endif + +#if ! defined( RL_QUATERNION_TYPE ) +// Quaternion type +typedef Vector4 Quaternion; +#endif + +#if ! defined( RL_MATRIX_TYPE ) +// Matrix type (OpenGL style 4x4 - right handed, column major) +typedef struct Matrix +{ + f32 m0, m4, m8, m12; // Matrix first row (4 components) + f32 m1, m5, m9, m13; // Matrix second row (4 components) + f32 m2, m6, m10, m14; // Matrix third row (4 components) + f32 m3, m7, m11, m15; // Matrix fourth row (4 components) + +} Matrix; +#endif + +// NOTE: Helper types to be used instead of array return types for *ToFloat functions +typedef struct float3 +{ + f32 v; + +} float3; + +typedef struct float16 +{ + f32 v; + +} float16; + +#include + +// Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), floor(), fminf(), fmaxf(), fabs() + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Utils math +//---------------------------------------------------------------------------------- + +// Clamp float value +RMAPI float clamp( f32 value, f32 min, f32 max ) +{ + float result = ( value < min ) ? min : value; + + if ( result > max ) + result = max; + + return result; +} + +// Calculate linear interpolation between two floats +RMAPI float lerp( f32 start, f32 end, f32 amount ) +{ + float result = start + amount * ( end - start ); + + return result; +} + +// Normalize input value within input range +RMAPI float normalize( f32 value, f32 start, f32 end ) +{ + float result = ( value - start ) / ( end - start ); + + return result; +} + +// Remap input value within input range to output range +RMAPI float remap( f32 value, f32 inputStart, f32 inputEnd, f32 outputStart, f32 outputEnd ) +{ + float result = ( value - inputStart ) / ( inputEnd - inputStart ) * ( outputEnd - outputStart ) + outputStart; + + return result; +} + +// Wrap input value from min to max +RMAPI float wrap( f32 value, f32 min, f32 max ) +{ + float result = value - ( max - min ) * floorf( ( value - min ) / ( max - min ) ); + + return result; +} + +// Check whether two given floats are almost equal +RMAPI int float_equals( f32 x, f32 y ) +{ +#if ! defined( EPSILON ) +#define EPSILON 0.000001f +#endif + + int result = ( fabsf( x - y ) ) <= ( EPSILON * fmaxf( 1.0f, fmaxf( fabsf( x ), fabsf( y ) ) ) ); + + return result; +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Vector2 math +//---------------------------------------------------------------------------------- + +// Vector with components value 0.0f +RMAPI Vector2 vector2_zero( void ) +{ + Vector2 result = { 0.0f, 0.0f }; + + return result; +} + +// Vector with components value 1.0f +RMAPI Vector2 vector2_one( void ) +{ + Vector2 result = { 1.0f, 1.0f }; + + return result; +} + +// Add two vectors (v1 + v2) +RMAPI Vector2 vector2_add( Vector2 v1, Vector2 v2 ) +{ + Vector2 result = { v1.x + v2.x, v1.y + v2.y }; + + return result; +} + +// Add vector and float value +RMAPI Vector2 vector2_add_value( Vector2 v, f32 add ) +{ + Vector2 result = { v.x + add, v.y + add }; + + return result; +} + +// Subtract two vectors (v1 - v2) +RMAPI Vector2 vector2_subtract( Vector2 v1, Vector2 v2 ) +{ + Vector2 result = { v1.x - v2.x, v1.y - v2.y }; + + return result; +} + +// Subtract vector by float value +RMAPI Vector2 vector2_subtract_value( Vector2 v, f32 sub ) +{ + Vector2 result = { v.x - sub, v.y - sub }; + + return result; +} + +// Calculate vector length +RMAPI float vector2_length( Vector2 v ) +{ + float result = sqrtf( ( v.x * v.x ) + ( v.y * v.y ) ); + + return result; +} + +// Calculate vector square length +RMAPI float vector2_length_sqr( Vector2 v ) +{ + float result = ( v.x * v.x ) + ( v.y * v.y ); + + return result; +} + +// Calculate two vectors dot product +RMAPI float vector_2dot_product( Vector2 v1, Vector2 v2 ) +{ + float result = ( v1.x * v2.x + v1.y * v2.y ); + + return result; +} + +// Calculate distance between two vectors +RMAPI float vector_2distance( Vector2 v1, Vector2 v2 ) +{ + float result = sqrtf( ( v1.x - v2.x ) * ( v1.x - v2.x ) + ( v1.y - v2.y ) * ( v1.y - v2.y ) ); + + return result; +} + +// Calculate square distance between two vectors +RMAPI float vector_2distance_sqr( Vector2 v1, Vector2 v2 ) +{ + float result = ( ( v1.x - v2.x ) * ( v1.x - v2.x ) + ( v1.y - v2.y ) * ( v1.y - v2.y ) ); + + return result; +} + +// Calculate angle between two vectors +// NOTE: Angle is calculated from origin point (0, 0) +RMAPI float vector2_angle( Vector2 v1, Vector2 v2 ) +{ + float result = 0.0f; + + float dot = v1.x * v2.x + v1.y * v2.y; + float det = v1.x * v2.y - v1.y * v2.x; + + result = atan2f( det, dot ); + + return result; +} + +// Calculate angle defined by a two vectors line +// NOTE: Parameters need to be normalized +// Current implementation should be aligned with glm::angle +RMAPI float vector2_line_angle( Vector2 start, Vector2 end ) +{ + float result = 0.0f; + + // TODO(10/9/2023): Currently angles move clockwise, determine if this is wanted behavior + result = -atan2f( end.y - start.y, end.x - start.x ); + + return result; +} + +// Scale vector (multiply by value) +RMAPI Vector2 vector2_scale( Vector2 v, f32 scale ) +{ + Vector2 result = { v.x * scale, v.y * scale }; + + return result; +} + +// Multiply vector by vector +RMAPI Vector2 vector2_multiply( Vector2 v1, Vector2 v2 ) +{ + Vector2 result = { v1.x * v2.x, v1.y * v2.y }; + + return result; +} + +// Negate vector +RMAPI Vector2 vector2_negate( Vector2 v ) +{ + Vector2 result = { -v.x, -v.y }; + + return result; +} + +// Divide vector by vector +RMAPI Vector2 vector_2divide( Vector2 v1, Vector2 v2 ) +{ + Vector2 result = { v1.x / v2.x, v1.y / v2.y }; + + return result; +} + +// Normalize provided vector +RMAPI Vector2 vector2_normalize( Vector2 v ) +{ + Vector2 result = { 0 }; + float length = sqrtf( ( v.x * v.x ) + ( v.y * v.y ) ); + + if ( length > 0 ) + { + float ilength = 1.0f / length; + result.x = v.x * ilength; + result.y = v.y * ilength; + } + + return result; +} + +// Transforms a Vector2 by a given Matrix +RMAPI Vector2 vector2_transform( Vector2 v, Matrix mat ) +{ + Vector2 result = { 0 }; + + float x = v.x; + float y = v.y; + float z = 0; + + result.x = mat.m0 * x + mat.m4 * y + mat.m8 * z + mat.m12; + result.y = mat.m1 * x + mat.m5 * y + mat.m9 * z + mat.m13; + + return result; +} + +// Calculate linear interpolation between two vectors +RMAPI Vector2 vector2_lerp( Vector2 v1, Vector2 v2, f32 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 vector2_reflect( 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 vector2_rotate( Vector2 v, f32 angle ) +{ + Vector2 result = { 0 }; + + float cosres = cosf( angle ); + float sinres = sinf( angle ); + + result.x = v.x * cosres - v.y * sinres; + result.y = v.x * sinres + v.y * cosres; + + return result; +} + +// Move Vector towards target +RMAPI Vector2 vector2_move_towards( Vector2 v, Vector2 target, f32 maxDistance ) +{ + Vector2 result = { 0 }; + + float dx = target.x - v.x; + float dy = target.y - v.y; + float value = ( dx * dx ) + ( dy * dy ); + + if ( ( value == 0 ) || ( ( maxDistance >= 0 ) && ( value <= maxDistance * maxDistance ) ) ) + return target; + + float dist = sqrtf( value ); + + result.x = v.x + dx / dist * maxDistance; + result.y = v.y + dy / dist * maxDistance; + + return result; +} + +// Invert the given vector +RMAPI Vector2 vector2_invert( Vector2 v ) +{ + Vector2 result = { 1.0f / v.x, 1.0f / v.y }; + + return result; +} + +// Clamp the components of the vector between +// min and max values specified by the given vectors +RMAPI Vector2 vector2_clamp( Vector2 v, Vector2 min, Vector2 max ) +{ + Vector2 result = { 0 }; + + result.x = fminf( max.x, fmaxf( min.x, v.x ) ); + result.y = fminf( max.y, fmaxf( min.y, v.y ) ); + + return result; +} + +// Clamp the magnitude of the vector between two min and max values +RMAPI Vector2 vector2_clamp_value( Vector2 v, f32 min, f32 max ) +{ + Vector2 result = v; + + float length = ( v.x * v.x ) + ( v.y * v.y ); + if ( length > 0.0f ) + { + length = sqrtf( length ); + + if ( length < min ) + { + float scale = min / length; + result.x = v.x * scale; + result.y = v.y * scale; + } + else if ( length > max ) + { + float scale = max / length; + result.x = v.x * scale; + result.y = v.y * scale; + } + } + + return result; +} + +// Check whether two given vectors are almost equal +RMAPI int vector2_equals( Vector2 p, Vector2 q ) +{ +#if ! defined( EPSILON ) +#define EPSILON 0.000001f +#endif + + int result = ( ( fabsf( p.x - q.x ) ) <= ( EPSILON * fmaxf( 1.0f, fmaxf( fabsf( p.x ), fabsf( q.x ) ) ) ) ) + && ( ( fabsf( p.y - q.y ) ) <= ( EPSILON * fmaxf( 1.0f, fmaxf( fabsf( p.y ), fabsf( q.y ) ) ) ) ); + + return result; +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Vector3 math +//---------------------------------------------------------------------------------- + +// Vector with components value 0.0f +RMAPI Vector3 vector3_zero( void ) +{ + Vector3 result = { 0.0f, 0.0f, 0.0f }; + + return result; +} + +// Vector with components value 1.0f +RMAPI Vector3 vector3_one( void ) +{ + Vector3 result = { 1.0f, 1.0f, 1.0f }; + + return result; +} + +// Add two vectors +RMAPI Vector3 vector3_add( 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 vector3_add_value( Vector3 v, f32 add ) +{ + Vector3 result = { v.x + add, v.y + add, v.z + add }; + + return result; +} + +// Subtract two vectors +RMAPI Vector3 vector3_subtract( 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 vector3_subtract_value( Vector3 v, f32 sub ) +{ + Vector3 result = { v.x - sub, v.y - sub, v.z - sub }; + + return result; +} + +// Multiply vector by scalar +RMAPI Vector3 vector3_scale( Vector3 v, f32 scalar ) +{ + Vector3 result = { v.x * scalar, v.y * scalar, v.z * scalar }; + + return result; +} + +// Multiply vector by vector +RMAPI Vector3 vector3_multiply( 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 vector3_cross_product( 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 vector3_perpendicular( Vector3 v ) +{ + Vector3 result = { 0 }; + + float min = ( float )fabs( v.x ); + Vector3 cardinalAxis = { 1.0f, 0.0f, 0.0f }; + + if ( fabsf( v.y ) < min ) + { + min = ( float )fabs( v.y ); + Vector3 tmp = { 0.0f, 1.0f, 0.0f }; + cardinalAxis = tmp; + } + + if ( fabsf( v.z ) < min ) + { + Vector3 tmp = { 0.0f, 0.0f, 1.0f }; + cardinalAxis = tmp; + } + + // Cross product between vectors + result.x = v.y * cardinalAxis.z - v.z * cardinalAxis.y; + result.y = v.z * cardinalAxis.x - v.x * cardinalAxis.z; + result.z = v.x * cardinalAxis.y - v.y * cardinalAxis.x; + + return result; +} + +// Calculate vector length +RMAPI float vector3_length( Vector3 const v ) +{ + float result = sqrtf( v.x * v.x + v.y * v.y + v.z * v.z ); + + return result; +} + +// Calculate vector square length +RMAPI float vector3_length_sqr( Vector3 const v ) +{ + float result = v.x * v.x + v.y * v.y + v.z * v.z; + + return result; +} + +// Calculate two vectors dot product +RMAPI float vector_3dot_product( 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 vector_3distance( Vector3 v1, Vector3 v2 ) +{ + float result = 0.0f; + + float dx = v2.x - v1.x; + float dy = v2.y - v1.y; + float dz = v2.z - v1.z; + result = sqrtf( dx * dx + dy * dy + dz * dz ); + + return result; +} + +// Calculate square distance between two vectors +RMAPI float vector_3distance_sqr( Vector3 v1, Vector3 v2 ) +{ + float result = 0.0f; + + float dx = v2.x - v1.x; + float dy = v2.y - v1.y; + float dz = v2.z - v1.z; + result = dx * dx + dy * dy + dz * dz; + + return result; +} + +// Calculate angle between two vectors +RMAPI float vector3_angle( Vector3 v1, Vector3 v2 ) +{ + float result = 0.0f; + + Vector3 cross = { v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x }; + float len = sqrtf( cross.x * cross.x + cross.y * cross.y + cross.z * cross.z ); + float dot = ( v1.x * v2.x + v1.y * v2.y + v1.z * v2.z ); + result = atan2f( len, dot ); + + return result; +} + +// Negate provided vector (invert direction) +RMAPI Vector3 vector3_negate( Vector3 v ) +{ + Vector3 result = { -v.x, -v.y, -v.z }; + + return result; +} + +// Divide vector by vector +RMAPI Vector3 vector_3divide( 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 vector3_normalize( Vector3 v ) +{ + Vector3 result = v; + + float length = sqrtf( v.x * v.x + v.y * v.y + v.z * v.z ); + if ( length != 0.0f ) + { + float ilength = 1.0f / length; + + result.x *= ilength; + result.y *= ilength; + result.z *= ilength; + } + + return result; +} + +// Calculate the projection of the vector v1 on to v2 +RMAPI Vector3 vector3_project( Vector3 v1, Vector3 v2 ) +{ + Vector3 result = { 0 }; + + float v1dv2 = ( v1.x * v2.x + v1.y * v2.y + v1.z * v2.z ); + float v2dv2 = ( v2.x * v2.x + v2.y * v2.y + v2.z * v2.z ); + + float mag = v1dv2 / v2dv2; + + result.x = v2.x * mag; + result.y = v2.y * mag; + result.z = v2.z * mag; + + return result; +} + +// Calculate the rejection of the vector v1 on to v2 +RMAPI Vector3 vector3_reject( Vector3 v1, Vector3 v2 ) +{ + Vector3 result = { 0 }; + + float v1dv2 = ( v1.x * v2.x + v1.y * v2.y + v1.z * v2.z ); + float v2dv2 = ( v2.x * v2.x + v2.y * v2.y + v2.z * v2.z ); + + float mag = v1dv2 / v2dv2; + + result.x = v1.x - ( v2.x * mag ); + result.y = v1.y - ( v2.y * mag ); + result.z = v1.z - ( v2.z * mag ); + + return result; +} + +// Orthonormalize provided vectors +// Makes vectors normalized and orthogonal to each other +// Gram-Schmidt function implementation +RMAPI void vector3_ortho_normalize( 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 vector3_transform( 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 vector3_rotate_by_quaternion( Vector3 v, Quaternion q ) +{ + Vector3 result = { 0 }; + + result.x = v.x * ( q.x * q.x + q.w * q.w - q.y * q.y - q.z * q.z ) + v.y * ( 2 * q.x * q.y - 2 * q.w * q.z ) + v.z * ( 2 * q.x * q.z + 2 * q.w * q.y ); + result.y = v.x * ( 2 * q.w * q.z + 2 * q.x * q.y ) + v.y * ( q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z ) + v.z * ( -2 * q.w * q.x + 2 * q.y * q.z ); + result.z = v.x * ( -2 * q.w * q.y + 2 * q.x * q.z ) + v.y * ( 2 * q.w * q.x + 2 * q.y * q.z ) + v.z * ( q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z ); + + return result; +} + +// Rotates a vector around an axis +RMAPI Vector3 vector3_rotate_by_axis_angle( Vector3 v, Vector3 axis, f32 angle ) +{ + Vector3 result = v; + + // Vector3Normalize(axis); + float length = sqrtf( axis.x * axis.x + axis.y * axis.y + axis.z * axis.z ); + if ( length == 0.0f ) + length = 1.0f; + float ilength = 1.0f / length; + axis.x *= ilength; + axis.y *= ilength; + axis.z *= ilength; + + angle /= 2.0f; + float a = sinf( angle ); + float b = axis.x * a; + float c = axis.y * a; + float d = axis.z * a; + a = cosf( angle ); + Vector3 w = { b, c, d }; + + // Vector3CrossProduct(w, v) + Vector3 wv = { w.y * v.z - w.z * v.y, w.z * v.x - w.x * v.z, w.x * v.y - w.y * v.x }; + + // Vector3CrossProduct(w, wv) + Vector3 wwv = { w.y * wv.z - w.z * wv.y, w.z * wv.x - w.x * wv.z, w.x * wv.y - w.y * wv.x }; + + // Vector3Scale(wv, 2*a) + a *= 2; + wv.x *= a; + wv.y *= a; + wv.z *= a; + + // Vector3Scale(wwv, 2) + wwv.x *= 2; + wwv.y *= 2; + wwv.z *= 2; + + result.x += wv.x; + result.y += wv.y; + result.z += wv.z; + + result.x += wwv.x; + result.y += wwv.y; + result.z += wwv.z; + + return result; +} + +// Calculate linear interpolation between two vectors +RMAPI Vector3 vector3_lerp( Vector3 v1, Vector3 v2, f32 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 vector3_reflect( 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 vector3_min( 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 vector3_max( 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 vector3_barycenter( 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 vector3_unproject( Vector3 source, Matrix projection, Matrix view ) +{ + Vector3 result = { 0 }; + + // Calculate unprojected matrix (multiply view matrix by projection matrix) and invert it + Matrix matViewProj = { // MatrixMultiply(view, projection); + view.m0 * projection.m0 + view.m1 * projection.m4 + view.m2 * projection.m8 + view.m3 * projection.m12, + view.m0 * projection.m1 + view.m1 * projection.m5 + view.m2 * projection.m9 + view.m3 * projection.m13, + view.m0 * projection.m2 + view.m1 * projection.m6 + view.m2 * projection.m10 + view.m3 * projection.m14, + view.m0 * projection.m3 + view.m1 * projection.m7 + view.m2 * projection.m11 + view.m3 * projection.m15, + view.m4 * projection.m0 + view.m5 * projection.m4 + view.m6 * projection.m8 + view.m7 * projection.m12, + view.m4 * projection.m1 + view.m5 * projection.m5 + view.m6 * projection.m9 + view.m7 * projection.m13, + view.m4 * projection.m2 + view.m5 * projection.m6 + view.m6 * projection.m10 + view.m7 * projection.m14, + view.m4 * projection.m3 + view.m5 * projection.m7 + view.m6 * projection.m11 + view.m7 * projection.m15, + view.m8 * projection.m0 + view.m9 * projection.m4 + view.m10 * projection.m8 + view.m11 * projection.m12, + view.m8 * projection.m1 + view.m9 * projection.m5 + view.m10 * projection.m9 + view.m11 * projection.m13, + view.m8 * projection.m2 + view.m9 * projection.m6 + view.m10 * projection.m10 + view.m11 * projection.m14, + view.m8 * projection.m3 + view.m9 * projection.m7 + view.m10 * projection.m11 + view.m11 * projection.m15, + view.m12 * projection.m0 + view.m13 * projection.m4 + view.m14 * projection.m8 + view.m15 * projection.m12, + view.m12 * projection.m1 + view.m13 * projection.m5 + view.m14 * projection.m9 + view.m15 * projection.m13, + view.m12 * projection.m2 + view.m13 * projection.m6 + view.m14 * projection.m10 + view.m15 * projection.m14, + view.m12 * projection.m3 + view.m13 * projection.m7 + view.m14 * projection.m11 + view.m15 * projection.m15 + }; + + // Calculate inverted matrix -> MatrixInvert(matViewProj); + // Cache the matrix values (speed optimization) + float a00 = matViewProj.m0, a01 = matViewProj.m1, a02 = matViewProj.m2, a03 = matViewProj.m3; + float a10 = matViewProj.m4, a11 = matViewProj.m5, a12 = matViewProj.m6, a13 = matViewProj.m7; + float a20 = matViewProj.m8, a21 = matViewProj.m9, a22 = matViewProj.m10, a23 = matViewProj.m11; + float a30 = matViewProj.m12, a31 = matViewProj.m13, a32 = matViewProj.m14, a33 = matViewProj.m15; + + float b00 = a00 * a11 - a01 * a10; + float b01 = a00 * a12 - a02 * a10; + float b02 = a00 * a13 - a03 * a10; + float b03 = a01 * a12 - a02 * a11; + float b04 = a01 * a13 - a03 * a11; + float b05 = a02 * a13 - a03 * a12; + float b06 = a20 * a31 - a21 * a30; + float b07 = a20 * a32 - a22 * a30; + float b08 = a20 * a33 - a23 * a30; + float b09 = a21 * a32 - a22 * a31; + float b10 = a21 * a33 - a23 * a31; + float b11 = a22 * a33 - a23 * a32; + + // Calculate the invert determinant (inlined to avoid double-caching) + float invDet = 1.0f / ( b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06 ); + + Matrix matViewProjInv = { ( a11 * b11 - a12 * b10 + a13 * b09 ) * invDet, ( -a01 * b11 + a02 * b10 - a03 * b09 ) * invDet, + ( a31 * b05 - a32 * b04 + a33 * b03 ) * invDet, ( -a21 * b05 + a22 * b04 - a23 * b03 ) * invDet, + ( -a10 * b11 + a12 * b08 - a13 * b07 ) * invDet, ( a00 * b11 - a02 * b08 + a03 * b07 ) * invDet, + ( -a30 * b05 + a32 * b02 - a33 * b01 ) * invDet, ( a20 * b05 - a22 * b02 + a23 * b01 ) * invDet, + ( a10 * b10 - a11 * b08 + a13 * b06 ) * invDet, ( -a00 * b10 + a01 * b08 - a03 * b06 ) * invDet, + ( a30 * b04 - a31 * b02 + a33 * b00 ) * invDet, ( -a20 * b04 + a21 * b02 - a23 * b00 ) * invDet, + ( -a10 * b09 + a11 * b07 - a12 * b06 ) * invDet, ( a00 * b09 - a01 * b07 + a02 * b06 ) * invDet, + ( -a30 * b03 + a31 * b01 - a32 * b00 ) * invDet, ( a20 * b03 - a21 * b01 + a22 * b00 ) * invDet }; + + // Create quaternion from source point + Quaternion quat = { source.x, source.y, source.z, 1.0f }; + + // Multiply quat point by unprojecte 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 vector3_to_float_v( Vector3 v ) +{ + float3 buffer = { 0 }; + + buffer.v[ 0 ] = v.x; + buffer.v[ 1 ] = v.y; + buffer.v[ 2 ] = v.z; + + return buffer; +} + +// Invert the given vector +RMAPI Vector3 vector3_invert( Vector3 v ) +{ + Vector3 result = { 1.0f / v.x, 1.0f / v.y, 1.0f / v.z }; + + return result; +} + +// Clamp the components of the vector between +// min and max values specified by the given vectors +RMAPI Vector3 vector3_clamp( Vector3 v, Vector3 min, Vector3 max ) +{ + Vector3 result = { 0 }; + + result.x = fminf( max.x, fmaxf( min.x, v.x ) ); + result.y = fminf( max.y, fmaxf( min.y, v.y ) ); + result.z = fminf( max.z, fmaxf( min.z, v.z ) ); + + return result; +} + +// Clamp the magnitude of the vector between two values +RMAPI Vector3 vector3_clamp_value( Vector3 v, f32 min, f32 max ) +{ + Vector3 result = v; + + float length = ( v.x * v.x ) + ( v.y * v.y ) + ( v.z * v.z ); + if ( length > 0.0f ) + { + length = sqrtf( length ); + + if ( length < min ) + { + float scale = min / length; + result.x = v.x * scale; + result.y = v.y * scale; + result.z = v.z * scale; + } + else if ( length > max ) + { + float scale = max / length; + result.x = v.x * scale; + result.y = v.y * scale; + result.z = v.z * scale; + } + } + + return result; +} + +// Check whether two given vectors are almost equal +RMAPI int vector3_equals( Vector3 p, Vector3 q ) +{ +#if ! defined( EPSILON ) +#define EPSILON 0.000001f +#endif + + int result = ( ( fabsf( p.x - q.x ) ) <= ( EPSILON * fmaxf( 1.0f, fmaxf( fabsf( p.x ), fabsf( q.x ) ) ) ) ) + && ( ( fabsf( p.y - q.y ) ) <= ( EPSILON * fmaxf( 1.0f, fmaxf( fabsf( p.y ), fabsf( q.y ) ) ) ) ) + && ( ( fabsf( p.z - q.z ) ) <= ( EPSILON * fmaxf( 1.0f, fmaxf( fabsf( p.z ), fabsf( q.z ) ) ) ) ); + + return result; +} + +// Compute the direction of a refracted ray +// v: normalized direction of the incoming ray +// n: normalized normal vector of the interface of two optical media +// r: ratio of the refractive index of the medium from where the ray comes +// to the refractive index of the medium on the other side of the surface +RMAPI Vector3 vector3_refract( Vector3 v, Vector3 n, f32 r ) +{ + Vector3 result = { 0 }; + + float dot = v.x * n.x + v.y * n.y + v.z * n.z; + float d = 1.0f - r * r * ( 1.0f - dot * dot ); + + if ( d >= 0.0f ) + { + d = sqrtf( d ); + v.x = r * v.x - ( r * dot + d ) * n.x; + v.y = r * v.y - ( r * dot + d ) * n.y; + v.z = r * v.z - ( r * dot + d ) * n.z; + + result = v; + } + + return result; +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition - Matrix math +//---------------------------------------------------------------------------------- + +// Compute matrix determinant +RMAPI float matrix_determinant( 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 matrix_trace( Matrix mat ) +{ + float result = ( mat.m0 + mat.m5 + mat.m10 + mat.m15 ); + + return result; +} + +// Transposes provided matrix +RMAPI Matrix matrix_transpose( 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 matrix_invert( Matrix mat ) +{ + Matrix result = { 0 }; + + // Cache the matrix values (speed optimization) + float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; + float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7; + float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; + float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15; + + float b00 = a00 * a11 - a01 * a10; + float b01 = a00 * a12 - a02 * a10; + float b02 = a00 * a13 - a03 * a10; + float b03 = a01 * a12 - a02 * a11; + float b04 = a01 * a13 - a03 * a11; + float b05 = a02 * a13 - a03 * a12; + float b06 = a20 * a31 - a21 * a30; + float b07 = a20 * a32 - a22 * a30; + float b08 = a20 * a33 - a23 * a30; + float b09 = a21 * a32 - a22 * a31; + float b10 = a21 * a33 - a23 * a31; + float b11 = a22 * a33 - a23 * a32; + + // Calculate the invert determinant (inlined to avoid double-caching) + float invDet = 1.0f / ( b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06 ); + + result.m0 = ( a11 * b11 - a12 * b10 + a13 * b09 ) * invDet; + result.m1 = ( -a01 * b11 + a02 * b10 - a03 * b09 ) * invDet; + result.m2 = ( a31 * b05 - a32 * b04 + a33 * b03 ) * invDet; + result.m3 = ( -a21 * b05 + a22 * b04 - a23 * b03 ) * invDet; + result.m4 = ( -a10 * b11 + a12 * b08 - a13 * b07 ) * invDet; + result.m5 = ( a00 * b11 - a02 * b08 + a03 * b07 ) * invDet; + result.m6 = ( -a30 * b05 + a32 * b02 - a33 * b01 ) * invDet; + result.m7 = ( a20 * b05 - a22 * b02 + a23 * b01 ) * invDet; + result.m8 = ( a10 * b10 - a11 * b08 + a13 * b06 ) * invDet; + result.m9 = ( -a00 * b10 + a01 * b08 - a03 * b06 ) * invDet; + result.m10 = ( a30 * b04 - a31 * b02 + a33 * b00 ) * invDet; + result.m11 = ( -a20 * b04 + a21 * b02 - a23 * b00 ) * invDet; + result.m12 = ( -a10 * b09 + a11 * b07 - a12 * b06 ) * invDet; + result.m13 = ( a00 * b09 - a01 * b07 + a02 * b06 ) * invDet; + result.m14 = ( -a30 * b03 + a31 * b01 - a32 * b00 ) * invDet; + result.m15 = ( a20 * b03 - a21 * b01 + a22 * b00 ) * invDet; + + return result; +} + +// Get identity matrix +RMAPI Matrix matrix_identity( 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 matrix_add( 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 matrix_subtract( 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 matrix_multiply( 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 matrix_translate( f32 x, f32 y, f32 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 matrix_rotate( Vector3 axis, f32 angle ) +{ + Matrix result = { 0 }; + + float x = axis.x, y = axis.y, z = axis.z; + + float lengthSquared = x * x + y * y + z * z; + + if ( ( lengthSquared != 1.0f ) && ( lengthSquared != 0.0f ) ) + { + float ilength = 1.0f / sqrtf( lengthSquared ); + x *= ilength; + y *= ilength; + z *= ilength; + } + + float sinres = sinf( angle ); + float cosres = cosf( angle ); + float t = 1.0f - cosres; + + result.m0 = x * x * t + cosres; + result.m1 = y * x * t + z * sinres; + result.m2 = z * x * t - y * sinres; + result.m3 = 0.0f; + + result.m4 = x * y * t - z * sinres; + result.m5 = y * y * t + cosres; + result.m6 = z * y * t + x * sinres; + result.m7 = 0.0f; + + result.m8 = x * z * t + y * sinres; + result.m9 = y * z * t - x * sinres; + result.m10 = z * z * t + cosres; + result.m11 = 0.0f; + + result.m12 = 0.0f; + result.m13 = 0.0f; + result.m14 = 0.0f; + result.m15 = 1.0f; + + return result; +} + +// Get x-rotation matrix +// NOTE: Angle must be provided in radians +RMAPI Matrix matrix_rotate_x( f32 angle ) +{ + Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() + + float cosres = cosf( angle ); + float sinres = sinf( angle ); + + result.m5 = cosres; + result.m6 = sinres; + result.m9 = -sinres; + result.m10 = cosres; + + return result; +} + +// Get y-rotation matrix +// NOTE: Angle must be provided in radians +RMAPI Matrix matrix_rotate_y( f32 angle ) +{ + Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() + + float cosres = cosf( angle ); + float sinres = sinf( angle ); + + result.m0 = cosres; + result.m2 = -sinres; + result.m8 = sinres; + result.m10 = cosres; + + return result; +} + +// Get z-rotation matrix +// NOTE: Angle must be provided in radians +RMAPI Matrix matrix_rotate_z( f32 angle ) +{ + Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() + + float cosres = cosf( angle ); + float sinres = sinf( angle ); + + result.m0 = cosres; + result.m1 = sinres; + result.m4 = -sinres; + result.m5 = cosres; + + return result; +} + +// Get xyz-rotation matrix +// NOTE: Angle must be provided in radians +RMAPI Matrix matrix_rotate_xyz( Vector3 angle ) +{ + Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity() + + float cosz = cosf( -angle.z ); + float sinz = sinf( -angle.z ); + float cosy = cosf( -angle.y ); + float siny = sinf( -angle.y ); + float cosx = cosf( -angle.x ); + float sinx = sinf( -angle.x ); + + result.m0 = cosz * cosy; + result.m1 = ( cosz * siny * sinx ) - ( sinz * cosx ); + result.m2 = ( cosz * siny * cosx ) + ( sinz * sinx ); + + result.m4 = sinz * cosy; + result.m5 = ( sinz * siny * sinx ) + ( cosz * cosx ); + result.m6 = ( sinz * siny * cosx ) - ( cosz * sinx ); + + result.m8 = -siny; + result.m9 = cosy * sinx; + result.m10 = cosy * cosx; + + return result; +} + +// Get zyx-rotation matrix +// NOTE: Angle must be provided in radians +RMAPI Matrix matrix_rotate_zyx( Vector3 angle ) +{ + Matrix result = { 0 }; + + float cz = cosf( angle.z ); + float sz = sinf( angle.z ); + float cy = cosf( angle.y ); + float sy = sinf( angle.y ); + float cx = cosf( angle.x ); + float sx = sinf( angle.x ); + + result.m0 = cz * cy; + result.m4 = cz * sy * sx - cx * sz; + result.m8 = sz * sx + cz * cx * sy; + result.m12 = 0; + + result.m1 = cy * sz; + result.m5 = cz * cx + sz * sy * sx; + result.m9 = cx * sz * sy - cz * sx; + result.m13 = 0; + + result.m2 = -sy; + result.m6 = cy * sx; + result.m10 = cy * cx; + result.m14 = 0; + + result.m3 = 0; + result.m7 = 0; + result.m11 = 0; + result.m15 = 1; + + return result; +} + +// Get scaling matrix +RMAPI Matrix matrix_scale( f32 x, f32 y, f32 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 matrix_frustum( 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: Fovy angle must be provided in radians +RMAPI Matrix matrix_perspective( double fovY, double aspect, double nearPlane, double farPlane ) +{ + Matrix result = { 0 }; + + double top = nearPlane * tan( fovY * 0.5 ); + double bottom = -top; + double right = top * aspect; + double left = -right; + + // MatrixFrustum(-right, right, -top, top, near, far); + float rl = ( float )( right - left ); + float tb = ( float )( top - bottom ); + float fn = ( float )( farPlane - nearPlane ); + + result.m0 = ( ( float )nearPlane * 2.0f ) / rl; + result.m5 = ( ( float )nearPlane * 2.0f ) / tb; + result.m8 = ( ( float )right + ( float )left ) / rl; + result.m9 = ( ( float )top + ( float )bottom ) / tb; + result.m10 = -( ( float )farPlane + ( float )nearPlane ) / fn; + result.m11 = -1.0f; + result.m14 = -( ( float )farPlane * ( float )nearPlane * 2.0f ) / fn; + + return result; +} + +// Get orthographic projection matrix +RMAPI Matrix matrix_ortho( double left, double right, double bottom, double top, double nearPlane, double farPlane ) +{ + Matrix result = { 0 }; + + float rl = ( float )( right - left ); + float tb = ( float )( top - bottom ); + float fn = ( float )( farPlane - nearPlane ); + + result.m0 = 2.0f / rl; + result.m1 = 0.0f; + result.m2 = 0.0f; + result.m3 = 0.0f; + result.m4 = 0.0f; + result.m5 = 2.0f / tb; + result.m6 = 0.0f; + result.m7 = 0.0f; + result.m8 = 0.0f; + result.m9 = 0.0f; + result.m10 = -2.0f / fn; + result.m11 = 0.0f; + result.m12 = -( ( float )left + ( float )right ) / rl; + result.m13 = -( ( float )top + ( float )bottom ) / tb; + result.m14 = -( ( float )farPlane + ( float )nearPlane ) / fn; + result.m15 = 1.0f; + + return result; +} + +// Get camera look-at matrix (view matrix) +RMAPI Matrix matrix_look_at( 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 matrix_to_float_v( 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 quaternion_add( 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 quaternion_add_value( Quaternion q, f32 add ) +{ + Quaternion result = { q.x + add, q.y + add, q.z + add, q.w + add }; + + return result; +} + +// Subtract two quaternions +RMAPI Quaternion quaternion_subtract( 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 quaternion_subtract_value( Quaternion q, f32 sub ) +{ + Quaternion result = { q.x - sub, q.y - sub, q.z - sub, q.w - sub }; + + return result; +} + +// Get identity quaternion +RMAPI Quaternion quaternion_identity( void ) +{ + Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f }; + + return result; +} + +// Computes the length of a quaternion +RMAPI float quaternion_length( 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 quaternion_normalize( 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 quaternion_invert( Quaternion q ) +{ + Quaternion result = q; + + float lengthSq = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w; + + if ( lengthSq != 0.0f ) + { + float invLength = 1.0f / lengthSq; + + result.x *= -invLength; + result.y *= -invLength; + result.z *= -invLength; + result.w *= invLength; + } + + return result; +} + +// Calculate two quaternion multiplication +RMAPI Quaternion quaternion_multiply( 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 quaternion_scale( Quaternion q, f32 mul ) +{ + Quaternion result = { 0 }; + + result.x = q.x * mul; + result.y = q.y * mul; + result.z = q.z * mul; + result.w = q.w * mul; + + return result; +} + +// Divide two quaternions +RMAPI Quaternion quaternion_divide( 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 quaternion_lerp( Quaternion q1, Quaternion q2, f32 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 quaternion_nlerp( Quaternion q1, Quaternion q2, f32 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 quaternion_slerp( Quaternion q1, Quaternion q2, f32 amount ) +{ + Quaternion result = { 0 }; + +#if ! defined( EPSILON ) +#define EPSILON 0.000001f +#endif + + float cosHalfTheta = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; + + if ( cosHalfTheta < 0 ) + { + q2.x = -q2.x; + q2.y = -q2.y; + q2.z = -q2.z; + q2.w = -q2.w; + cosHalfTheta = -cosHalfTheta; + } + + if ( fabsf( cosHalfTheta ) >= 1.0f ) + result = q1; + else if ( cosHalfTheta > 0.95f ) + result = QuaternionNlerp( q1, q2, amount ); + else + { + float halfTheta = acosf( cosHalfTheta ); + float sinHalfTheta = sqrtf( 1.0f - cosHalfTheta * cosHalfTheta ); + + if ( fabsf( sinHalfTheta ) < EPSILON ) + { + result.x = ( q1.x * 0.5f + q2.x * 0.5f ); + result.y = ( q1.y * 0.5f + q2.y * 0.5f ); + result.z = ( q1.z * 0.5f + q2.z * 0.5f ); + result.w = ( q1.w * 0.5f + q2.w * 0.5f ); + } + else + { + float ratioA = sinf( ( 1 - amount ) * halfTheta ) / sinHalfTheta; + float ratioB = sinf( amount * halfTheta ) / sinHalfTheta; + + result.x = ( q1.x * ratioA + q2.x * ratioB ); + result.y = ( q1.y * ratioA + q2.y * ratioB ); + result.z = ( q1.z * ratioA + q2.z * ratioB ); + result.w = ( q1.w * ratioA + q2.w * ratioB ); + } + } + + return result; +} + +// Calculate quaternion based on the rotation from one vector to another +RMAPI Quaternion quaternion_from_vector3_to_vector3( 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 quaternion_from_matrix( Matrix mat ) +{ + Quaternion result = { 0 }; + + float fourWSquaredMinus1 = mat.m0 + mat.m5 + mat.m10; + float fourXSquaredMinus1 = mat.m0 - mat.m5 - mat.m10; + float fourYSquaredMinus1 = mat.m5 - mat.m0 - mat.m10; + float fourZSquaredMinus1 = mat.m10 - mat.m0 - mat.m5; + + int biggestIndex = 0; + float fourBiggestSquaredMinus1 = fourWSquaredMinus1; + if ( fourXSquaredMinus1 > fourBiggestSquaredMinus1 ) + { + fourBiggestSquaredMinus1 = fourXSquaredMinus1; + biggestIndex = 1; + } + + if ( fourYSquaredMinus1 > fourBiggestSquaredMinus1 ) + { + fourBiggestSquaredMinus1 = fourYSquaredMinus1; + biggestIndex = 2; + } + + if ( fourZSquaredMinus1 > fourBiggestSquaredMinus1 ) + { + fourBiggestSquaredMinus1 = fourZSquaredMinus1; + biggestIndex = 3; + } + + float biggestVal = sqrtf( fourBiggestSquaredMinus1 + 1.0f ) * 0.5f; + float mult = 0.25f / biggestVal; + + switch ( biggestIndex ) + { + case 0 : + result.w = biggestVal; + result.x = ( mat.m6 - mat.m9 ) * mult; + result.y = ( mat.m8 - mat.m2 ) * mult; + result.z = ( mat.m1 - mat.m4 ) * mult; + break; + case 1 : + result.x = biggestVal; + result.w = ( mat.m6 - mat.m9 ) * mult; + result.y = ( mat.m1 + mat.m4 ) * mult; + result.z = ( mat.m8 + mat.m2 ) * mult; + break; + case 2 : + result.y = biggestVal; + result.w = ( mat.m8 - mat.m2 ) * mult; + result.x = ( mat.m1 + mat.m4 ) * mult; + result.z = ( mat.m6 + mat.m9 ) * mult; + break; + case 3 : + result.z = biggestVal; + result.w = ( mat.m1 - mat.m4 ) * mult; + result.x = ( mat.m8 + mat.m2 ) * mult; + result.y = ( mat.m6 + mat.m9 ) * mult; + break; + } + + return result; +} + +// Get a matrix for a given quaternion +RMAPI Matrix quaternion_to_matrix( 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 quaternion_from_axis_angle( Vector3 axis, f32 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 quaternion_to_axis_angle( Quaternion q, Vector3* outAxis, f32* outAngle ) +{ + if ( fabsf( q.w ) > 1.0f ) + { + // QuaternionNormalize(q); + float length = sqrtf( q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w ); + if ( length == 0.0f ) + length = 1.0f; + float ilength = 1.0f / length; + + q.x = q.x * ilength; + q.y = q.y * ilength; + q.z = q.z * ilength; + q.w = q.w * ilength; + } + + Vector3 resAxis = { 0.0f, 0.0f, 0.0f }; + float resAngle = 2.0f * acosf( q.w ); + float den = sqrtf( 1.0f - q.w * q.w ); + + if ( den > EPSILON ) + { + resAxis.x = q.x / den; + resAxis.y = q.y / den; + resAxis.z = q.z / den; + } + else + { + // This occurs when the angle is zero. + // Not a problem: 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 quaternion_from_euler( f32 pitch, f32 yaw, f32 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 quaternion_to_euler( 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 quaternion_transform( Quaternion q, Matrix mat ) +{ + Quaternion result = { 0 }; + + result.x = mat.m0 * q.x + mat.m4 * q.y + mat.m8 * q.z + mat.m12 * q.w; + result.y = mat.m1 * q.x + mat.m5 * q.y + mat.m9 * q.z + mat.m13 * q.w; + result.z = mat.m2 * q.x + mat.m6 * q.y + mat.m10 * q.z + mat.m14 * q.w; + result.w = mat.m3 * q.x + mat.m7 * q.y + mat.m11 * q.z + mat.m15 * q.w; + + return result; +} + +// Check whether two given quaternions are almost equal +RMAPI int quaternion_equals( Quaternion p, Quaternion q ) +{ +#if ! defined( EPSILON ) +#define EPSILON 0.000001f +#endif + + int result = ( ( ( fabsf( p.x - q.x ) ) <= ( EPSILON * fmaxf( 1.0f, fmaxf( fabsf( p.x ), fabsf( q.x ) ) ) ) ) + && ( ( fabsf( p.y - q.y ) ) <= ( EPSILON * fmaxf( 1.0f, fmaxf( fabsf( p.y ), fabsf( q.y ) ) ) ) ) + && ( ( fabsf( p.z - q.z ) ) <= ( EPSILON * fmaxf( 1.0f, fmaxf( fabsf( p.z ), fabsf( q.z ) ) ) ) ) + && ( ( fabsf( p.w - q.w ) ) <= ( EPSILON * fmaxf( 1.0f, fmaxf( fabsf( p.w ), fabsf( q.w ) ) ) ) ) ) + || ( ( ( fabsf( p.x + q.x ) ) <= ( EPSILON * fmaxf( 1.0f, fmaxf( fabsf( p.x ), fabsf( q.x ) ) ) ) ) + && ( ( fabsf( p.y + q.y ) ) <= ( EPSILON * fmaxf( 1.0f, fmaxf( fabsf( p.y ), fabsf( q.y ) ) ) ) ) + && ( ( fabsf( p.z + q.z ) ) <= ( EPSILON * fmaxf( 1.0f, fmaxf( fabsf( p.z ), fabsf( q.z ) ) ) ) ) + && ( ( fabsf( p.w + q.w ) ) <= ( EPSILON * fmaxf( 1.0f, fmaxf( fabsf( p.w ), fabsf( q.w ) ) ) ) ) ); + + return result; +} + +#endif +// RAYMATH_H diff --git a/project/auxillary/vis_ast/dependencies/raylib/include/rcamera.h b/project/auxillary/vis_ast/dependencies/raylib/include/rcamera.h new file mode 100644 index 0000000..5b8f0f0 --- /dev/null +++ b/project/auxillary/vis_ast/dependencies/raylib/include/rcamera.h @@ -0,0 +1,595 @@ +/******************************************************************************************* + * + * rcamera - Basic camera system with support for multiple camera modes + * + * CONFIGURATION: + * #define RCAMERA_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 RCAMERA_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 + * Christoph Wagner: Complete redesign, using raymath (2022) + * Marc Palau: Initial implementation (2014) + * + * + * LICENSE: zlib/libpng + * + * Copyright (c) 2022-2023 Christoph Wagner (@Crydsch) & 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 RL_RCAMERA_H + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +// Function specifiers definition + +// 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 ) +#if defined( __TINYC__ ) +#define RL___declspec( x ) __attribute__( ( x ) ) +#endif +#elif defined( USE_LIBTYPE_SHARED ) +#endif +#endif + +#ifndef RLAPI +#endif + +#if defined( RCAMERA_STANDALONE ) +#define RL_CAMERA_CULL_DISTANCE_NEAR 0.01 +#define RL_CAMERA_CULL_DISTANCE_FAR 1000.0 +#else +#define RL_CAMERA_CULL_DISTANCE_NEAR RL_CULL_DISTANCE_NEAR +#define RL_CAMERA_CULL_DISTANCE_FAR RL_CULL_DISTANCE_FAR +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +// NOTE: Below types are required for standalone usage +//---------------------------------------------------------------------------------- +#if defined( RCAMERA_STANDALONE ) +// Vector2, 2 components +typedef struct Vector2 +{ + f32 x; // Vector x component + f32 y; // Vector y component + +} Vector2; + +// Vector3, 3 components +typedef struct Vector3 +{ + f32 x; // Vector x component + f32 y; // Vector y component + f32 z; // Vector z component + +} Vector3; + +// Matrix, 4x4 components, column major, OpenGL style, right-handed +typedef struct Matrix +{ + f32 m0, m4, m8, m12; // Matrix first row (4 components) + f32 m1, m5, m9, m13; // Matrix second row (4 components) + f32 m2, m6, m10, m14; // Matrix third row (4 components) + f32 m3, m7, m11, m15; // Matrix fourth row (4 components) + +} Matrix; + +// 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) + f32 fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic + s32 projection; // Camera projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC + +} Camera3D; + +typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D + +// Camera projection +typedef enum +{ + Camera_Perspective = 0, // Perspective projection + Camera_Orthographic // orthographic projection + +} CameraProjection; + +// Camera system modes +typedef enum +{ + Camera_Custom = 0, // Camera custom, controlled by user (UpdateCamera() does nothing) + Camera_Free, // Camera free mode + Camera_Orbital, // Camera orbital, around target, zoom supported + Camera_First_Person, // Camera first person + Camera_Third_Person // camera third person + +} CameraMode; +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- + +#if defined( __cplusplus ) +namespace raylib +{ + extern "C" + { +// Prevents name mangling of functions +#endif + + RLAPI Vector3 get_camera_forward( Camera* camera ); + RLAPI Vector3 get_camera_up( Camera* camera ); + RLAPI Vector3 get_camera_right( Camera* camera ); + + // Camera movement + RLAPI void camera_move_forward( Camera* camera, f32 distance, bool moveInWorldPlane ); + RLAPI void camera_move_up( Camera* camera, f32 distance ); + RLAPI void camera_move_right( Camera* camera, f32 distance, bool moveInWorldPlane ); + RLAPI void camera_move_to_target( Camera* camera, f32 delta ); + + // Camera rotation + RLAPI void camera_yaw( Camera* camera, f32 angle, bool rotateAroundTarget ); + RLAPI void camera_pitch( Camera* camera, f32 angle, bool lockView, bool rotateAroundTarget, bool rotateUp ); + RLAPI void camera_roll( Camera* camera, f32 angle ); + + RLAPI Matrix get_camera_view_matrix( Camera* camera ); + RLAPI Matrix get_camera_projection_matrix( Camera* camera, f32 aspect ); + +#if defined( __cplusplus ) + } +} +#endif + +#endif +// RCAMERA_H + + +/*********************************************************************************** + * + * CAMERA IMPLEMENTATION + * + ************************************************************************************/ + +#if defined( RCAMERA_IMPLEMENTATION ) + +#include "raymath.h" +// Required for vector maths: +// Vector3Add() +// Vector3Subtract() +// Vector3Scale() +// Vector3Normalize() +// Vector3Distance() +// Vector3CrossProduct() +// Vector3RotateByAxisAngle() +// Vector3Angle() +// Vector3Negate() +// MatrixLookAt() +// MatrixPerspective() +// MatrixOrtho() +// MatrixIdentity() + +// raylib required functionality: +// GetMouseDelta() +// GetMouseWheelMove() +// IsKeyDown() +// IsKeyPressed() +// GetFrameTime() + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#define RL_CAMERA_MOVE_SPEED 0.09f +#define RL_CAMERA_ROTATION_SPEED 0.03f +#define RL_CAMERA_PAN_SPEED 0.2f + +// Camera mouse movement sensitivity +#define RL_CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f // TODO: it should be independant of framerate +#define RL_CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f + +#define RL_CAMERA_ORBITAL_SPEED 0.5f // Radians per second + + +#define RL_CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 8.0f +#define RL_CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f +#define RL_CAMERA_FIRST_PERSON_WAVING_DIVIDER 200.0f + +// PLAYER (used by camera) +#define RL_PLAYER_MOVEMENT_SENSITIVITY 20.0f + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Module specific Functions Declaration +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Module Functions Definition +//---------------------------------------------------------------------------------- +// Returns the cameras forward vector (normalized) +Vector3 get_camera_forward( Camera* camera ) +{ + return Vector3Normalize( Vector3Subtract( camera->target, camera->position ) ); +} + +// Returns the cameras up vector (normalized) +// Note: The up vector might not be perpendicular to the forward vector +Vector3 get_camera_up( Camera* camera ) +{ + return Vector3Normalize( camera->up ); +} + +// Returns the cameras right vector (normalized) +Vector3 get_camera_right( Camera* camera ) +{ + Vector3 forward = GetCameraForward( camera ); + Vector3 up = GetCameraUp( camera ); + + return Vector3CrossProduct( forward, up ); +} + +// Moves the camera in its forward direction +void camera_move_forward( Camera* camera, f32 distance, bool moveInWorldPlane ) +{ + Vector3 forward = GetCameraForward( camera ); + + if ( moveInWorldPlane ) + { + // Project vector onto world plane + forward.y = 0; + forward = Vector3Normalize( forward ); + } + + // Scale by distance + forward = Vector3Scale( forward, distance ); + + // Move position and target + camera->position = Vector3Add( camera->position, forward ); + camera->target = Vector3Add( camera->target, forward ); +} + +// Moves the camera in its up direction +void camera_move_up( Camera* camera, f32 distance ) +{ + Vector3 up = GetCameraUp( camera ); + + // Scale by distance + up = Vector3Scale( up, distance ); + + // Move position and target + camera->position = Vector3Add( camera->position, up ); + camera->target = Vector3Add( camera->target, up ); +} + +// Moves the camera target in its current right direction +void camera_move_right( Camera* camera, f32 distance, bool moveInWorldPlane ) +{ + Vector3 right = GetCameraRight( camera ); + + if ( moveInWorldPlane ) + { + // Project vector onto world plane + right.y = 0; + right = Vector3Normalize( right ); + } + + // Scale by distance + right = Vector3Scale( right, distance ); + + // Move position and target + camera->position = Vector3Add( camera->position, right ); + camera->target = Vector3Add( camera->target, right ); +} + +// Moves the camera position closer/farther to/from the camera target +void camera_move_to_target( Camera* camera, f32 delta ) +{ + float distance = Vector3Distance( camera->position, camera->target ); + + // Apply delta + distance += delta; + + // Distance must be greater than 0 + if ( distance <= 0 ) + distance = 0.001f; + + // Set new distance by moving the position along the forward vector + Vector3 forward = GetCameraForward( camera ); + camera->position = Vector3Add( camera->target, Vector3Scale( forward, -distance ) ); +} + +// Rotates the camera around its up vector +// Yaw is "looking left and right" +// If rotateAroundTarget is false, the camera rotates around its position +// Note: angle must be provided in radians +void camera_yaw( Camera* camera, f32 angle, bool rotateAroundTarget ) +{ + Vector3 up = GetCameraUp( camera ); + + // View vector + Vector3 targetPosition = Vector3Subtract( camera->target, camera->position ); + + // Rotate view vector around up axis + targetPosition = Vector3RotateByAxisAngle( targetPosition, up, angle ); + + if ( rotateAroundTarget ) + { + // Move position relative to target + camera->position = Vector3Subtract( camera->target, targetPosition ); + } + else // rotate around camera.position + { + // Move target relative to position + camera->target = Vector3Add( camera->position, targetPosition ); + } +} + +// Rotates the camera around its right vector, pitch is "looking up and down" +// - lockView prevents camera overrotation (aka "somersaults") +// - rotateAroundTarget defines if rotation is around target or around its position +// - rotateUp rotates the up direction as well (typically only usefull in CAMERA_FREE) +// NOTE: angle must be provided in radians +void camera_pitch( Camera* camera, f32 angle, bool lockView, bool rotateAroundTarget, bool rotateUp ) +{ + Vector3 up = GetCameraUp( camera ); + + // View vector + Vector3 targetPosition = Vector3Subtract( camera->target, camera->position ); + + if ( lockView ) + { + // In these camera modes we clamp the Pitch angle + // to allow only viewing straight up or down. + + // Clamp view up + float maxAngleUp = Vector3Angle( up, targetPosition ); + maxAngleUp -= 0.001f; // avoid numerical errors + if ( angle > maxAngleUp ) + angle = maxAngleUp; + + // Clamp view down + float maxAngleDown = Vector3Angle( Vector3Negate( up ), targetPosition ); + maxAngleDown *= -1.0f; // downwards angle is negative + maxAngleDown += 0.001f; // avoid numerical errors + if ( angle < maxAngleDown ) + angle = maxAngleDown; + } + + // Rotation axis + Vector3 right = GetCameraRight( camera ); + + // Rotate view vector around right axis + targetPosition = Vector3RotateByAxisAngle( targetPosition, right, angle ); + + if ( rotateAroundTarget ) + { + // Move position relative to target + camera->position = Vector3Subtract( camera->target, targetPosition ); + } + else // rotate around camera.position + { + // Move target relative to position + camera->target = Vector3Add( camera->position, targetPosition ); + } + + if ( rotateUp ) + { + // Rotate up direction around right axis + camera->up = Vector3RotateByAxisAngle( camera->up, right, angle ); + } +} + +// Rotates the camera around its forward vector +// Roll is "turning your head sideways to the left or right" +// Note: angle must be provided in radians +void camera_roll( Camera* camera, f32 angle ) +{ + Vector3 forward = GetCameraForward( camera ); + + // Rotate up direction around forward axis + camera->up = Vector3RotateByAxisAngle( camera->up, forward, angle ); +} + +// Returns the camera view matrix +Matrix get_camera_view_matrix( Camera* camera ) +{ + return MatrixLookAt( camera->position, camera->target, camera->up ); +} + +// Returns the camera projection matrix +Matrix get_camera_projection_matrix( Camera* camera, f32 aspect ) +{ + if ( camera->projection == CAMERA_PERSPECTIVE ) + { + return MatrixPerspective( camera->fovy * DEG2RAD, aspect, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR ); + } + else if ( camera->projection == CAMERA_ORTHOGRAPHIC ) + { + double top = camera->fovy / 2.0; + double right = top * aspect; + + return MatrixOrtho( -right, right, -top, top, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR ); + } + + return MatrixIdentity(); +} + +#if ! defined( RCAMERA_STANDALONE ) +// Update camera position for selected mode +// Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM +void update_camera( Camera* camera, s32 mode ) +{ + Vector2 mousePositionDelta = GetMouseDelta(); + + bool moveInWorldPlane = ( ( mode == CAMERA_FIRST_PERSON ) || ( mode == CAMERA_THIRD_PERSON ) ); + bool rotateAroundTarget = ( ( mode == CAMERA_THIRD_PERSON ) || ( mode == CAMERA_ORBITAL ) ); + bool lockView = ( ( mode == CAMERA_FIRST_PERSON ) || ( mode == CAMERA_THIRD_PERSON ) || ( mode == CAMERA_ORBITAL ) ); + bool rotateUp = false; + + if ( mode == CAMERA_ORBITAL ) + { + // Orbital can just orbit + Matrix rotation = MatrixRotate( GetCameraUp( camera ), CAMERA_ORBITAL_SPEED * GetFrameTime() ); + Vector3 view = Vector3Subtract( camera->position, camera->target ); + view = Vector3Transform( view, rotation ); + camera->position = Vector3Add( camera->target, view ); + } + else + { + // Camera rotation + if ( IsKeyDown( KEY_DOWN ) ) + CameraPitch( camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp ); + if ( IsKeyDown( KEY_UP ) ) + CameraPitch( camera, CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp ); + if ( IsKeyDown( KEY_RIGHT ) ) + CameraYaw( camera, -CAMERA_ROTATION_SPEED, rotateAroundTarget ); + if ( IsKeyDown( KEY_LEFT ) ) + CameraYaw( camera, CAMERA_ROTATION_SPEED, rotateAroundTarget ); + if ( IsKeyDown( KEY_Q ) ) + CameraRoll( camera, -CAMERA_ROTATION_SPEED ); + if ( IsKeyDown( KEY_E ) ) + CameraRoll( camera, CAMERA_ROTATION_SPEED ); + + // Camera movement + if ( ! IsGamepadAvailable( 0 ) ) + { + // Camera pan (for CAMERA_FREE) + if ( ( mode == CAMERA_FREE ) && ( IsMouseButtonDown( MOUSE_BUTTON_MIDDLE ) ) ) + { + const Vector2 mouseDelta = GetMouseDelta(); + if ( mouseDelta.x > 0.0f ) + CameraMoveRight( camera, CAMERA_PAN_SPEED, moveInWorldPlane ); + if ( mouseDelta.x < 0.0f ) + CameraMoveRight( camera, -CAMERA_PAN_SPEED, moveInWorldPlane ); + if ( mouseDelta.y > 0.0f ) + CameraMoveUp( camera, -CAMERA_PAN_SPEED ); + if ( mouseDelta.y < 0.0f ) + CameraMoveUp( camera, CAMERA_PAN_SPEED ); + } + else + { + // Mouse support + CameraYaw( camera, -mousePositionDelta.x * CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget ); + CameraPitch( camera, -mousePositionDelta.y * CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp ); + } + + // Keyboard support + if ( IsKeyDown( KEY_W ) ) + CameraMoveForward( camera, CAMERA_MOVE_SPEED, moveInWorldPlane ); + if ( IsKeyDown( KEY_A ) ) + CameraMoveRight( camera, -CAMERA_MOVE_SPEED, moveInWorldPlane ); + if ( IsKeyDown( KEY_S ) ) + CameraMoveForward( camera, -CAMERA_MOVE_SPEED, moveInWorldPlane ); + if ( IsKeyDown( KEY_D ) ) + CameraMoveRight( camera, CAMERA_MOVE_SPEED, moveInWorldPlane ); + } + else + { + // Gamepad controller support + CameraYaw( camera, -( GetGamepadAxisMovement( 0, GAMEPAD_AXIS_RIGHT_X ) * 2 ) * CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget ); + CameraPitch( + camera, + -( GetGamepadAxisMovement( 0, GAMEPAD_AXIS_RIGHT_Y ) * 2 ) * CAMERA_MOUSE_MOVE_SENSITIVITY, + lockView, + rotateAroundTarget, + rotateUp + ); + + if ( GetGamepadAxisMovement( 0, GAMEPAD_AXIS_LEFT_Y ) <= -0.25f ) + CameraMoveForward( camera, CAMERA_MOVE_SPEED, moveInWorldPlane ); + if ( GetGamepadAxisMovement( 0, GAMEPAD_AXIS_LEFT_X ) <= -0.25f ) + CameraMoveRight( camera, -CAMERA_MOVE_SPEED, moveInWorldPlane ); + if ( GetGamepadAxisMovement( 0, GAMEPAD_AXIS_LEFT_Y ) >= 0.25f ) + CameraMoveForward( camera, -CAMERA_MOVE_SPEED, moveInWorldPlane ); + if ( GetGamepadAxisMovement( 0, GAMEPAD_AXIS_LEFT_X ) >= 0.25f ) + CameraMoveRight( camera, CAMERA_MOVE_SPEED, moveInWorldPlane ); + } + + if ( mode == CAMERA_FREE ) + { + if ( IsKeyDown( KEY_SPACE ) ) + CameraMoveUp( camera, CAMERA_MOVE_SPEED ); + if ( IsKeyDown( KEY_LEFT_CONTROL ) ) + CameraMoveUp( camera, -CAMERA_MOVE_SPEED ); + } + } + + if ( ( mode == CAMERA_THIRD_PERSON ) || ( mode == CAMERA_ORBITAL ) || ( mode == CAMERA_FREE ) ) + { + // Zoom target distance + CameraMoveToTarget( camera, -GetMouseWheelMove() ); + if ( IsKeyPressed( KEY_KP_SUBTRACT ) ) + CameraMoveToTarget( camera, 2.0f ); + if ( IsKeyPressed( KEY_KP_ADD ) ) + CameraMoveToTarget( camera, -2.0f ); + } +} +#endif +// !RCAMERA_STANDALONE + +// Update camera movement, movement/rotation values should be provided by user +void update_camera_pro( Camera* camera, Vector3 movement, Vector3 rotation, f32 zoom ) +{ + bool lockView = true; + bool rotateAroundTarget = false; + bool rotateUp = false; + bool moveInWorldPlane = true; + + // Camera rotation + CameraPitch( camera, -rotation.y * DEG2RAD, lockView, rotateAroundTarget, rotateUp ); + CameraYaw( camera, -rotation.x * DEG2RAD, rotateAroundTarget ); + CameraRoll( camera, rotation.z * DEG2RAD ); + + // Camera movement + CameraMoveForward( camera, movement.x, moveInWorldPlane ); + CameraMoveRight( camera, movement.y, moveInWorldPlane ); + CameraMoveUp( camera, movement.z ); + + // Zoom target distance + CameraMoveToTarget( camera, zoom ); +} + +#endif +// RCAMERA_IMPLEMENTATION diff --git a/project/auxillary/vis_ast/dependencies/raylib/include/rcore.h b/project/auxillary/vis_ast/dependencies/raylib/include/rcore.h new file mode 100644 index 0000000..83d852f --- /dev/null +++ b/project/auxillary/vis_ast/dependencies/raylib/include/rcore.h @@ -0,0 +1,233 @@ +/********************************************************************************************** + * + * rcore - Common types and globals (all platforms) + * + * LIMITATIONS: + * - Limitation 01 + * - Limitation 02 + * + * POSSIBLE IMPROVEMENTS: + * - Improvement 01 + * - Improvement 02 + * + * + * LICENSE: zlib/libpng + * + * Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) and contributors + * + * 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 RCORE_H +#define RCORE_H + +#include "raylib.h" + +#include "utils.h" // Required for: TRACELOG() macros + +#include "rlgl.h" // Required for: graphics layer functionality + +#define RAYMATH_IMPLEMENTATION +#include "raymath.h" // Required for: Vector2/Vector3/Matrix functionality + +#include // Required for: srand(), rand(), atexit() +#include // Required for: sprintf() [Used in OpenURL()] +#include // Required for: strrchr(), strcmp(), strlen(), memset() +#include // Required for: time() [Used in InitTimer()] +#include // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()] + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#ifndef MAX_FILEPATH_CAPACITY +#define MAX_FILEPATH_CAPACITY 8192 // Maximum capacity for filepath +#endif +#ifndef MAX_FILEPATH_LENGTH +#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value) +#endif + +#ifndef MAX_KEYBOARD_KEYS +#define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported +#endif +#ifndef MAX_MOUSE_BUTTONS +#define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported +#endif +#ifndef MAX_GAMEPADS +#define MAX_GAMEPADS 4 // Maximum number of gamepads supported +#endif +#ifndef MAX_GAMEPAD_AXIS +#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad) +#endif +#ifndef MAX_GAMEPAD_BUTTONS +#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad) +#endif +#ifndef MAX_TOUCH_POINTS +#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported +#endif +#ifndef MAX_KEY_PRESSED_QUEUE +#define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue +#endif +#ifndef MAX_CHAR_PRESSED_QUEUE +#define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue +#endif + +#ifndef MAX_DECOMPRESSION_SIZE +#define MAX_DECOMPRESSION_SIZE 64 // Maximum size allocated for decompression in MB +#endif + +// Flags operation macros +#define FLAG_SET( n, f ) ( ( n ) |= ( f ) ) +#define FLAG_CLEAR( n, f ) ( ( n ) &= ~( f ) ) +#define FLAG_TOGGLE( n, f ) ( ( n ) ^= ( f ) ) +#define FLAG_CHECK( n, f ) ( ( n ) & ( f ) ) + +#if ( defined( __linux__ ) || defined( PLATFORM_WEB ) ) && ( _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 + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef struct +{ + int x; + int y; +} Point; + +typedef struct +{ + unsigned int width; + unsigned int height; +} Size; + +// Core global state context data +typedef struct CoreData +{ + struct + { + const char* title; // Window text title const pointer + unsigned int flags; // Configuration flags (bit based), keeps window state + bool ready; // Check if window has been initialized successfully + bool fullscreen; // Check if fullscreen mode is enabled + bool shouldClose; // Check if window set for closing + bool resizedLastFrame; // Check if window has been resized last frame + bool eventWaiting; // Wait for events before ending frame + + Point position; // Window position (required on fullscreen toggle) + Point previousPosition; // Window previous position (required on borderless windowed toggle) + Size display; // Display width and height (monitor, device-screen, LCD, ...) + Size screen; // Screen width and height (used render area) + Size previousScreen; // Screen previous width and height (required on borderless windowed toggle) + Size currentFbo; // Current render width and height (depends on active fbo) + Size render; // Framebuffer width and height (render area, including black bars if required) + Point renderOffset; // Offset from render area (must be divided by 2) + Size screenMin; // Screen minimum width and height (for resizable window) + Size screenMax; // Screen maximum width and height (for resizable window) + Matrix screenScale; // Matrix to scale screen (framebuffer rendering) + + char** dropFilepaths; // Store dropped files paths pointers (provided by GLFW) + unsigned int dropFileCount; // Count dropped files strings + + } Window; + + struct + { + const char* basePath; // Base path for data storage + + } Storage; + + struct + { + struct + { + int exitKey; // Default exit key + char currentKeyState[ MAX_KEYBOARD_KEYS ]; // Registers current frame key state + char previousKeyState[ MAX_KEYBOARD_KEYS ]; // Registers previous frame key state + + // NOTE: Since key press logic involves comparing prev vs cur key state, we need to handle key repeats specially + char keyRepeatInFrame[ MAX_KEYBOARD_KEYS ]; // Registers key repeats for current frame. + + int keyPressedQueue[ MAX_KEY_PRESSED_QUEUE ]; // Input keys queue + int keyPressedQueueCount; // Input keys queue count + + int charPressedQueue[ MAX_CHAR_PRESSED_QUEUE ]; // Input characters queue (unicode) + int charPressedQueueCount; // Input characters queue count + + } Keyboard; + + struct + { + Vector2 offset; // Mouse offset + Vector2 scale; // Mouse scaling + Vector2 currentPosition; // Mouse position on screen + Vector2 previousPosition; // Previous mouse position + + int cursor; // Tracks current mouse cursor + bool cursorHidden; // Track if cursor is hidden + bool cursorOnScreen; // Tracks if cursor is inside client area + + char currentButtonState[ MAX_MOUSE_BUTTONS ]; // Registers current mouse button state + char previousButtonState[ MAX_MOUSE_BUTTONS ]; // Registers previous mouse button state + Vector2 currentWheelMove; // Registers current mouse wheel variation + Vector2 previousWheelMove; // Registers previous mouse wheel variation + + } Mouse; + + struct + { + int pointCount; // Number of touch points active + int pointId[ MAX_TOUCH_POINTS ]; // Point identifiers + Vector2 position[ MAX_TOUCH_POINTS ]; // Touch position on screen + char currentTouchState[ MAX_TOUCH_POINTS ]; // Registers current touch state + char previousTouchState[ MAX_TOUCH_POINTS ]; // Registers previous touch state + + } Touch; + + struct + { + int lastButtonPressed; // Register last gamepad button pressed + int axisCount[ MAX_GAMEPADS ]; // Register number of available gamepad axis + bool ready[ MAX_GAMEPADS ]; // Flag to know if gamepad is ready + char name[ MAX_GAMEPADS ][ 64 ]; // Gamepad name holder + char currentButtonState[ MAX_GAMEPADS ][ MAX_GAMEPAD_BUTTONS ]; // Current gamepad buttons state + char previousButtonState[ MAX_GAMEPADS ][ MAX_GAMEPAD_BUTTONS ]; // Previous gamepad buttons state + float axisState[ MAX_GAMEPADS ][ MAX_GAMEPAD_AXIS ]; // Gamepad axis state + + } Gamepad; + } Input; + + struct + { + double current; // Current time measure + double previous; // Previous time measure + double update; // Time measure for frame update + double draw; // Time measure for frame draw + double frame; // Time measure for one frame + double target; // Desired time for one frame, if 0 not applied + unsigned long long int base; // Base time measure for hi-res timer (PLATFORM_ANDROID, PLATFORM_DRM) + unsigned int frameCounter; // Frame counter + + } Time; +} CoreData; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +extern CoreData CORE; + +#endif diff --git a/project/auxillary/vis_ast/dependencies/raylib/include/rgestures.h b/project/auxillary/vis_ast/dependencies/raylib/include/rgestures.h new file mode 100644 index 0000000..3284448 --- /dev/null +++ b/project/auxillary/vis_ast/dependencies/raylib/include/rgestures.h @@ -0,0 +1,594 @@ +/********************************************************************************************** + * + * rgestures - Gestures system, gestures processing based on input events (touch/mouse) + * + * CONFIGURATION: + * #define RGESTURES_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 RGESTURES_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-2023 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 standalone usage +//---------------------------------------------------------------------------------- +// Boolean type +#if ( defined( __STDC__ ) && __STDC_VERSION__ >= 199901L ) || ( defined( _MSC_VER ) && _MSC_VER >= 1800 ) +#include +#elif ! defined( __cplusplus ) && ! defined( bool ) && ! defined( RL_BOOL_TYPE ) +typedef enum bool +{ + false = 0, + true = ! false +} bool; +#endif + +#if ! defined( RL_VECTOR2_TYPE ) +// Vector2 type +typedef struct Vector2 +{ + float x; + float y; +} Vector2; +#endif + +#if defined( RGESTURES_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 +//---------------------------------------------------------------------------------- + +#if defined( __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( RGESTURES_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 seconds + 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 + +#if defined( __cplusplus ) +} +#endif + +#endif // RGESTURES_H + +/*********************************************************************************** + * + * RGESTURES IMPLEMENTATION + * + ************************************************************************************/ + +#if defined( RGESTURES_IMPLEMENTATION ) + +#if defined( RGESTURES_STANDALONE ) +#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 +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +#define FORCE_TO_SWIPE 0.2f // 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 DRAG_TIMEOUT 0.3f // Drag minimum time for web, measured in seconds +#define MINIMUM_PINCH 0.005f // Pinch minimum force, measured in normalized screen units (0.0f to 1.0f) +#define TAP_TIMEOUT 0.3f // Tap minimum time, measured in seconds +#define PINCH_TIMEOUT 0.3f // Pinch minimum time, measured in seconds +#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 + Vector2 previousPositionA; // Previous position A to compare for pinch gestures + Vector2 previousPositionB; // Previous position B to compare for pinch gestures + 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 seconds + } 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 + { + double startTime; // SWIPE start 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 gestures to be detected +void SetGesturesEnabled( unsigned int flags ) +{ + GESTURES.enabledFlags = flags; +} + +// Check if a gesture have been detected +bool IsGestureDetected( unsigned 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.Swipe.startTime = rgGetCurrentTime(); + + GESTURES.Drag.vector = ( Vector2 ) { 0.0f, 0.0f }; + } + else if ( event.touchAction == TOUCH_ACTION_UP ) + { + // A swipe can happen while the current gesture is drag, but (specially for web) also hold, so set upPosition for both cases + if ( GESTURES.current == GESTURE_DRAG || GESTURES.current == GESTURE_HOLD ) + GESTURES.Touch.upPosition = event.position[ 0 ]; + + // NOTE: GESTURES.Drag.intensity dependent 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.startTime ) ); + + // Detect GESTURE_SWIPE + if ( ( GESTURES.Drag.intensity > FORCE_TO_SWIPE ) && ( GESTURES.current != GESTURE_DRAG ) ) + { + // 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 <= 150 ) ) + GESTURES.current = GESTURE_SWIPE_UP; // Up + else if ( ( GESTURES.Drag.angle > 150 ) && ( GESTURES.Drag.angle < 210 ) ) + GESTURES.current = GESTURE_SWIPE_LEFT; // Left + else if ( ( GESTURES.Drag.angle >= 210 ) && ( GESTURES.Drag.angle <= 330 ) ) + 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 ) + { + 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 ( ( rgGetCurrentTime() - GESTURES.Touch.eventTime ) > DRAG_TIMEOUT ) + { + 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.Touch.previousPositionA = GESTURES.Touch.downPositionA; + GESTURES.Touch.previousPositionB = GESTURES.Touch.downPositionB; + + // 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.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.previousPositionA, GESTURES.Touch.moveDownPositionA ) >= MINIMUM_PINCH ) + || ( rgVector2Distance( GESTURES.Touch.previousPositionB, GESTURES.Touch.moveDownPositionB ) >= MINIMUM_PINCH ) ) + { + if ( rgVector2Distance( GESTURES.Touch.previousPositionA, GESTURES.Touch.previousPositionB ) + > rgVector2Distance( GESTURES.Touch.moveDownPositionA, GESTURES.Touch.moveDownPositionB ) ) + 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(); + } + + // 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, counterclockwise +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 between two pinch points +// NOTE: Angle in degrees, horizontal-right is 0, counterclockwise +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 seconds +static double rgGetCurrentTime( void ) +{ + double time = 0; + +#if ! defined( RGESTURES_STANDALONE ) + time = GetTime(); +#else +#if defined( _WIN32 ) + unsigned long long int clockFrequency, currentTime; + + QueryPerformanceFrequency( &clockFrequency ); // BE CAREFUL: Costly operation! + QueryPerformanceCounter( ¤tTime ); + + time = ( double )currentTime / clockFrequency; // Time in seconds +#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 * 1e-9 ); // Time in seconds +#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 * 1e-9 ); // Time in seconds +#endif +#endif + + return time; +} + +#endif // RGESTURES_IMPLEMENTATION diff --git a/project/auxillary/vis_ast/dependencies/raylib/include/rlgl.h b/project/auxillary/vis_ast/dependencies/raylib/include/rlgl.h new file mode 100644 index 0000000..dde4422 --- /dev/null +++ b/project/auxillary/vis_ast/dependencies/raylib/include/rlgl.h @@ -0,0 +1,5679 @@ +/********************************************************************************************** + * + * rlgl v4.5 - A multi-OpenGL abstraction layer with an immediate-mode style API + * + * DESCRIPTION: + * An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0) + * that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...) + * + * ADDITIONAL NOTES: + * When choosing an OpenGL backend different than OpenGL 1.1, some internal 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, + * additionally, rlDrawRenderBatchActive() could be called to force flushing of the batch. + * + * Some resources are also loaded for convenience, here the complete list: + * - Default batch (RLGL.defaultBatch): RenderBatch system to accumulate vertex data + * - Default texture (RLGL.defaultTextureId): 1x1 white pixel R8G8B8A8 + * - Default shader (RLGL.State.defaultShaderId, RLGL.State.defaultShaderLocs) + * + * Internal buffer (and resources) must be manually unloaded calling rlglClose(). + * + * CONFIGURATION: + * #define GRAPHICS_API_OPENGL_11 + * #define GRAPHICS_API_OPENGL_21 + * #define GRAPHICS_API_OPENGL_33 + * #define GRAPHICS_API_OPENGL_43 + * #define GRAPHICS_API_OPENGL_ES2 + * #define GRAPHICS_API_OPENGL_ES3 + * Use selected OpenGL graphics backend, should be supported by platform + * Those preprocessor defines are only used on 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" // Bound by default to shader location: 0 + * #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: 1 + * #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: 2 + * #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: 3 + * #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: 4 + * #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-2023 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.5" + +// 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 ) && ! defined( GRAPHICS_API_OPENGL_ES3 ) +#define GRAPHICS_API_OPENGL_33 +#endif + +// Security check in case multiple GRAPHICS_API_OPENGL_* defined +#if defined( GRAPHICS_API_OPENGL_11 ) +#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 + +// OpenGL ES 3.0 uses OpenGL ES 2.0 functionality (and more) +#if defined( GRAPHICS_API_OPENGL_ES3 ) +#define GRAPHICS_API_OPENGL_ES2 +#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_MIPMAP_BIAS_RATIO 0x4000 // Texture mipmap bias, percentage ratio (custom identifier) + +#define RL_TEXTURE_WRAP_REPEAT 0x2901 // GL_REPEAT +#define RL_TEXTURE_WRAP_CLAMP 0x812F // GL_CLAMP_TO_EDGE +#define RL_TEXTURE_WRAP_MIRROR_REPEAT 0x8370 // GL_MIRRORED_REPEAT +#define RL_TEXTURE_WRAP_MIRROR_CLAMP 0x8742 // GL_MIRROR_CLAMP_EXT + +// Matrix modes (equivalent to OpenGL) +#define RL_MODELVIEW 0x1700 // GL_MODELVIEW +#define RL_PROJECTION 0x1701 // GL_PROJECTION +#define RL_TEXTURE 0x1702 // GL_TEXTURE + +// Primitive assembly draw modes +#define RL_LINES 0x0001 // GL_LINES +#define RL_TRIANGLES 0x0004 // GL_TRIANGLES +#define RL_QUADS 0x0007 // GL_QUADS + +// GL equivalent data types +#define RL_UNSIGNED_BYTE 0x1401 // GL_UNSIGNED_BYTE +#define RL_FLOAT 0x1406 // GL_FLOAT + +// GL buffer usage hint +#define RL_STREAM_DRAW 0x88E0 // GL_STREAM_DRAW +#define RL_STREAM_READ 0x88E1 // GL_STREAM_READ +#define RL_STREAM_COPY 0x88E2 // GL_STREAM_COPY +#define RL_STATIC_DRAW 0x88E4 // GL_STATIC_DRAW +#define RL_STATIC_READ 0x88E5 // GL_STATIC_READ +#define RL_STATIC_COPY 0x88E6 // GL_STATIC_COPY +#define RL_DYNAMIC_DRAW 0x88E8 // GL_DYNAMIC_DRAW +#define RL_DYNAMIC_READ 0x88E9 // GL_DYNAMIC_READ +#define RL_DYNAMIC_COPY 0x88EA // GL_DYNAMIC_COPY + +// GL Shader type +#define RL_FRAGMENT_SHADER 0x8B30 // GL_FRAGMENT_SHADER +#define RL_VERTEX_SHADER 0x8B31 // GL_VERTEX_SHADER +#define RL_COMPUTE_SHADER 0x91B9 // GL_COMPUTE_SHADER + +// GL blending factors +#define RL_ZERO 0 // GL_ZERO +#define RL_ONE 1 // GL_ONE +#define RL_SRC_COLOR 0x0300 // GL_SRC_COLOR +#define RL_ONE_MINUS_SRC_COLOR 0x0301 // GL_ONE_MINUS_SRC_COLOR +#define RL_SRC_ALPHA 0x0302 // GL_SRC_ALPHA +#define RL_ONE_MINUS_SRC_ALPHA 0x0303 // GL_ONE_MINUS_SRC_ALPHA +#define RL_DST_ALPHA 0x0304 // GL_DST_ALPHA +#define RL_ONE_MINUS_DST_ALPHA 0x0305 // GL_ONE_MINUS_DST_ALPHA +#define RL_DST_COLOR 0x0306 // GL_DST_COLOR +#define RL_ONE_MINUS_DST_COLOR 0x0307 // GL_ONE_MINUS_DST_COLOR +#define RL_SRC_ALPHA_SATURATE 0x0308 // GL_SRC_ALPHA_SATURATE +#define RL_CONSTANT_COLOR 0x8001 // GL_CONSTANT_COLOR +#define RL_ONE_MINUS_CONSTANT_COLOR 0x8002 // GL_ONE_MINUS_CONSTANT_COLOR +#define RL_CONSTANT_ALPHA 0x8003 // GL_CONSTANT_ALPHA +#define RL_ONE_MINUS_CONSTANT_ALPHA 0x8004 // GL_ONE_MINUS_CONSTANT_ALPHA + +// GL blending functions/equations +#define RL_FUNC_ADD 0x8006 // GL_FUNC_ADD +#define RL_MIN 0x8007 // GL_MIN +#define RL_MAX 0x8008 // GL_MAX +#define RL_FUNC_SUBTRACT 0x800A // GL_FUNC_SUBTRACT +#define RL_FUNC_REVERSE_SUBTRACT 0x800B // GL_FUNC_REVERSE_SUBTRACT +#define RL_BLEND_EQUATION 0x8009 // GL_BLEND_EQUATION +#define RL_BLEND_EQUATION_RGB 0x8009 // GL_BLEND_EQUATION_RGB // (Same as BLEND_EQUATION) +#define RL_BLEND_EQUATION_ALPHA 0x883D // GL_BLEND_EQUATION_ALPHA +#define RL_BLEND_DST_RGB 0x80C8 // GL_BLEND_DST_RGB +#define RL_BLEND_SRC_RGB 0x80C9 // GL_BLEND_SRC_RGB +#define RL_BLEND_DST_ALPHA 0x80CA // GL_BLEND_DST_ALPHA +#define RL_BLEND_SRC_ALPHA 0x80CB // GL_BLEND_SRC_ALPHA +#define RL_BLEND_COLOR 0x8005 // GL_BLEND_COLOR + + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +#if ( defined( __STDC__ ) && __STDC_VERSION__ >= 199901L ) || ( defined( _MSC_VER ) && _MSC_VER >= 1800 ) +#include +#elif ! defined( __cplusplus ) && ! defined( bool ) && ! defined( RL_BOOL_TYPE ) +// Boolean type +typedef enum bool +{ + false = 0, + true = ! false +} bool; +#endif + +#if ! defined( RL_MATRIX_TYPE ) +// Matrix, 4x4 components, column major, OpenGL style, right handed +typedef struct Matrix +{ + float m0, m4, m8, m12; // Matrix first row (4 components) + float m1, m5, m9, m13; // Matrix second row (4 components) + float m2, m6, m10, m14; // Matrix third row (4 components) + float m3, m7, m11, m15; // Matrix fourth row (4 components) +} Matrix; + +#define RL_MATRIX_TYPE +#endif + +// Dynamic vertex buffers (position + texcoords + colors + indices arrays) +typedef struct rlVertexBuffer +{ + int elementCount; // Number of elements in the buffer (QUADS) + + float* vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0) + float* texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1) + 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; + +// OpenGL version +typedef enum +{ + RL_OPENGL_11 = 1, // OpenGL 1.1 + RL_OPENGL_21, // OpenGL 2.1 (GLSL 120) + RL_OPENGL_33, // OpenGL 3.3 (GLSL 330) + RL_OPENGL_43, // OpenGL 4.3 (using GLSL 330) + RL_OPENGL_ES_20, // OpenGL ES 2.0 (GLSL 100) + RL_OPENGL_ES_30 // OpenGL ES 3.0 (GLSL 300 es) +} rlGlVersion; + +// Trace log level +// NOTE: Organized by priority level +typedef enum +{ + RL_LOG_ALL = 0, // Display all logs + RL_LOG_TRACE, // Trace logging, intended for internal use only + RL_LOG_DEBUG, // Debug logging, used for internal debugging, it should be disabled on release builds + RL_LOG_INFO, // Info logging, used for program execution info + RL_LOG_WARNING, // Warning logging, used on recoverable failures + RL_LOG_ERROR, // Error logging, used on unrecoverable failures + RL_LOG_FATAL, // Fatal logging, used to abort program: exit(EXIT_FAILURE) + RL_LOG_NONE // Disable logging +} rlTraceLogLevel; + +// Texture pixel formats +// NOTE: Support depends on OpenGL version +typedef enum +{ + RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha) + RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA, // 8*2 bpp (2 channels) + RL_PIXELFORMAT_UNCOMPRESSED_R5G6B5, // 16 bpp + RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8, // 24 bpp + RL_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha) + RL_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha) + RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, // 32 bpp + RL_PIXELFORMAT_UNCOMPRESSED_R32, // 32 bpp (1 channel - float) + RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32, // 32*3 bpp (3 channels - float) + RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32, // 32*4 bpp (4 channels - float) + RL_PIXELFORMAT_UNCOMPRESSED_R16, // 16 bpp (1 channel - half float) + RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16, // 16*3 bpp (3 channels - half float) + RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16, // 16*4 bpp (4 channels - half float) + RL_PIXELFORMAT_COMPRESSED_DXT1_RGB, // 4 bpp (no alpha) + RL_PIXELFORMAT_COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha) + RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA, // 8 bpp + RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA, // 8 bpp + RL_PIXELFORMAT_COMPRESSED_ETC1_RGB, // 4 bpp + RL_PIXELFORMAT_COMPRESSED_ETC2_RGB, // 4 bpp + RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA, // 8 bpp + RL_PIXELFORMAT_COMPRESSED_PVRT_RGB, // 4 bpp + RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA, // 4 bpp + RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA, // 8 bpp + RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA // 2 bpp +} rlPixelFormat; + +// Texture parameters: filter mode +// NOTE 1: Filtering considers mipmaps if available in the texture +// NOTE 2: Filter is accordingly set for minification and magnification +typedef enum +{ + RL_TEXTURE_FILTER_POINT = 0, // No filter, just pixel approximation + RL_TEXTURE_FILTER_BILINEAR, // Linear filtering + RL_TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps) + RL_TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x + RL_TEXTURE_FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x + RL_TEXTURE_FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x +} rlTextureFilter; + +// Color blending modes (pre-defined) +typedef enum +{ + RL_BLEND_ALPHA = 0, // Blend textures considering alpha (default) + RL_BLEND_ADDITIVE, // Blend textures adding colors + RL_BLEND_MULTIPLIED, // Blend textures multiplying colors + RL_BLEND_ADD_COLORS, // Blend textures adding colors (alternative) + RL_BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative) + RL_BLEND_ALPHA_PREMULTIPLY, // Blend premultiplied textures considering alpha + RL_BLEND_CUSTOM, // Blend textures using custom src/dst factors (use rlSetBlendFactors()) + RL_BLEND_CUSTOM_SEPARATE // Blend textures using custom src/dst factors (use rlSetBlendFactorsSeparate()) +} rlBlendMode; + +// Shader location point type +typedef enum +{ + RL_SHADER_LOC_VERTEX_POSITION = 0, // Shader location: vertex attribute: position + RL_SHADER_LOC_VERTEX_TEXCOORD01, // Shader location: vertex attribute: texcoord01 + RL_SHADER_LOC_VERTEX_TEXCOORD02, // Shader location: vertex attribute: texcoord02 + RL_SHADER_LOC_VERTEX_NORMAL, // Shader location: vertex attribute: normal + RL_SHADER_LOC_VERTEX_TANGENT, // Shader location: vertex attribute: tangent + RL_SHADER_LOC_VERTEX_COLOR, // Shader location: vertex attribute: color + RL_SHADER_LOC_MATRIX_MVP, // Shader location: matrix uniform: model-view-projection + RL_SHADER_LOC_MATRIX_VIEW, // Shader location: matrix uniform: view (camera transform) + RL_SHADER_LOC_MATRIX_PROJECTION, // Shader location: matrix uniform: projection + RL_SHADER_LOC_MATRIX_MODEL, // Shader location: matrix uniform: model (transform) + RL_SHADER_LOC_MATRIX_NORMAL, // Shader location: matrix uniform: normal + RL_SHADER_LOC_VECTOR_VIEW, // Shader location: vector uniform: view + RL_SHADER_LOC_COLOR_DIFFUSE, // Shader location: vector uniform: diffuse color + RL_SHADER_LOC_COLOR_SPECULAR, // Shader location: vector uniform: specular color + RL_SHADER_LOC_COLOR_AMBIENT, // Shader location: vector uniform: ambient color + RL_SHADER_LOC_MAP_ALBEDO, // Shader location: sampler2d texture: albedo (same as: RL_SHADER_LOC_MAP_DIFFUSE) + RL_SHADER_LOC_MAP_METALNESS, // Shader location: sampler2d texture: metalness (same as: RL_SHADER_LOC_MAP_SPECULAR) + RL_SHADER_LOC_MAP_NORMAL, // Shader location: sampler2d texture: normal + RL_SHADER_LOC_MAP_ROUGHNESS, // Shader location: sampler2d texture: roughness + RL_SHADER_LOC_MAP_OCCLUSION, // Shader location: sampler2d texture: occlusion + RL_SHADER_LOC_MAP_EMISSION, // Shader location: sampler2d texture: emission + RL_SHADER_LOC_MAP_HEIGHT, // Shader location: sampler2d texture: height + RL_SHADER_LOC_MAP_CUBEMAP, // Shader location: samplerCube texture: cubemap + RL_SHADER_LOC_MAP_IRRADIANCE, // Shader location: samplerCube texture: irradiance + RL_SHADER_LOC_MAP_PREFILTER, // Shader location: samplerCube texture: prefilter + RL_SHADER_LOC_MAP_BRDF // Shader location: sampler2d texture: brdf +} rlShaderLocationIndex; + +#define RL_SHADER_LOC_MAP_DIFFUSE RL_SHADER_LOC_MAP_ALBEDO +#define RL_SHADER_LOC_MAP_SPECULAR RL_SHADER_LOC_MAP_METALNESS + +// Shader uniform data type +typedef enum +{ + RL_SHADER_UNIFORM_FLOAT = 0, // Shader uniform type: float + RL_SHADER_UNIFORM_VEC2, // Shader uniform type: vec2 (2 float) + RL_SHADER_UNIFORM_VEC3, // Shader uniform type: vec3 (3 float) + RL_SHADER_UNIFORM_VEC4, // Shader uniform type: vec4 (4 float) + RL_SHADER_UNIFORM_INT, // Shader uniform type: int + RL_SHADER_UNIFORM_IVEC2, // Shader uniform type: ivec2 (2 int) + RL_SHADER_UNIFORM_IVEC3, // Shader uniform type: ivec3 (3 int) + RL_SHADER_UNIFORM_IVEC4, // Shader uniform type: ivec4 (4 int) + RL_SHADER_UNIFORM_SAMPLER2D // Shader uniform type: sampler2d +} rlShaderUniformDataType; + +// Shader attribute data types +typedef enum +{ + RL_SHADER_ATTRIB_FLOAT = 0, // Shader attribute type: float + RL_SHADER_ATTRIB_VEC2, // Shader attribute type: vec2 (2 float) + RL_SHADER_ATTRIB_VEC3, // Shader attribute type: vec3 (3 float) + RL_SHADER_ATTRIB_VEC4 // Shader attribute type: vec4 (4 float) +} rlShaderAttributeDataType; + +// Framebuffer attachment type +// NOTE: By default up to 8 color channels defined, but it can be more +typedef enum +{ + RL_ATTACHMENT_COLOR_CHANNEL0 = 0, // Framebuffer attachment type: color 0 + RL_ATTACHMENT_COLOR_CHANNEL1, // Framebuffer attachment type: color 1 + RL_ATTACHMENT_COLOR_CHANNEL2, // Framebuffer attachment type: color 2 + RL_ATTACHMENT_COLOR_CHANNEL3, // Framebuffer attachment type: color 3 + RL_ATTACHMENT_COLOR_CHANNEL4, // Framebuffer attachment type: color 4 + RL_ATTACHMENT_COLOR_CHANNEL5, // Framebuffer attachment type: color 5 + RL_ATTACHMENT_COLOR_CHANNEL6, // Framebuffer attachment type: color 6 + RL_ATTACHMENT_COLOR_CHANNEL7, // Framebuffer attachment type: color 7 + RL_ATTACHMENT_DEPTH = 100, // Framebuffer attachment type: depth + RL_ATTACHMENT_STENCIL = 200, // Framebuffer attachment type: stencil +} rlFramebufferAttachType; + +// Framebuffer texture attachment type +typedef enum +{ + RL_ATTACHMENT_CUBEMAP_POSITIVE_X = 0, // Framebuffer texture attachment type: cubemap, +X side + RL_ATTACHMENT_CUBEMAP_NEGATIVE_X, // Framebuffer texture attachment type: cubemap, -X side + RL_ATTACHMENT_CUBEMAP_POSITIVE_Y, // Framebuffer texture attachment type: cubemap, +Y side + RL_ATTACHMENT_CUBEMAP_NEGATIVE_Y, // Framebuffer texture attachment type: cubemap, -Y side + RL_ATTACHMENT_CUBEMAP_POSITIVE_Z, // Framebuffer texture attachment type: cubemap, +Z side + RL_ATTACHMENT_CUBEMAP_NEGATIVE_Z, // Framebuffer texture attachment type: cubemap, -Z side + RL_ATTACHMENT_TEXTURE2D = 100, // Framebuffer texture attachment type: texture2d + RL_ATTACHMENT_RENDERBUFFER = 200, // Framebuffer texture attachment type: renderbuffer +} rlFramebufferAttachTextureType; + +// Face culling mode +typedef enum +{ + RL_CULL_FACE_FRONT = 0, + RL_CULL_FACE_BACK +} rlCullMode; + +//------------------------------------------------------------------------------------ +// Functions Declaration - Matrix operations +//------------------------------------------------------------------------------------ + +#if defined( __cplusplus ) +extern "C" +{ // Prevents name mangling of functions +#endif + + RLAPI void rlMatrixMode( int mode ); // Choose the current matrix to be transformed + RLAPI void rlPushMatrix( void ); // Push the current matrix to stack + RLAPI void rlPopMatrix( void ); // Pop latest inserted matrix from stack + RLAPI void rlLoadIdentity( void ); // Reset current matrix to identity matrix + RLAPI void rlTranslatef( float x, float y, float z ); // Multiply the current matrix by a translation matrix + RLAPI void rlRotatef( float angle, float x, float y, float z ); // Multiply the current matrix by a rotation matrix + RLAPI void rlScalef( float x, float y, float z ); // Multiply the current matrix by a scaling matrix + RLAPI void rlMultMatrixf( const float* matf ); // Multiply the current matrix by another matrix + RLAPI void rlFrustum( double left, double right, double bottom, double top, double znear, double zfar ); + RLAPI void rlOrtho( double left, double right, double bottom, double top, double znear, double zfar ); + RLAPI void rlViewport( int x, int y, int width, int height ); // Set the viewport area + + //------------------------------------------------------------------------------------ + // 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) + RLAPI void rlCubemapParameters( unsigned int id, int param, int value ); // Set cubemap parameters (filter, wrap) + + // Shader state + RLAPI void rlEnableShader( unsigned int id ); // Enable shader program + RLAPI void rlDisableShader( void ); // Disable shader program + + // Framebuffer state + RLAPI void rlEnableFramebuffer( unsigned int id ); // Enable render texture (fbo) + RLAPI void rlDisableFramebuffer( void ); // Disable render texture (fbo), return to default framebuffer + RLAPI 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 rlSetCullFace( int mode ); // Set face culling mode + RLAPI void rlEnableScissorTest( void ); // Enable scissor test + RLAPI void rlDisableScissorTest( void ); // Disable scissor test + RLAPI void rlScissor( int x, int y, int width, int height ); // Scissor test + RLAPI void rlEnableWireMode( void ); // Enable wire mode + RLAPI void rlDisableWireMode( void ); // Disable wire mode + RLAPI void rlSetLineWidth( float width ); // Set the line drawing width + RLAPI float rlGetLineWidth( void ); // Get the line drawing width + RLAPI void rlEnableSmoothLines( void ); // Enable line aliasing + RLAPI void rlDisableSmoothLines( void ); // Disable line aliasing + RLAPI void rlEnableStereoRender( void ); // Enable stereo rendering + RLAPI void rlDisableStereoRender( void ); // Disable stereo rendering + RLAPI bool rlIsStereoRenderEnabled( void ); // Check if stereo render is enabled + + RLAPI void rlClearColor( unsigned char r, unsigned char g, unsigned char b, unsigned char a ); // Clear color buffer with color + RLAPI void rlClearScreenBuffers( void ); // Clear used screen buffers (color and depth) + RLAPI void rlCheckErrors( void ); // Check and log OpenGL error codes + RLAPI void rlSetBlendMode( int mode ); // Set blending mode + RLAPI void rlSetBlendFactors( int glSrcFactor, int glDstFactor, int glEquation ); // Set blending mode factor and equation (using OpenGL factors) + RLAPI void rlSetBlendFactorsSeparate( + int glSrcRGB, + int glDstRGB, + int glSrcAlpha, + int glDstAlpha, + int glEqRGB, + int glEqAlpha + ); // Set blending mode factors and equations separately (using OpenGL factors) + + //------------------------------------------------------------------------------------ + // Functions Declaration - rlgl functionality + //------------------------------------------------------------------------------------ + // rlgl initialization functions + RLAPI void rlglInit( int width, int height ); // Initialize rlgl (buffers, shaders, textures, states) + RLAPI void rlglClose( void ); // De-initialize rlgl (buffers, shaders, textures) + RLAPI void rlLoadExtensions( void* loader ); // Load OpenGL extensions (loader function required) + RLAPI int rlGetVersion( void ); // Get current OpenGL version + RLAPI void rlSetFramebufferWidth( int width ); // Set current framebuffer width + RLAPI int rlGetFramebufferWidth( void ); // Get default framebuffer width + RLAPI void rlSetFramebufferHeight( int height ); // Set current framebuffer height + RLAPI int rlGetFramebufferHeight( void ); // Get default framebuffer height + + RLAPI unsigned int rlGetTextureIdDefault( void ); // Get default texture id + RLAPI unsigned int rlGetShaderIdDefault( void ); // Get default shader id + RLAPI int* rlGetShaderLocsDefault( void ); // Get default shader locations + + // Render batch management + // NOTE: rlgl provides a default render batch to behave like OpenGL 1.1 immediate mode + // but this render batch API is exposed in case of custom batches are required + RLAPI rlRenderBatch rlLoadRenderBatch( int numBuffers, int bufferElements ); // Load a render batch system + RLAPI void rlUnloadRenderBatch( rlRenderBatch batch ); // Unload render batch system + RLAPI void rlDrawRenderBatch( rlRenderBatch* batch ); // Draw render batch data (Update->Draw->Reset) + RLAPI void rlSetRenderBatchActive( rlRenderBatch* batch ); // Set the active render batch for rlgl (NULL for default internal) + RLAPI void rlDrawRenderBatchActive( void ); // Update and draw internal render batch + RLAPI bool rlCheckRenderBatchLimit( int vCount ); // Check internal buffer overflow for a given number of vertex + + RLAPI void rlSetTexture( unsigned int id ); // Set current texture for render batch and check buffers limits + + //------------------------------------------------------------------------------------------------------------------------ + + // Vertex buffers management + RLAPI unsigned int rlLoadVertexArray( void ); // Load vertex array (vao) if supported + RLAPI unsigned int rlLoadVertexBuffer( const void* buffer, int size, bool dynamic ); // Load a vertex buffer attribute + RLAPI unsigned int rlLoadVertexBufferElement( const void* buffer, int size, bool dynamic ); // Load a new attributes element buffer + RLAPI void rlUpdateVertexBuffer( unsigned int bufferId, const void* data, int dataSize, int offset ); // Update GPU buffer with new data + RLAPI void rlUpdateVertexBufferElements( unsigned int id, const void* data, int dataSize, int offset ); // Update vertex buffer elements 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, const 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, const void* buffer ); + RLAPI void rlDrawVertexArrayInstanced( int offset, int count, int instances ); + RLAPI void rlDrawVertexArrayElementsInstanced( int offset, int count, const void* buffer, int instances ); + + // Textures management + RLAPI unsigned int rlLoadTexture( const 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( const 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, unsigned int* glInternalFormat, unsigned int* glFormat, unsigned int* glType ); // Get OpenGL internal formats + RLAPI const char* rlGetPixelFormatName( unsigned int format ); // Get name string for pixel format + RLAPI void rlUnloadTexture( unsigned int id ); // Unload texture from GPU memory + RLAPI void rlGenTextureMipmaps( unsigned int id, int width, int height, int format, int* mipmaps ); // Generate mipmap data for selected texture + RLAPI void* rlReadTexturePixels( unsigned int id, int width, int height, int format ); // Read texture pixel data + RLAPI unsigned char* rlReadScreenPixels( int width, int height ); // Read screen pixel data (color buffer) + + // Framebuffer management (fbo) + RLAPI unsigned int rlLoadFramebuffer( 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 pipeline) + + // Shader buffer storage object management (ssbo) + RLAPI unsigned int rlLoadShaderBuffer( unsigned int size, const void* data, int usageHint ); // Load shader storage buffer object (SSBO) + RLAPI void rlUnloadShaderBuffer( unsigned int ssboId ); // Unload shader storage buffer object (SSBO) + RLAPI void rlUpdateShaderBuffer( unsigned int id, const void* data, unsigned int dataSize, unsigned int offset ); // Update SSBO buffer data + RLAPI void rlBindShaderBuffer( unsigned int id, unsigned int index ); // Bind SSBO buffer + RLAPI void rlReadShaderBuffer( unsigned int id, void* dest, unsigned int count, unsigned int offset ); // Read SSBO buffer data (GPU->CPU) + RLAPI void rlCopyShaderBuffer( + unsigned int destId, + unsigned int srcId, + unsigned int destOffset, + unsigned int srcOffset, + unsigned int count + ); // Copy SSBO data between buffers + RLAPI unsigned int rlGetShaderBufferSize( unsigned int id ); // Get SSBO buffer size + + // Buffer management + RLAPI void rlBindImageTexture( unsigned int id, unsigned int index, int format, bool readonly ); // Bind image texture + + // Matrix state management + RLAPI Matrix rlGetMatrixModelview( void ); // Get internal modelview matrix + RLAPI Matrix rlGetMatrixProjection( void ); // Get internal projection matrix + RLAPI Matrix rlGetMatrixTransform( void ); // Get internal accumulated transform matrix + RLAPI Matrix rlGetMatrixProjectionStereo( int eye ); // Get internal projection matrix for stereo render (selected eye) + RLAPI Matrix rlGetMatrixViewOffsetStereo( int eye ); // Get internal view offset matrix for stereo render (selected eye) + RLAPI void rlSetMatrixProjection( Matrix proj ); // Set a custom projection matrix (replaces internal projection matrix) + RLAPI void rlSetMatrixModelview( Matrix view ); // Set a custom modelview matrix (replaces internal modelview matrix) + RLAPI void rlSetMatrixProjectionStereo( Matrix right, Matrix left ); // Set eyes projection matrices for stereo rendering + RLAPI void rlSetMatrixViewOffsetStereo( Matrix right, Matrix left ); // Set eyes view offsets matrices for stereo rendering + + // Quick and dirty cube/quad buffers load->draw->unload + RLAPI void rlLoadDrawCube( void ); // Load and draw a cube + RLAPI void rlLoadDrawQuad( void ); // Load and draw a quad + +#if defined( __cplusplus ) +} +#endif + +#endif // RLGL_H + +/*********************************************************************************** + * + * RLGL IMPLEMENTATION + * + ************************************************************************************/ + +#if defined( RLGL_IMPLEMENTATION ) + +#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 +#if ! defined( APIENTRY ) +#if defined( _WIN32 ) +#define APIENTRY __stdcall +#else +#define APIENTRY +#endif +#endif +// WINGDIAPI definition. Some Windows OpenGL headers need it +#if ! defined( WINGDIAPI ) && defined( _WIN32 ) +#define WINGDIAPI __declspec( dllimport ) +#endif + +#include // OpenGL 1.1 library +#endif +#endif + +#if defined( GRAPHICS_API_OPENGL_33 ) +#define GLAD_MALLOC RL_MALLOC +#define GLAD_FREE RL_FREE + +#define GLAD_GL_IMPLEMENTATION +#include "external/glad.h" // GLAD extensions loading library, includes OpenGL headers +#endif + +#if defined( GRAPHICS_API_OPENGL_ES2 ) +// NOTE: OpenGL ES 2.0 can be enabled on PLATFORM_DESKTOP, +// in that case, functions are loaded from a custom glad for OpenGL ES 2.0 +#if defined( PLATFORM_DESKTOP ) +#define GLAD_GLES2_IMPLEMENTATION +#include "external/glad_gles2.h" +#else +#define GL_GLEXT_PROTOTYPES +// #include // EGL library -> not required, platform layer +#include // OpenGL ES 2.0 library +#include // OpenGL ES 2.0 extensions library +#endif + +// It seems OpenGL ES 2.0 instancing entry points are not defined on Raspberry Pi +// provided headers (despite being defined in official Khronos GLES2 headers) +#if defined( PLATFORM_DRM ) +typedef void( GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDEXTPROC )( GLenum mode, GLint start, GLsizei count, GLsizei primcount ); +typedef void( GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDEXTPROC )( GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei primcount ); +typedef void( GL_APIENTRYP PFNGLVERTEXATTRIBDIVISOREXTPROC )( GLuint index, GLuint divisor ); +#endif +#endif + +#include // Required for: 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" // Bound by default to shader location: 0 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD +#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: 1 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL +#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: 2 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR +#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: 3 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT +#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: 4 +#endif +#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 +#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound 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 + + // Blending variables + int currentBlendMode; // Blending mode active + int glBlendSrcFactor; // Blending source factor + int glBlendDstFactor; // Blending destination factor + int glBlendEquation; // Blending equation + int glBlendSrcFactorRGB; // Blending source RGB factor + int glBlendDestFactorRGB; // Blending destination RGB factor + int glBlendSrcFactorAlpha; // Blending source alpha factor + int glBlendDestFactorAlpha; // Blending destination alpha factor + int glBlendEquationRGB; // Blending equation for RGB + int glBlendEquationAlpha; // Blending equation for alpha + bool glCustomBlendModeModified; // Custom blending factor and equation modification status + + int framebufferWidth; // Current framebuffer width + int framebufferHeight; // Current framebuffer height + + } State; // Renderer state + + struct + { + bool vao; // VAO support (OpenGL ES2 could not support VAO extension) (GL_ARB_vertex_array_object) + bool instancing; // Instancing supported (GL_ANGLE_instanced_arrays, GL_EXT_draw_instanced + GL_EXT_instanced_arrays) + bool texNPOT; // NPOT textures full support (GL_ARB_texture_non_power_of_two, GL_OES_texture_npot) + bool texDepth; // Depth textures supported (GL_ARB_depth_texture, GL_OES_depth_texture) + bool texDepthWebGL; // Depth textures supported WebGL specific (GL_WEBGL_depth_texture) + bool texFloat32; // float textures support (32 bit per channel) (GL_OES_texture_float) + bool texFloat16; // half float textures support (16 bit per channel) (GL_OES_texture_half_float) + bool texCompDXT; // DDS texture compression support (GL_EXT_texture_compression_s3tc, GL_WEBGL_compressed_texture_s3tc, + // GL_WEBKIT_WEBGL_compressed_texture_s3tc) + bool texCompETC1; // ETC1 texture compression support (GL_OES_compressed_ETC1_RGB8_texture, GL_WEBGL_compressed_texture_etc1) + bool texCompETC2; // ETC2/EAC texture compression support (GL_ARB_ES3_compatibility) + bool texCompPVRT; // PVR texture compression support (GL_IMG_texture_compression_pvrtc) + bool texCompASTC; // ASTC texture compression support (GL_KHR_texture_compression_astc_hdr, GL_KHR_texture_compression_astc_ldr) + bool texMirrorClamp; // Clamp mirror wrap mode supported (GL_EXT_texture_mirror_clamp) + bool texAnisoFilter; // Anisotropic texture filtering support (GL_EXT_texture_filter_anisotropic) + bool computeShader; // Compute shaders support (GL_ARB_compute_shader) + bool ssbo; // Shader storage buffer object support (GL_ARB_shader_storage_buffer_object) + + float maxAnisotropyLevel; // Maximum anisotropy level supported (minimum is 2.0f) + int maxDepthBits; // Maximum bits for depth component + + } ExtSupported; // Extensions supported flags +} rlglData; + +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 + +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( const float* matf ) +{ + glMultMatrixf( matf ); +} +#endif +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) +// Choose the current matrix to be transformed +void rlMatrixMode( int mode ) +{ + if ( mode == RL_PROJECTION ) + RLGL.State.currentMatrix = &RLGL.State.projection; + else if ( mode == RL_MODELVIEW ) + RLGL.State.currentMatrix = &RLGL.State.modelview; + // else if (mode == RL_TEXTURE) // Not supported + + RLGL.State.currentMatrixMode = mode; +} + +// Push the current matrix into RLGL.State.stack +void rlPushMatrix( void ) +{ + if ( RLGL.State.stackCounter >= RL_MAX_MATRIX_STACK_SIZE ) + TRACELOG( RL_LOG_ERROR, "RLGL: Matrix stack overflow (RL_MAX_MATRIX_STACK_SIZE)" ); + + if ( RLGL.State.currentMatrixMode == RL_MODELVIEW ) + { + RLGL.State.transformRequired = true; + RLGL.State.currentMatrix = &RLGL.State.transform; + } + + RLGL.State.stack[ RLGL.State.stackCounter ] = *RLGL.State.currentMatrix; + RLGL.State.stackCounter++; +} + +// Pop 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( const 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) +// NOTE: We store current viewport dimensions +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 ); +} + +// Define one vertex (position) +// NOTE: Vertex position data is the basic information required for drawing +void rlVertex3f( float x, float y, float z ) +{ + float tx = x; + float ty = y; + float tz = z; + + // Transform provided vector if required + if ( RLGL.State.transformRequired ) + { + tx = RLGL.State.transform.m0 * x + RLGL.State.transform.m4 * y + RLGL.State.transform.m8 * z + RLGL.State.transform.m12; + ty = RLGL.State.transform.m1 * x + RLGL.State.transform.m5 * y + RLGL.State.transform.m9 * z + RLGL.State.transform.m13; + tz = RLGL.State.transform.m2 * x + RLGL.State.transform.m6 * y + RLGL.State.transform.m10 * z + RLGL.State.transform.m14; + } + + // WARNING: We can't break primitives when launching a new batch. + // RL_LINES comes in pairs, RL_TRIANGLES come in groups of 3 vertices and RL_QUADS come in groups of 4 vertices. + // We must check current draw.mode when a new vertex is required and finish the batch only if the draw.mode draw.vertexCount is %2, %3 or %4 + if ( RLGL.State.vertexCounter > ( RLGL.currentBatch->vertexBuffer[ RLGL.currentBatch->currentBuffer ].elementCount * 4 - 4 ) ) + { + if ( ( RLGL.currentBatch->draws[ RLGL.currentBatch->drawCounter - 1 ].mode == RL_LINES ) + && ( RLGL.currentBatch->draws[ RLGL.currentBatch->drawCounter - 1 ].vertexCount % 2 == 0 ) ) + { + // Reached the maximum number of vertices for RL_LINES drawing + // Launch a draw call but keep current state for next vertices comming + // NOTE: We add +1 vertex to the check for security + rlCheckRenderBatchLimit( 2 + 1 ); + } + else if ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_TRIANGLES) && + (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%3 == 0)) + { + rlCheckRenderBatchLimit( 3 + 1 ); + } + else if ((RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].mode == RL_QUADS) && + (RLGL.currentBatch->draws[RLGL.currentBatch->drawCounter - 1].vertexCount%4 == 0)) + { + rlCheckRenderBatchLimit( 4 + 1 ); + } + } + + // Add vertices + RLGL.currentBatch->vertexBuffer[ RLGL.currentBatch->currentBuffer ].vertices[ 3 * RLGL.State.vertexCounter ] = tx; + RLGL.currentBatch->vertexBuffer[ RLGL.currentBatch->currentBuffer ].vertices[ 3 * RLGL.State.vertexCounter + 1 ] = ty; + RLGL.currentBatch->vertexBuffer[ RLGL.currentBatch->currentBuffer ].vertices[ 3 * RLGL.State.vertexCounter + 2 ] = tz; + + // Add current texcoord + RLGL.currentBatch->vertexBuffer[ RLGL.currentBatch->currentBuffer ].texcoords[ 2 * RLGL.State.vertexCounter ] = RLGL.State.texcoordx; + RLGL.currentBatch->vertexBuffer[ RLGL.currentBatch->currentBuffer ].texcoords[ 2 * RLGL.State.vertexCounter + 1 ] = RLGL.State.texcoordy; + + // WARNING: By default rlVertexBuffer struct 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++; +} + +// 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 ); + +#if ! defined( GRAPHICS_API_OPENGL_11 ) + // Reset anisotropy filter, in case it was set + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f ); +#endif + + 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, ( int )RLGL.ExtSupported.maxAnisotropyLevel ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, ( float )value ); + } + else + TRACELOG( RL_LOG_WARNING, "GL: Anisotropic filtering not supported" ); +#endif + } + break; +#if defined( GRAPHICS_API_OPENGL_33 ) + case RL_TEXTURE_MIPMAP_BIAS_RATIO : + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, value / 100.0f ); +#endif + default : + break; + } + + glBindTexture( GL_TEXTURE_2D, 0 ); +} + +// Set cubemap parameters (wrap mode/filter mode) +void rlCubemapParameters( unsigned int id, int param, int value ) +{ +#if ! defined( GRAPHICS_API_OPENGL_11 ) + glBindTexture( GL_TEXTURE_CUBE_MAP, id ); + + // Reset anisotropy filter, in case it was set + glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f ); + + switch ( param ) + { + case RL_TEXTURE_WRAP_S : + case RL_TEXTURE_WRAP_T : + { + if ( value == RL_TEXTURE_WRAP_MIRROR_CLAMP ) + { + if ( RLGL.ExtSupported.texMirrorClamp ) + glTexParameteri( GL_TEXTURE_CUBE_MAP, param, value ); + else + TRACELOG( RL_LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)" ); + } + else + glTexParameteri( GL_TEXTURE_CUBE_MAP, param, value ); + } + break; + case RL_TEXTURE_MAG_FILTER : + case RL_TEXTURE_MIN_FILTER : + glTexParameteri( GL_TEXTURE_CUBE_MAP, param, value ); + break; + case RL_TEXTURE_FILTER_ANISOTROPIC : + { + if ( value <= RLGL.ExtSupported.maxAnisotropyLevel ) + glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, ( float )value ); + else if ( RLGL.ExtSupported.maxAnisotropyLevel > 0.0f ) + { + TRACELOG( RL_LOG_WARNING, "GL: Maximum anisotropic filter level supported is %iX", id, ( int )RLGL.ExtSupported.maxAnisotropyLevel ); + glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, ( float )value ); + } + else + TRACELOG( RL_LOG_WARNING, "GL: Anisotropic filtering not supported" ); + } + break; +#if defined( GRAPHICS_API_OPENGL_33 ) + case RL_TEXTURE_MIPMAP_BIAS_RATIO : + glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_LOD_BIAS, value / 100.0f ); +#endif + default : + break; + } + + glBindTexture( GL_TEXTURE_CUBE_MAP, 0 ); +#endif +} + +// Enable shader program +void rlEnableShader( unsigned int id ) +{ +#if ( defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) ) + glUseProgram( id ); +#endif +} + +// Disable shader program +void rlDisableShader( void ) +{ +#if ( defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) ) + glUseProgram( 0 ); +#endif +} + +// Enable rendering to texture (fbo) +void rlEnableFramebuffer( unsigned int id ) +{ +#if ( defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) ) && defined( 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( GRAPHICS_API_OPENGL_ES3 ) ) && 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 ] = { +#if defined( GRAPHICS_API_OPENGL_ES3 ) + GL_COLOR_ATTACHMENT0_EXT, + GL_COLOR_ATTACHMENT1_EXT, + GL_COLOR_ATTACHMENT2_EXT, + GL_COLOR_ATTACHMENT3_EXT, + GL_COLOR_ATTACHMENT4_EXT, + GL_COLOR_ATTACHMENT5_EXT, + GL_COLOR_ATTACHMENT6_EXT, + GL_COLOR_ATTACHMENT7_EXT, +#else + GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, + GL_COLOR_ATTACHMENT2, + GL_COLOR_ATTACHMENT3, + GL_COLOR_ATTACHMENT4, + GL_COLOR_ATTACHMENT5, + GL_COLOR_ATTACHMENT6, + GL_COLOR_ATTACHMENT7, +#endif + }; + +#if defined( GRAPHICS_API_OPENGL_ES3 ) + glDrawBuffersEXT( count, buffers ); +#else + glDrawBuffers( count, buffers ); +#endif + } + } + 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 ); +} + +// Set face culling mode +void rlSetCullFace( int mode ) +{ + switch ( mode ) + { + case RL_CULL_FACE_BACK : + glCullFace( GL_BACK ); + break; + case RL_CULL_FACE_FRONT : + glCullFace( GL_FRONT ); + break; + default : + break; + } +} + +// Enable scissor test +void rlEnableScissorTest( void ) +{ + glEnable( GL_SCISSOR_TEST ); +} + +// Disable scissor test +void rlDisableScissorTest( void ) +{ + glDisable( GL_SCISSOR_TEST ); +} + +// Scissor test +void rlScissor( int x, int y, int width, int height ) +{ + glScissor( x, y, width, height ); +} + +// Enable wire mode +void rlEnableWireMode( void ) +{ +#if defined( GRAPHICS_API_OPENGL_11 ) || defined( GRAPHICS_API_OPENGL_33 ) + // NOTE: glPolygonMode() not available on OpenGL ES + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); +#endif +} + +// Disable wire mode +void rlDisableWireMode( void ) +{ +#if defined( GRAPHICS_API_OPENGL_11 ) || defined( GRAPHICS_API_OPENGL_33 ) + // NOTE: glPolygonMode() not available on OpenGL ES + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); +#endif +} + +// 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 ) + || ( ( mode == RL_BLEND_CUSTOM || mode == RL_BLEND_CUSTOM_SEPARATE ) && RLGL.State.glCustomBlendModeModified ) ) + { + rlDrawRenderBatch( RLGL.currentBatch ); + + switch ( mode ) + { + case RL_BLEND_ALPHA : + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + glBlendEquation( GL_FUNC_ADD ); + break; + case RL_BLEND_ADDITIVE : + glBlendFunc( GL_SRC_ALPHA, GL_ONE ); + glBlendEquation( GL_FUNC_ADD ); + break; + case RL_BLEND_MULTIPLIED : + glBlendFunc( GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA ); + glBlendEquation( GL_FUNC_ADD ); + break; + case RL_BLEND_ADD_COLORS : + glBlendFunc( GL_ONE, GL_ONE ); + glBlendEquation( GL_FUNC_ADD ); + break; + case RL_BLEND_SUBTRACT_COLORS : + glBlendFunc( GL_ONE, GL_ONE ); + glBlendEquation( GL_FUNC_SUBTRACT ); + break; + case RL_BLEND_ALPHA_PREMULTIPLY : + glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA ); + glBlendEquation( GL_FUNC_ADD ); + break; + case RL_BLEND_CUSTOM : + { + // NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactors() + glBlendFunc( RLGL.State.glBlendSrcFactor, RLGL.State.glBlendDstFactor ); + glBlendEquation( RLGL.State.glBlendEquation ); + } + break; + case RL_BLEND_CUSTOM_SEPARATE : + { + // NOTE: Using GL blend src/dst factors and GL equation configured with rlSetBlendFactorsSeparate() + glBlendFuncSeparate( + RLGL.State.glBlendSrcFactorRGB, + RLGL.State.glBlendDestFactorRGB, + RLGL.State.glBlendSrcFactorAlpha, + RLGL.State.glBlendDestFactorAlpha + ); + glBlendEquationSeparate( RLGL.State.glBlendEquationRGB, RLGL.State.glBlendEquationAlpha ); + } + break; + default : + break; + } + + RLGL.State.currentBlendMode = mode; + RLGL.State.glCustomBlendModeModified = false; + } +#endif +} + +// Set blending mode factor and equation +void rlSetBlendFactors( int glSrcFactor, int glDstFactor, int glEquation ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + if ( ( RLGL.State.glBlendSrcFactor != glSrcFactor ) || ( RLGL.State.glBlendDstFactor != glDstFactor ) || ( RLGL.State.glBlendEquation != glEquation ) ) + { + RLGL.State.glBlendSrcFactor = glSrcFactor; + RLGL.State.glBlendDstFactor = glDstFactor; + RLGL.State.glBlendEquation = glEquation; + + RLGL.State.glCustomBlendModeModified = true; + } +#endif +} + +// Set blending mode factor and equation separately for RGB and alpha +void rlSetBlendFactorsSeparate( int glSrcRGB, int glDstRGB, int glSrcAlpha, int glDstAlpha, int glEqRGB, int glEqAlpha ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + if ( ( RLGL.State.glBlendSrcFactorRGB != glSrcRGB ) || ( RLGL.State.glBlendDestFactorRGB != glDstRGB ) || ( RLGL.State.glBlendSrcFactorAlpha != glSrcAlpha ) + || ( RLGL.State.glBlendDestFactorAlpha != glDstAlpha ) || ( RLGL.State.glBlendEquationRGB != glEqRGB ) + || ( RLGL.State.glBlendEquationAlpha != glEqAlpha ) ) + { + RLGL.State.glBlendSrcFactorRGB = glSrcRGB; + RLGL.State.glBlendDestFactorRGB = glDstRGB; + RLGL.State.glBlendSrcFactorAlpha = glSrcAlpha; + RLGL.State.glBlendDestFactorAlpha = glDstAlpha; + RLGL.State.glBlendEquationRGB = glEqRGB; + RLGL.State.glBlendEquationAlpha = glEqAlpha; + + RLGL.State.glCustomBlendModeModified = true; + } +#endif +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition - OpenGL Debug +//---------------------------------------------------------------------------------- +#if defined( 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); + + // 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 ( gladLoadGL( ( GLADloadfunc )loader ) == 0 ) + TRACELOG( RL_LOG_WARNING, "GLAD: Cannot load OpenGL extensions" ); + else + TRACELOG( RL_LOG_INFO, "GLAD: OpenGL extensions loaded successfully" ); + + // Get number of supported extensions + GLint numExt = 0; + glGetIntegerv( GL_NUM_EXTENSIONS, &numExt ); + TRACELOG( RL_LOG_INFO, "GL: Supported extensions count: %i", numExt ); + +#if 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 + +#if defined( GRAPHICS_API_OPENGL_21 ) + // Register supported extensions flags + // Optional OpenGL 2.1 extensions + RLGL.ExtSupported.vao = GLAD_GL_ARB_vertex_array_object; + RLGL.ExtSupported.instancing = ( GLAD_GL_EXT_draw_instanced && GLAD_GL_ARB_instanced_arrays ); + RLGL.ExtSupported.texNPOT = GLAD_GL_ARB_texture_non_power_of_two; + RLGL.ExtSupported.texFloat32 = GLAD_GL_ARB_texture_float; + RLGL.ExtSupported.texFloat16 = GLAD_GL_ARB_texture_float; + RLGL.ExtSupported.texDepth = GLAD_GL_ARB_depth_texture; + RLGL.ExtSupported.maxDepthBits = 32; + RLGL.ExtSupported.texAnisoFilter = GLAD_GL_EXT_texture_filter_anisotropic; + RLGL.ExtSupported.texMirrorClamp = GLAD_GL_EXT_texture_mirror_clamp; +#else + // Register supported extensions flags + // OpenGL 3.3 extensions supported by default (core) + RLGL.ExtSupported.vao = true; + RLGL.ExtSupported.instancing = true; + RLGL.ExtSupported.texNPOT = true; + RLGL.ExtSupported.texFloat32 = true; + RLGL.ExtSupported.texFloat16 = true; + RLGL.ExtSupported.texDepth = true; + RLGL.ExtSupported.maxDepthBits = 32; + RLGL.ExtSupported.texAnisoFilter = true; + RLGL.ExtSupported.texMirrorClamp = true; +#endif + + // Optional OpenGL 3.3 extensions + RLGL.ExtSupported.texCompASTC = GLAD_GL_KHR_texture_compression_astc_hdr && GLAD_GL_KHR_texture_compression_astc_ldr; + RLGL.ExtSupported.texCompDXT = GLAD_GL_EXT_texture_compression_s3tc; // Texture compression: DXT + RLGL.ExtSupported.texCompETC2 = GLAD_GL_ARB_ES3_compatibility; // Texture compression: ETC2/EAC +#if defined( GRAPHICS_API_OPENGL_43 ) + RLGL.ExtSupported.computeShader = GLAD_GL_ARB_compute_shader; + RLGL.ExtSupported.ssbo = GLAD_GL_ARB_shader_storage_buffer_object; +#endif + +#endif // GRAPHICS_API_OPENGL_33 + +#if defined( GRAPHICS_API_OPENGL_ES3 ) + // Register supported extensions flags + // OpenGL ES 3.0 extensions supported by default + RLGL.ExtSupported.vao = true; + RLGL.ExtSupported.instancing = true; + RLGL.ExtSupported.texNPOT = true; + RLGL.ExtSupported.texFloat32 = true; + RLGL.ExtSupported.texFloat16 = true; + RLGL.ExtSupported.texDepth = true; + RLGL.ExtSupported.texDepthWebGL = true; + RLGL.ExtSupported.maxDepthBits = 24; + RLGL.ExtSupported.texAnisoFilter = true; + RLGL.ExtSupported.texMirrorClamp = true; + // TODO: Make sure that the ones above are actually present by default + // TODO: Check for these... + // RLGL.ExtSupported.texCompDXT + // RLGL.ExtSupported.texCompETC1 + // RLGL.ExtSupported.texCompETC2 + // RLGL.ExtSupported.texCompPVRT + // RLGL.ExtSupported.texCompASTC + // RLGL.ExtSupported.computeShader + // RLGL.ExtSupported.ssbo + // RLGL.ExtSupported.maxAnisotropyLevel +#elif defined( GRAPHICS_API_OPENGL_ES2 ) + +#if defined( PLATFORM_DESKTOP ) + // TODO: Support OpenGL ES 3.0 + if ( gladLoadGLES2( ( GLADloadfunc )loader ) == 0 ) + TRACELOG( RL_LOG_WARNING, "GLAD: Cannot load OpenGL ES2.0 functions" ); + else + TRACELOG( RL_LOG_INFO, "GLAD: OpenGL ES 2.0 loaded successfully" ); +#endif + + // Get supported extensions list + GLint numExt = 0; + const char** extList = 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; + if ( strcmp( extList[ i ], ( const char* )"GL_OES_texture_half_float" ) == 0 ) + RLGL.ExtSupported.texFloat16 = true; + + // Check depth texture support + if ( strcmp( extList[ i ], ( const char* )"GL_OES_depth_texture" ) == 0 ) + RLGL.ExtSupported.texDepth = true; + if ( strcmp( extList[ i ], ( const char* )"GL_WEBGL_depth_texture" ) == 0 ) + RLGL.ExtSupported.texDepthWebGL = true; // WebGL requires unsized internal format + if ( RLGL.ExtSupported.texDepthWebGL ) + RLGL.ExtSupported.texDepth = true; + + if ( strcmp( extList[ i ], ( const char* )"GL_OES_depth24" ) == 0 ) + RLGL.ExtSupported.maxDepthBits = 24; // Not available on WebGL + if ( strcmp( extList[ i ], ( const char* )"GL_OES_depth32" ) == 0 ) + RLGL.ExtSupported.maxDepthBits = 32; // Not available on WebGL + + // Check texture compression support: DXT + if ( ( strcmp( extList[ i ], ( const char* )"GL_EXT_texture_compression_s3tc" ) == 0 ) + || ( strcmp( extList[ i ], ( const char* )"GL_WEBGL_compressed_texture_s3tc" ) == 0 ) + || ( strcmp( extList[ i ], ( const char* )"GL_WEBKIT_WEBGL_compressed_texture_s3tc" ) == 0 ) ) + RLGL.ExtSupported.texCompDXT = true; + + // Check texture compression support: ETC1 + if ( ( strcmp( extList[ i ], ( const char* )"GL_OES_compressed_ETC1_RGB8_texture" ) == 0 ) + || ( strcmp( extList[ i ], ( const char* )"GL_WEBGL_compressed_texture_etc1" ) == 0 ) ) + RLGL.ExtSupported.texCompETC1 = true; + + // Check texture compression support: ETC2/EAC + if ( strcmp( extList[ i ], ( const char* )"GL_ARB_ES3_compatibility" ) == 0 ) + RLGL.ExtSupported.texCompETC2 = true; + + // Check texture compression support: PVR + if ( strcmp( extList[ i ], ( const char* )"GL_IMG_texture_compression_pvrtc" ) == 0 ) + RLGL.ExtSupported.texCompPVRT = true; + + // Check texture compression support: ASTC + if ( strcmp( extList[ i ], ( const char* )"GL_KHR_texture_compression_astc_hdr" ) == 0 ) + RLGL.ExtSupported.texCompASTC = true; + + // Check anisotropic texture filter support + if ( strcmp( extList[ i ], ( const char* )"GL_EXT_texture_filter_anisotropic" ) == 0 ) + RLGL.ExtSupported.texAnisoFilter = true; + + // Check clamp mirror wrap mode support + if ( strcmp( extList[ i ], ( const char* )"GL_EXT_texture_mirror_clamp" ) == 0 ) + RLGL.ExtSupported.texMirrorClamp = true; + } + + // Free extensions pointers + RL_FREE( extList ); + RL_FREE( extensionsDup ); // Duplicated string must be deallocated +#endif // GRAPHICS_API_OPENGL_ES2 + + // Check OpenGL information and capabilities + //------------------------------------------------------------------------------ + // Show current OpenGL and GLSL version + TRACELOG( RL_LOG_INFO, "GL: OpenGL device information:" ); + TRACELOG( RL_LOG_INFO, " > Vendor: %s", glGetString( GL_VENDOR ) ); + TRACELOG( RL_LOG_INFO, " > Renderer: %s", glGetString( GL_RENDERER ) ); + TRACELOG( RL_LOG_INFO, " > Version: %s", glGetString( GL_VERSION ) ); + TRACELOG( RL_LOG_INFO, " > GLSL: %s", glGetString( GL_SHADING_LANGUAGE_VERSION ) ); + +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) +// 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 ); + +#if defined( GRAPHICS_API_OPENGL_43 ) + glGetIntegerv( GL_MAX_VERTEX_ATTRIB_BINDINGS, &capability ); + TRACELOG( RL_LOG_INFO, " GL_MAX_VERTEX_ATTRIB_BINDINGS: %i", capability ); + glGetIntegerv( GL_MAX_UNIFORM_LOCATIONS, &capability ); + TRACELOG( RL_LOG_INFO, " GL_MAX_UNIFORM_LOCATIONS: %i", capability ); +#endif // GRAPHICS_API_OPENGL_43 +#else // RLGL_SHOW_GL_DETAILS_INFO + + // Show some basic info about GL supported features + if ( RLGL.ExtSupported.vao ) + TRACELOG( RL_LOG_INFO, "GL: VAO extension detected, VAO functions loaded successfully" ); + else + TRACELOG( RL_LOG_WARNING, "GL: VAO extension not found, VAO not supported" ); + if ( RLGL.ExtSupported.texNPOT ) + TRACELOG( RL_LOG_INFO, "GL: NPOT textures extension detected, full NPOT textures supported" ); + else + TRACELOG( RL_LOG_WARNING, "GL: NPOT textures extension not found, limited NPOT support (no-mipmaps, no-repeat)" ); + if ( RLGL.ExtSupported.texCompDXT ) + TRACELOG( RL_LOG_INFO, "GL: DXT compressed textures supported" ); + if ( RLGL.ExtSupported.texCompETC1 ) + TRACELOG( RL_LOG_INFO, "GL: ETC1 compressed textures supported" ); + if ( RLGL.ExtSupported.texCompETC2 ) + TRACELOG( RL_LOG_INFO, "GL: ETC2/EAC compressed textures supported" ); + if ( RLGL.ExtSupported.texCompPVRT ) + TRACELOG( RL_LOG_INFO, "GL: PVRT compressed textures supported" ); + if ( RLGL.ExtSupported.texCompASTC ) + TRACELOG( RL_LOG_INFO, "GL: ASTC compressed textures supported" ); + if ( RLGL.ExtSupported.computeShader ) + TRACELOG( RL_LOG_INFO, "GL: Compute shaders supported" ); + if ( RLGL.ExtSupported.ssbo ) + TRACELOG( RL_LOG_INFO, "GL: Shader storage buffer objects supported" ); +#endif // 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 = RL_OPENGL_11; +#endif +#if defined( GRAPHICS_API_OPENGL_21 ) + glVersion = RL_OPENGL_21; +#elif defined( GRAPHICS_API_OPENGL_43 ) + glVersion = RL_OPENGL_43; +#elif defined( GRAPHICS_API_OPENGL_33 ) + glVersion = RL_OPENGL_33; +#endif +#if defined( GRAPHICS_API_OPENGL_ES3 ) + glVersion = RL_OPENGL_ES_30; +#elif defined( GRAPHICS_API_OPENGL_ES2 ) + glVersion = RL_OPENGL_ES_20; +#endif + + return glVersion; +} + +// Set current framebuffer width +void rlSetFramebufferWidth( int width ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + RLGL.State.framebufferWidth = width; +#endif +} + +// Set current framebuffer height +void rlSetFramebufferHeight( int height ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + RLGL.State.framebufferHeight = height; +#endif +} + +// Get default framebuffer width +int rlGetFramebufferWidth( void ) +{ + int width = 0; +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + width = RLGL.State.framebufferWidth; +#endif + return width; +} + +// Get default framebuffer height +int rlGetFramebufferHeight( void ) +{ + int height = 0; +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + height = RLGL.State.framebufferHeight; +#endif + return height; +} + +// Get default internal texture (white texture) +// NOTE: Default texture is a 1x1 pixel UNCOMPRESSED_R8G8B8A8 +unsigned int rlGetTextureIdDefault( void ) +{ + unsigned int id = 0; +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + id = RLGL.State.defaultTextureId; +#endif + return id; +} + +// Get default shader id +unsigned int rlGetShaderIdDefault( void ) +{ + unsigned int id = 0; +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + id = RLGL.State.defaultShaderId; +#endif + return id; +} + +// Get default shader locs +int* rlGetShaderLocsDefault( void ) +{ + int* locs = NULL; +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + locs = RLGL.State.defaultShaderLocs; +#endif + return locs; +} + +// Render batch management +//------------------------------------------------------------------------------------------------ +// Load render batch +rlRenderBatch rlLoadRenderBatch( int numBuffers, int bufferElements ) +{ + rlRenderBatch batch = { 0 }; + +#if 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 (use a change detector flag?) + 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 Bound to sampler2D texture0 by default + glBindTexture( GL_TEXTURE_2D, batch->draws[ i ].textureId ); + + if ( ( batch->draws[ i ].mode == RL_LINES ) || ( batch->draws[ i ].mode == RL_TRIANGLES ) ) + glDrawArrays( batch->draws[ i ].mode, vertexOffset, batch->draws[ i ].vertexCount ); + else + { +#if defined( GRAPHICS_API_OPENGL_33 ) + // 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 + } + + // Restore viewport to default measures + if ( eyeCount == 2 ) + rlViewport( 0, 0, RLGL.State.framebufferWidth, RLGL.State.framebufferHeight ); + //------------------------------------------------------------------------------------------------------------ + + // Reset batch buffers + //------------------------------------------------------------------------------------------------------------ + // Reset vertex counter for next frame + RLGL.State.vertexCounter = 0; + + // Reset depth for next draw + batch->currentDepth = -1.0f; + + // Restore projection/modelview matrices + RLGL.State.projection = matProjection; + RLGL.State.modelview = matModelView; + + // Reset RLGL.currentBatch->draws array + for ( int i = 0; i < RL_DEFAULT_BATCH_DRAWCALLS; i++ ) + { + batch->draws[ i ].mode = RL_QUADS; + batch->draws[ i ].vertexCount = 0; + batch->draws[ i ].textureId = RLGL.State.defaultTextureId; + } + + // Reset active texture units for next batch + for ( int i = 0; i < RL_DEFAULT_BATCH_MAX_TEXTURE_UNITS; i++ ) + RLGL.State.activeTextureId[ i ] = 0; + + // Reset draws counter to one draw for the batch + batch->drawCounter = 1; + //------------------------------------------------------------------------------------------------------------ + + // Change to next buffer in the list (in case of multi-buffering) + batch->currentBuffer++; + if ( batch->currentBuffer >= batch->bufferCount ) + batch->currentBuffer = 0; +#endif +} + +// Set the active render batch for rlgl +void rlSetRenderBatchActive( rlRenderBatch* batch ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + rlDrawRenderBatch( RLGL.currentBatch ); + + if ( batch != NULL ) + RLGL.currentBatch = batch; + else + RLGL.currentBatch = &RLGL.defaultBatch; +#endif +} + +// Update and draw internal render batch +void rlDrawRenderBatchActive( void ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + rlDrawRenderBatch( RLGL.currentBatch ); // NOTE: Stereo rendering is checked inside +#endif +} + +// Check internal buffer overflow for a given number of vertex +// and force a rlRenderBatch draw call if required +bool rlCheckRenderBatchLimit( int vCount ) +{ + bool overflow = false; + +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + if ( ( RLGL.State.vertexCounter + vCount ) >= ( RLGL.currentBatch->vertexBuffer[ RLGL.currentBatch->currentBuffer ].elementCount * 4 ) ) + { + overflow = true; + + // Store current primitive drawing mode and texture id + int currentMode = RLGL.currentBatch->draws[ RLGL.currentBatch->drawCounter - 1 ].mode; + int currentTexture = RLGL.currentBatch->draws[ RLGL.currentBatch->drawCounter - 1 ].textureId; + + rlDrawRenderBatch( RLGL.currentBatch ); // NOTE: Stereo rendering is checked inside + + // Restore state of last batch so 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( const void* data, int width, int height, int format, int mipmapCount ) +{ + unsigned int id = 0; + + glBindTexture( GL_TEXTURE_2D, 0 ); // Free any old binding + + // Check texture format support by OpenGL 1.1 (compressed textures not supported) +#if defined( GRAPHICS_API_OPENGL_11 ) + if ( format >= RL_PIXELFORMAT_COMPRESSED_DXT1_RGB ) + { + TRACELOG( RL_LOG_WARNING, "GL: OpenGL 1.1 does not support GPU compressed texture formats" ); + return id; + } +#else + if ( ( ! RLGL.ExtSupported.texCompDXT ) + && ( ( format == RL_PIXELFORMAT_COMPRESSED_DXT1_RGB ) || ( format == RL_PIXELFORMAT_COMPRESSED_DXT1_RGBA ) + || ( format == RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA ) || ( format == RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA ) ) ) + { + TRACELOG( RL_LOG_WARNING, "GL: DXT compressed texture format not supported" ); + return id; + } +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + if ( ( ! RLGL.ExtSupported.texCompETC1 ) && ( format == RL_PIXELFORMAT_COMPRESSED_ETC1_RGB ) ) + { + TRACELOG( RL_LOG_WARNING, "GL: ETC1 compressed texture format not supported" ); + return id; + } + + if ( ( ! RLGL.ExtSupported.texCompETC2 ) && ( ( format == RL_PIXELFORMAT_COMPRESSED_ETC2_RGB ) || ( format == RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA ) ) ) + { + TRACELOG( RL_LOG_WARNING, "GL: ETC2 compressed texture format not supported" ); + return id; + } + + if ( ( ! RLGL.ExtSupported.texCompPVRT ) && ( ( format == RL_PIXELFORMAT_COMPRESSED_PVRT_RGB ) || ( format == RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA ) ) ) + { + TRACELOG( RL_LOG_WARNING, "GL: PVRT compressed texture format not supported" ); + return id; + } + + if ( ( ! RLGL.ExtSupported.texCompASTC ) + && ( ( format == RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA ) || ( format == RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA ) ) ) + { + TRACELOG( RL_LOG_WARNING, "GL: ASTC compressed texture format not supported" ); + return id; + } +#endif +#endif // GRAPHICS_API_OPENGL_11 + + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + + glGenTextures( 1, &id ); // Generate texture id + + glBindTexture( GL_TEXTURE_2D, id ); + + int mipWidth = width; + int mipHeight = height; + int mipOffset = 0; // Mipmap data offset, only used for tracelog + + // NOTE: Added pointer math separately from function to avoid UBSAN complaining + unsigned char* dataPtr = NULL; + if ( data != NULL ) + dataPtr = ( unsigned char* )data; + + // Load the different mipmap levels + for ( int i = 0; i < mipmapCount; i++ ) + { + unsigned int mipSize = rlGetPixelDataSize( mipWidth, mipHeight, format ); + + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats( format, &glInternalFormat, &glFormat, &glType ); + + TRACELOGD( "TEXTURE: Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset ); + + if ( glInternalFormat != 0 ) + { + if ( format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB ) + glTexImage2D( GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, glFormat, glType, dataPtr ); +#if ! defined( GRAPHICS_API_OPENGL_11 ) + else + glCompressedTexImage2D( GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, mipSize, dataPtr ); +#endif + +#if defined( GRAPHICS_API_OPENGL_33 ) + if ( format == RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE ) + { + GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE }; + glTexParameteriv( GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask ); + } + else if ( format == RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA ) + { +#if defined( GRAPHICS_API_OPENGL_21 ) + GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ALPHA }; +#elif defined( GRAPHICS_API_OPENGL_33 ) + GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN }; +#endif + glTexParameteriv( GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask ); + } +#endif + } + + mipWidth /= 2; + mipHeight /= 2; + mipOffset += mipSize; // Increment offset position to next mipmap + if ( data != NULL ) + dataPtr += mipSize; // Increment data pointer to next mipmap + + // Security check for NPOT textures + if ( mipWidth < 1 ) + mipWidth = 1; + if ( mipHeight < 1 ) + mipHeight = 1; + } + + // Texture parameters configuration + // NOTE: glTexParameteri does NOT affect texture uploading, 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 and WebGL requires 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 ) || defined( GRAPHICS_API_OPENGL_ES3 ) ) + // WARNING: WebGL platform requires unsized internal format definition (GL_DEPTH_COMPONENT) + // while other platforms using OpenGL ES 2.0 require/support sized internal formats depending on the GPU capabilities + if ( ! RLGL.ExtSupported.texDepthWebGL || useRenderBuffer ) + { + if ( RLGL.ExtSupported.maxDepthBits == 32 ) + glInternalFormat = GL_DEPTH_COMPONENT32_OES; + else if ( RLGL.ExtSupported.maxDepthBits == 24 ) + glInternalFormat = GL_DEPTH_COMPONENT24_OES; + else + glInternalFormat = GL_DEPTH_COMPONENT16; + } +#endif + + if ( ! 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( const 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 ); + + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats( format, &glInternalFormat, &glFormat, &glType ); + + if ( glInternalFormat != 0 ) + { + // 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_R32 ) || ( format == RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32 ) + || ( format == RL_PIXELFORMAT_UNCOMPRESSED_R16 ) || ( format == RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16 ) ) + TRACELOG( RL_LOG_WARNING, "TEXTURES: Cubemap requested format not supported" ); + else + glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X + 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 ); + + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats( format, &glInternalFormat, &glFormat, &glType ); + + if ( ( glInternalFormat != 0 ) && ( format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB ) ) + { + glTexSubImage2D( GL_TEXTURE_2D, 0, offsetX, offsetY, width, height, glFormat, glType, data ); + } + else + TRACELOG( RL_LOG_WARNING, "TEXTURE: [ID %i] Failed to update for current texture format (%i)", id, format ); +} + +// Get OpenGL internal formats and data type from raylib PixelFormat +void rlGetGlTextureFormats( int format, unsigned int* glInternalFormat, unsigned int* glFormat, unsigned int* glType ) +{ + *glInternalFormat = 0; + *glFormat = 0; + *glType = 0; + + switch ( format ) + { +#if defined( GRAPHICS_API_OPENGL_11 ) || defined( GRAPHICS_API_OPENGL_21 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + // NOTE: on OpenGL ES 2.0 (WebGL), internalFormat must match format and options allowed are: GL_LUMINANCE, GL_RGB, GL_RGBA + case RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE : + *glInternalFormat = GL_LUMINANCE; + *glFormat = GL_LUMINANCE; + *glType = GL_UNSIGNED_BYTE; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA : + *glInternalFormat = GL_LUMINANCE_ALPHA; + *glFormat = GL_LUMINANCE_ALPHA; + *glType = GL_UNSIGNED_BYTE; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R5G6B5 : + *glInternalFormat = GL_RGB; + *glFormat = GL_RGB; + *glType = GL_UNSIGNED_SHORT_5_6_5; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8 : + *glInternalFormat = GL_RGB; + *glFormat = GL_RGB; + *glType = GL_UNSIGNED_BYTE; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1 : + *glInternalFormat = GL_RGBA; + *glFormat = GL_RGBA; + *glType = GL_UNSIGNED_SHORT_5_5_5_1; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4 : + *glInternalFormat = GL_RGBA; + *glFormat = GL_RGBA; + *glType = GL_UNSIGNED_SHORT_4_4_4_4; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 : + *glInternalFormat = GL_RGBA; + *glFormat = GL_RGBA; + *glType = GL_UNSIGNED_BYTE; + break; +#if ! defined( GRAPHICS_API_OPENGL_11 ) +#if defined( GRAPHICS_API_OPENGL_ES3 ) + case RL_PIXELFORMAT_UNCOMPRESSED_R32 : + if ( RLGL.ExtSupported.texFloat32 ) + *glInternalFormat = GL_R32F_EXT; + *glFormat = GL_RED_EXT; + *glType = GL_FLOAT; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32 : + if ( RLGL.ExtSupported.texFloat32 ) + *glInternalFormat = GL_RGB32F_EXT; + *glFormat = GL_RGB; + *glType = GL_FLOAT; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32 : + if ( RLGL.ExtSupported.texFloat32 ) + *glInternalFormat = GL_RGBA32F_EXT; + *glFormat = GL_RGBA; + *glType = GL_FLOAT; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16 : + if ( RLGL.ExtSupported.texFloat16 ) + *glInternalFormat = GL_R16F_EXT; + *glFormat = GL_RED_EXT; + *glType = GL_HALF_FLOAT; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16 : + if ( RLGL.ExtSupported.texFloat16 ) + *glInternalFormat = GL_RGB16F_EXT; + *glFormat = GL_RGB; + *glType = GL_HALF_FLOAT; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16 : + if ( RLGL.ExtSupported.texFloat16 ) + *glInternalFormat = GL_RGBA16F_EXT; + *glFormat = GL_RGBA; + *glType = GL_HALF_FLOAT; + break; +#else + case RL_PIXELFORMAT_UNCOMPRESSED_R32 : + if ( RLGL.ExtSupported.texFloat32 ) + *glInternalFormat = GL_LUMINANCE; + *glFormat = GL_LUMINANCE; + *glType = GL_FLOAT; + break; // NOTE: Requires extension OES_texture_float + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32 : + if ( RLGL.ExtSupported.texFloat32 ) + *glInternalFormat = GL_RGB; + *glFormat = GL_RGB; + *glType = GL_FLOAT; + break; // NOTE: Requires extension OES_texture_float + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32 : + if ( RLGL.ExtSupported.texFloat32 ) + *glInternalFormat = GL_RGBA; + *glFormat = GL_RGBA; + *glType = GL_FLOAT; + break; // NOTE: Requires extension OES_texture_float +#if defined( GRAPHICS_API_OPENGL_21 ) + case RL_PIXELFORMAT_UNCOMPRESSED_R16 : + if ( RLGL.ExtSupported.texFloat16 ) + *glInternalFormat = GL_LUMINANCE; + *glFormat = GL_LUMINANCE; + *glType = GL_HALF_FLOAT_ARB; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16 : + if ( RLGL.ExtSupported.texFloat16 ) + *glInternalFormat = GL_RGB; + *glFormat = GL_RGB; + *glType = GL_HALF_FLOAT_ARB; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16 : + if ( RLGL.ExtSupported.texFloat16 ) + *glInternalFormat = GL_RGBA; + *glFormat = GL_RGBA; + *glType = GL_HALF_FLOAT_ARB; + break; +#else // defined(GRAPHICS_API_OPENGL_ES2) + case RL_PIXELFORMAT_UNCOMPRESSED_R16 : + if ( RLGL.ExtSupported.texFloat16 ) + *glInternalFormat = GL_LUMINANCE; + *glFormat = GL_LUMINANCE; + *glType = GL_HALF_FLOAT_OES; + break; // NOTE: Requires extension OES_texture_half_float + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16 : + if ( RLGL.ExtSupported.texFloat16 ) + *glInternalFormat = GL_RGB; + *glFormat = GL_RGB; + *glType = GL_HALF_FLOAT_OES; + break; // NOTE: Requires extension OES_texture_half_float + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16 : + if ( RLGL.ExtSupported.texFloat16 ) + *glInternalFormat = GL_RGBA; + *glFormat = GL_RGBA; + *glType = GL_HALF_FLOAT_OES; + break; // NOTE: Requires extension OES_texture_half_float +#endif +#endif +#endif +#elif defined( GRAPHICS_API_OPENGL_33 ) + case RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE : + *glInternalFormat = GL_R8; + *glFormat = GL_RED; + *glType = GL_UNSIGNED_BYTE; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA : + *glInternalFormat = GL_RG8; + *glFormat = GL_RG; + *glType = GL_UNSIGNED_BYTE; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R5G6B5 : + *glInternalFormat = GL_RGB565; + *glFormat = GL_RGB; + *glType = GL_UNSIGNED_SHORT_5_6_5; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8 : + *glInternalFormat = GL_RGB8; + *glFormat = GL_RGB; + *glType = GL_UNSIGNED_BYTE; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1 : + *glInternalFormat = GL_RGB5_A1; + *glFormat = GL_RGBA; + *glType = GL_UNSIGNED_SHORT_5_5_5_1; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4 : + *glInternalFormat = GL_RGBA4; + *glFormat = GL_RGBA; + *glType = GL_UNSIGNED_SHORT_4_4_4_4; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 : + *glInternalFormat = GL_RGBA8; + *glFormat = GL_RGBA; + *glType = GL_UNSIGNED_BYTE; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32 : + if ( RLGL.ExtSupported.texFloat32 ) + *glInternalFormat = GL_R32F; + *glFormat = GL_RED; + *glType = GL_FLOAT; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32 : + if ( RLGL.ExtSupported.texFloat32 ) + *glInternalFormat = GL_RGB32F; + *glFormat = GL_RGB; + *glType = GL_FLOAT; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32 : + if ( RLGL.ExtSupported.texFloat32 ) + *glInternalFormat = GL_RGBA32F; + *glFormat = GL_RGBA; + *glType = GL_FLOAT; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16 : + if ( RLGL.ExtSupported.texFloat16 ) + *glInternalFormat = GL_R16F; + *glFormat = GL_RED; + *glType = GL_HALF_FLOAT; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16 : + if ( RLGL.ExtSupported.texFloat16 ) + *glInternalFormat = GL_RGB16F; + *glFormat = GL_RGB; + *glType = GL_HALF_FLOAT; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16 : + if ( RLGL.ExtSupported.texFloat16 ) + *glInternalFormat = GL_RGBA16F; + *glFormat = GL_RGBA; + *glType = GL_HALF_FLOAT; + break; +#endif +#if ! defined( GRAPHICS_API_OPENGL_11 ) + case RL_PIXELFORMAT_COMPRESSED_DXT1_RGB : + if ( RLGL.ExtSupported.texCompDXT ) + *glInternalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + break; + case RL_PIXELFORMAT_COMPRESSED_DXT1_RGBA : + if ( RLGL.ExtSupported.texCompDXT ) + *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA : + if ( RLGL.ExtSupported.texCompDXT ) + *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA : + if ( RLGL.ExtSupported.texCompDXT ) + *glInternalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + case RL_PIXELFORMAT_COMPRESSED_ETC1_RGB : + if ( RLGL.ExtSupported.texCompETC1 ) + *glInternalFormat = GL_ETC1_RGB8_OES; + break; // NOTE: Requires OpenGL ES 2.0 or OpenGL 4.3 + case RL_PIXELFORMAT_COMPRESSED_ETC2_RGB : + if ( RLGL.ExtSupported.texCompETC2 ) + *glInternalFormat = GL_COMPRESSED_RGB8_ETC2; + break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 + case RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA : + if ( RLGL.ExtSupported.texCompETC2 ) + *glInternalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC; + break; // NOTE: Requires OpenGL ES 3.0 or OpenGL 4.3 + case RL_PIXELFORMAT_COMPRESSED_PVRT_RGB : + if ( RLGL.ExtSupported.texCompPVRT ) + *glInternalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + break; // NOTE: Requires PowerVR GPU + case RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA : + if ( RLGL.ExtSupported.texCompPVRT ) + *glInternalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + break; // NOTE: Requires PowerVR GPU + case RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA : + if ( RLGL.ExtSupported.texCompASTC ) + *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_4x4_KHR; + break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 + case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA : + if ( RLGL.ExtSupported.texCompASTC ) + *glInternalFormat = GL_COMPRESSED_RGBA_ASTC_8x8_KHR; + break; // NOTE: Requires OpenGL ES 3.1 or OpenGL 4.3 +#endif + default : + TRACELOG( RL_LOG_WARNING, "TEXTURE: Current format not supported (%i)", format ); + break; + } +} + +// Unload texture from GPU memory +void rlUnloadTexture( unsigned int id ) +{ + glDeleteTextures( 1, &id ); +} + +// Generate mipmap data for selected texture +// NOTE: Only supports GPU mipmap generation +void rlGenTextureMipmaps( unsigned int id, int width, int height, int format, int* mipmaps ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + glBindTexture( GL_TEXTURE_2D, id ); + + // Check if texture is power-of-two (POT) + bool texIsPOT = false; + + if ( ( ( width > 0 ) && ( ( width & ( width - 1 ) ) == 0 ) ) && ( ( height > 0 ) && ( ( height & ( height - 1 ) ) == 0 ) ) ) + texIsPOT = true; + + if ( ( texIsPOT ) || ( RLGL.ExtSupported.texNPOT ) ) + { + // glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorithm: GL_FASTEST, GL_NICEST, GL_DONT_CARE + glGenerateMipmap( GL_TEXTURE_2D ); // Generate mipmaps automatically + +#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) ) +#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) ) + + *mipmaps = 1 + ( int )floor( log( MAX( width, height ) ) / log( 2 ) ); + TRACELOG( RL_LOG_INFO, "TEXTURE: [ID %i] Mipmaps generated automatically, total: %i", id, *mipmaps ); + } + else + TRACELOG( RL_LOG_WARNING, "TEXTURE: [ID %i] Failed to generate mipmaps", id ); + + glBindTexture( GL_TEXTURE_2D, 0 ); +#else + TRACELOG( RL_LOG_WARNING, "TEXTURE: [ID %i] GPU mipmap generation not supported", id ); +#endif +} + +// Read texture pixel data +void* rlReadTexturePixels( unsigned int id, int width, int height, int format ) +{ + void* pixels = NULL; + +#if defined( GRAPHICS_API_OPENGL_11 ) || defined( GRAPHICS_API_OPENGL_33 ) + glBindTexture( GL_TEXTURE_2D, id ); + + // NOTE: Using texture id, 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 ); + + unsigned int glInternalFormat, glFormat, glType; + rlGetGlTextureFormats( format, &glInternalFormat, &glFormat, &glType ); + unsigned int size = rlGetPixelDataSize( width, height, format ); + + if ( ( glInternalFormat != 0 ) && ( format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB ) ) + { + pixels = RL_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 ); + + // TODO: Review warning retrieving object name in WebGL + // WARNING: WebGL: INVALID_ENUM: getFramebufferAttachmentParameter: invalid parameter name + // https://registry.khronos.org/webgl/specs/latest/1.0/ + glGetFramebufferAttachmentParameteriv( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &depthId ); + + unsigned int depthIdU = ( unsigned int )depthId; + if ( depthType == GL_RENDERBUFFER ) + glDeleteRenderbuffers( 1, &depthIdU ); + else if ( depthType == GL_TEXTURE ) + glDeleteTextures( 1, &depthIdU ); + + // NOTE: If a texture object is deleted while its image is attached to the *currently bound* framebuffer, + // the texture image is automatically detached from the currently bound framebuffer. + + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + glDeleteFramebuffers( 1, &id ); + + TRACELOG( RL_LOG_INFO, "FBO: [ID %i] Unloaded framebuffer from VRAM (GPU)", id ); +#endif +} + +// Vertex data management +//----------------------------------------------------------------------------------------- +// Load a new attributes buffer +unsigned int rlLoadVertexBuffer( const void* buffer, int size, bool dynamic ) +{ + unsigned int id = 0; + +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + glGenBuffers( 1, &id ); + glBindBuffer( GL_ARRAY_BUFFER, id ); + glBufferData( GL_ARRAY_BUFFER, size, buffer, dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW ); +#endif + + return id; +} + +// Load a new attributes element buffer +unsigned int rlLoadVertexBufferElement( const void* buffer, int size, bool dynamic ) +{ + unsigned int id = 0; + +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + glGenBuffers( 1, &id ); + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, id ); + glBufferData( GL_ELEMENT_ARRAY_BUFFER, size, buffer, dynamic ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW ); +#endif + + return id; +} + +// Enable vertex buffer (VBO) +void rlEnableVertexBuffer( unsigned int id ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + glBindBuffer( GL_ARRAY_BUFFER, id ); +#endif +} + +// Disable vertex buffer (VBO) +void rlDisableVertexBuffer( void ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + glBindBuffer( GL_ARRAY_BUFFER, 0 ); +#endif +} + +// Enable vertex buffer element (VBO element) +void rlEnableVertexBufferElement( unsigned int id ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, id ); +#endif +} + +// Disable vertex buffer element (VBO element) +void rlDisableVertexBufferElement( void ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); +#endif +} + +// Update vertex buffer with new data +// NOTE: dataSize and offset must be provided in bytes +void rlUpdateVertexBuffer( unsigned int id, const void* data, int dataSize, int offset ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + glBindBuffer( GL_ARRAY_BUFFER, id ); + glBufferSubData( GL_ARRAY_BUFFER, offset, dataSize, data ); +#endif +} + +// Update vertex buffer elements with new data +// NOTE: dataSize and offset must be provided in bytes +void rlUpdateVertexBufferElements( unsigned int id, const void* data, int dataSize, int offset ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, id ); + glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, offset, dataSize, data ); +#endif +} + +// Enable vertex array object (VAO) +bool rlEnableVertexArray( unsigned int vaoId ) +{ + bool result = false; +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + if ( RLGL.ExtSupported.vao ) + { + glBindVertexArray( vaoId ); + result = true; + } +#endif + return result; +} + +// Disable vertex array object (VAO) +void rlDisableVertexArray( void ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + if ( RLGL.ExtSupported.vao ) + glBindVertexArray( 0 ); +#endif +} + +// Enable vertex attribute index +void rlEnableVertexAttribute( unsigned int index ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + glEnableVertexAttribArray( index ); +#endif +} + +// Disable vertex attribute index +void rlDisableVertexAttribute( unsigned int index ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + glDisableVertexAttribArray( index ); +#endif +} + +// Draw vertex array +void rlDrawVertexArray( int offset, int count ) +{ + glDrawArrays( GL_TRIANGLES, offset, count ); +} + +// Draw vertex array elements +void rlDrawVertexArrayElements( int offset, int count, const void* buffer ) +{ + // NOTE: Added pointer math separately from function to avoid UBSAN complaining + unsigned short* bufferPtr = ( unsigned short* )buffer; + if ( offset > 0 ) + bufferPtr += offset; + + glDrawElements( GL_TRIANGLES, count, GL_UNSIGNED_SHORT, ( const unsigned short* )bufferPtr ); +} + +// Draw vertex array instanced +void rlDrawVertexArrayInstanced( int offset, int count, int instances ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + glDrawArraysInstanced( GL_TRIANGLES, 0, count, instances ); +#endif +} + +// Draw vertex array elements instanced +void rlDrawVertexArrayElementsInstanced( int offset, int count, const void* buffer, int instances ) +{ +#if defined( GRAPHICS_API_OPENGL_33 ) || defined( GRAPHICS_API_OPENGL_ES2 ) + // NOTE: Added pointer math separately from function to avoid UBSAN complaining + unsigned short* bufferPtr = ( unsigned short* )buffer; + if ( offset > 0 ) + bufferPtr += offset; + + glDrawElementsInstanced( GL_TRIANGLES, count, GL_UNSIGNED_SHORT, ( const unsigned short* )bufferPtr, instances ); +#endif +} + +#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, const 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 = 0; + unsigned int fragmentShaderId = 0; + + // Compile vertex shader (if provided) + if ( vsCode != NULL ) + vertexShaderId = rlCompileShader( vsCode, GL_VERTEX_SHADER ); + // In case no vertex shader was provided or compilation failed, we use default vertex shader + if ( vertexShaderId == 0 ) + vertexShaderId = RLGL.State.defaultVShaderId; + + // Compile fragment shader (if provided) + if ( fsCode != NULL ) + fragmentShaderId = rlCompileShader( fsCode, GL_FRAGMENT_SHADER ); + // In case no fragment shader was provided or compilation failed, we use default fragment shader + if ( fragmentShaderId == 0 ) + fragmentShaderId = RLGL.State.defaultFShaderId; + + // In case vertex and fragment shader are the default ones, no need to recompile, we can just assign the default shader program id + if ( ( vertexShaderId == RLGL.State.defaultVShaderId ) && ( fragmentShaderId == RLGL.State.defaultFShaderId ) ) + id = RLGL.State.defaultShaderId; + else + { + // One of or both shader are new, we need to compile a new shader program + id = rlLoadShaderProgram( vertexShaderId, fragmentShaderId ); + + // We can detach and delete vertex/fragment shaders (if not default ones) + // NOTE: We detach shader before deletion to make sure memory is freed + if ( vertexShaderId != RLGL.State.defaultVShaderId ) + { + // WARNING: Shader program linkage could fail and returned id is 0 + if ( id > 0 ) + glDetachShader( id, vertexShaderId ); + glDeleteShader( vertexShaderId ); + } + if ( fragmentShaderId != RLGL.State.defaultFShaderId ) + { + // WARNING: Shader program linkage could fail and returned id is 0 + if ( id > 0 ) + glDetachShader( id, fragmentShaderId ); + glDeleteShader( fragmentShaderId ); + } + + // In case shader program loading failed, we assign default shader + if ( id == 0 ) + { + // In case shader loading fails, we return the default shader + TRACELOG( RL_LOG_WARNING, "SHADER: Failed to load custom shader code, using default shader" ); + id = RLGL.State.defaultShaderId; + } + /* + else + { + // Get available shader uniforms + // NOTE: This information is useful for debug... + int uniformCount = -1; + glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &uniformCount); + + for (int i = 0; i < uniformCount; i++) + { + int namelen = -1; + int num = -1; + char name[256] = { 0 }; // Assume no variable names longer than 256 + GLenum type = GL_ZERO; + + // Get the name of the uniforms + glGetActiveUniform(id, i, sizeof(name) - 1, &namelen, &num, &type, name); + + name[namelen] = 0; + 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 = ( char* )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 Bound 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 = ( char* )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 = ( char* )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 int size, const void* data, int usageHint ) +{ + unsigned int ssbo = 0; + +#if defined( GRAPHICS_API_OPENGL_43 ) + glGenBuffers( 1, &ssbo ); + glBindBuffer( GL_SHADER_STORAGE_BUFFER, ssbo ); + glBufferData( GL_SHADER_STORAGE_BUFFER, size, data, usageHint ? usageHint : RL_STREAM_COPY ); + if ( data == NULL ) + glClearBufferData( GL_SHADER_STORAGE_BUFFER, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, NULL ); // Clear buffer data to 0 + glBindBuffer( GL_SHADER_STORAGE_BUFFER, 0 ); +#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 rlUpdateShaderBuffer( unsigned int id, const void* data, unsigned int dataSize, unsigned int offset ) +{ +#if defined( GRAPHICS_API_OPENGL_43 ) + glBindBuffer( GL_SHADER_STORAGE_BUFFER, id ); + glBufferSubData( GL_SHADER_STORAGE_BUFFER, offset, dataSize, data ); +#endif +} + +// Get SSBO buffer size +unsigned int rlGetShaderBufferSize( unsigned int id ) +{ + 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 ) ? ( unsigned int )size : 0; +} + +// Read SSBO buffer data (GPU->CPU) +void rlReadShaderBuffer( unsigned int id, void* dest, unsigned int count, unsigned int offset ) +{ +#if defined( GRAPHICS_API_OPENGL_43 ) + glBindBuffer( GL_SHADER_STORAGE_BUFFER, id ); + glGetBufferSubData( GL_SHADER_STORAGE_BUFFER, offset, count, dest ); +#endif +} + +// Bind SSBO buffer +void rlBindShaderBuffer( unsigned int id, unsigned int index ) +{ +#if defined( GRAPHICS_API_OPENGL_43 ) + glBindBufferBase( GL_SHADER_STORAGE_BUFFER, index, id ); +#endif +} + +// Copy SSBO buffer data +void rlCopyShaderBuffer( unsigned int destId, unsigned int srcId, unsigned int destOffset, unsigned int srcOffset, unsigned int count ) +{ +#if defined( GRAPHICS_API_OPENGL_43 ) + glBindBuffer( GL_COPY_READ_BUFFER, srcId ); + glBindBuffer( GL_COPY_WRITE_BUFFER, destId ); + glCopyBufferSubData( GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, srcOffset, destOffset, count ); +#endif +} + +// Bind image texture +void rlBindImageTexture( unsigned int id, unsigned int index, int format, bool readonly ) +{ +#if defined( GRAPHICS_API_OPENGL_43 ) + unsigned int glInternalFormat = 0, glFormat = 0, glType = 0; + + rlGetGlTextureFormats( format, &glInternalFormat, &glFormat, &glType ); + glBindImageTexture( index, id, 0, 0, 0, readonly ? GL_READ_ONLY : GL_READ_WRITE, glInternalFormat ); +#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_UNCOMPRESSED_R16 : + return "R16"; + break; // 16 bpp (1 channel - half float) + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16 : + return "R16G16B16"; + break; // 16*3 bpp (3 channels - half float) + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16 : + return "R16G16B16A16"; + break; // 16*4 bpp (4 channels - half float) + case RL_PIXELFORMAT_COMPRESSED_DXT1_RGB : + return "DXT1_RGB"; + break; // 4 bpp (no alpha) + case RL_PIXELFORMAT_COMPRESSED_DXT1_RGBA : + return "DXT1_RGBA"; + break; // 4 bpp (1 bit alpha) + case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA : + return "DXT3_RGBA"; + break; // 8 bpp + case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA : + return "DXT5_RGBA"; + break; // 8 bpp + case RL_PIXELFORMAT_COMPRESSED_ETC1_RGB : + return "ETC1_RGB"; + break; // 4 bpp + case RL_PIXELFORMAT_COMPRESSED_ETC2_RGB : + return "ETC2_RGB"; + break; // 4 bpp + case RL_PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA : + return "ETC2_RGBA"; + break; // 8 bpp + case RL_PIXELFORMAT_COMPRESSED_PVRT_RGB : + return "PVRT_RGB"; + break; // 4 bpp + case RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA : + return "PVRT_RGBA"; + break; // 4 bpp + case RL_PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA : + return "ASTC_4x4_RGBA"; + break; // 8 bpp + case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA : + return "ASTC_8x8_RGBA"; + break; // 2 bpp + default : + return "UNKNOWN"; + break; + } +} + +//---------------------------------------------------------------------------------- +// Module 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" + "precision mediump float; \n" // Precision required for OpenGL ES2 (WebGL) (on some browsers) + "attribute vec3 vertexPosition; \n" + "attribute vec2 vertexTexCoord; \n" + "attribute vec4 vertexColor; \n" + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" +#endif + "uniform mat4 mvp; \n" + "void main() \n" + "{ \n" + " fragTexCoord = vertexTexCoord; \n" + " fragColor = vertexColor; \n" + " gl_Position = mvp*vec4(vertexPosition, 1.0); \n" + "} \n"; + + // Fragment shader directly defined, no external file required + const char* defaultFShaderCode = +#if defined( GRAPHICS_API_OPENGL_21 ) + "#version 120 \n" + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" + "uniform sampler2D texture0; \n" + "uniform vec4 colDiffuse; \n" + "void main() \n" + "{ \n" + " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" + " gl_FragColor = texelColor*colDiffuse*fragColor; \n" + "} \n"; +#elif defined( GRAPHICS_API_OPENGL_33 ) + "#version 330 \n" + "in vec2 fragTexCoord; \n" + "in vec4 fragColor; \n" + "out vec4 finalColor; \n" + "uniform sampler2D texture0; \n" + "uniform vec4 colDiffuse; \n" + "void main() \n" + "{ \n" + " vec4 texelColor = texture(texture0, fragTexCoord); \n" + " finalColor = texelColor*colDiffuse*fragColor; \n" + "} \n"; +#endif +#if defined( GRAPHICS_API_OPENGL_ES2 ) + "#version 100 \n" + "precision mediump float; \n" // Precision required for OpenGL ES2 (WebGL) + "varying vec2 fragTexCoord; \n" + "varying vec4 fragColor; \n" + "uniform sampler2D texture0; \n" + "uniform vec4 colDiffuse; \n" + "void main() \n" + "{ \n" + " vec4 texelColor = texture2D(texture0, fragTexCoord); \n" + " gl_FragColor = texelColor*colDiffuse*fragColor; \n" + "} \n"; +#endif + + // NOTE: Compiled vertex/fragment shaders are not deleted, + // they are kept for re-use as default shaders in case some shader loading fails + RLGL.State.defaultVShaderId = 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 ) +{ + switch ( format ) + { + // GL_EXT_texture_compression_s3tc + case 0x83F0 : + return "GL_COMPRESSED_RGB_S3TC_DXT1_EXT"; + break; + case 0x83F1 : + return "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT"; + break; + case 0x83F2 : + return "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT"; + break; + case 0x83F3 : + return "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT"; + break; + // GL_3DFX_texture_compression_FXT1 + case 0x86B0 : + return "GL_COMPRESSED_RGB_FXT1_3DFX"; + break; + case 0x86B1 : + return "GL_COMPRESSED_RGBA_FXT1_3DFX"; + break; + // GL_IMG_texture_compression_pvrtc + case 0x8C00 : + return "GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG"; + break; + case 0x8C01 : + return "GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG"; + break; + case 0x8C02 : + return "GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG"; + break; + case 0x8C03 : + return "GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG"; + break; + // GL_OES_compressed_ETC1_RGB8_texture + case 0x8D64 : + return "GL_ETC1_RGB8_OES"; + break; + // GL_ARB_texture_compression_rgtc + case 0x8DBB : + return "GL_COMPRESSED_RED_RGTC1"; + break; + case 0x8DBC : + return "GL_COMPRESSED_SIGNED_RED_RGTC1"; + break; + case 0x8DBD : + return "GL_COMPRESSED_RG_RGTC2"; + break; + case 0x8DBE : + return "GL_COMPRESSED_SIGNED_RG_RGTC2"; + break; + // GL_ARB_texture_compression_bptc + case 0x8E8C : + return "GL_COMPRESSED_RGBA_BPTC_UNORM_ARB"; + break; + case 0x8E8D : + return "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB"; + break; + case 0x8E8E : + return "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB"; + break; + case 0x8E8F : + return "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB"; + break; + // GL_ARB_ES3_compatibility + case 0x9274 : + return "GL_COMPRESSED_RGB8_ETC2"; + break; + case 0x9275 : + return "GL_COMPRESSED_SRGB8_ETC2"; + break; + case 0x9276 : + return "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2"; + break; + case 0x9277 : + return "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2"; + break; + case 0x9278 : + return "GL_COMPRESSED_RGBA8_ETC2_EAC"; + break; + case 0x9279 : + return "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC"; + break; + case 0x9270 : + return "GL_COMPRESSED_R11_EAC"; + break; + case 0x9271 : + return "GL_COMPRESSED_SIGNED_R11_EAC"; + break; + case 0x9272 : + return "GL_COMPRESSED_RG11_EAC"; + break; + case 0x9273 : + return "GL_COMPRESSED_SIGNED_RG11_EAC"; + break; + // GL_KHR_texture_compression_astc_hdr + case 0x93B0 : + return "GL_COMPRESSED_RGBA_ASTC_4x4_KHR"; + break; + case 0x93B1 : + return "GL_COMPRESSED_RGBA_ASTC_5x4_KHR"; + break; + case 0x93B2 : + return "GL_COMPRESSED_RGBA_ASTC_5x5_KHR"; + break; + case 0x93B3 : + return "GL_COMPRESSED_RGBA_ASTC_6x5_KHR"; + break; + case 0x93B4 : + return "GL_COMPRESSED_RGBA_ASTC_6x6_KHR"; + break; + case 0x93B5 : + return "GL_COMPRESSED_RGBA_ASTC_8x5_KHR"; + break; + case 0x93B6 : + return "GL_COMPRESSED_RGBA_ASTC_8x6_KHR"; + break; + case 0x93B7 : + return "GL_COMPRESSED_RGBA_ASTC_8x8_KHR"; + break; + case 0x93B8 : + return "GL_COMPRESSED_RGBA_ASTC_10x5_KHR"; + break; + case 0x93B9 : + return "GL_COMPRESSED_RGBA_ASTC_10x6_KHR"; + break; + case 0x93BA : + return "GL_COMPRESSED_RGBA_ASTC_10x8_KHR"; + break; + case 0x93BB : + return "GL_COMPRESSED_RGBA_ASTC_10x10_KHR"; + break; + case 0x93BC : + return "GL_COMPRESSED_RGBA_ASTC_12x10_KHR"; + break; + case 0x93BD : + return "GL_COMPRESSED_RGBA_ASTC_12x12_KHR"; + break; + case 0x93D0 : + return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR"; + break; + case 0x93D1 : + return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR"; + break; + case 0x93D2 : + return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR"; + break; + case 0x93D3 : + return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR"; + break; + case 0x93D4 : + return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR"; + break; + case 0x93D5 : + return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR"; + break; + case 0x93D6 : + return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR"; + break; + case 0x93D7 : + return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR"; + break; + case 0x93D8 : + return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR"; + break; + case 0x93D9 : + return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR"; + break; + case 0x93DA : + return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR"; + break; + case 0x93DB : + return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR"; + break; + case 0x93DC : + return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR"; + break; + case 0x93DD : + return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR"; + break; + default : + return "GL_COMPRESSED_UNKNOWN"; + break; + } +} +#endif // RLGL_SHOW_GL_DETAILS_INFO + +#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2 + +// Get pixel data size in bytes (image or texture) +// NOTE: Size depends on pixel format +static int rlGetPixelDataSize( int width, int height, int format ) +{ + int dataSize = 0; // Size in bytes + int bpp = 0; // Bits per pixel + + switch ( format ) + { + case RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE : + bpp = 8; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA : + case RL_PIXELFORMAT_UNCOMPRESSED_R5G6B5 : + case RL_PIXELFORMAT_UNCOMPRESSED_R5G5B5A1 : + case RL_PIXELFORMAT_UNCOMPRESSED_R4G4B4A4 : + bpp = 16; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 : + bpp = 32; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8 : + bpp = 24; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32 : + bpp = 32; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32 : + bpp = 32 * 3; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32A32 : + bpp = 32 * 4; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16 : + bpp = 16; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16 : + bpp = 16 * 3; + break; + case RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16 : + bpp = 16 * 4; + break; + case RL_PIXELFORMAT_COMPRESSED_DXT1_RGB : + case RL_PIXELFORMAT_COMPRESSED_DXT1_RGBA : + case RL_PIXELFORMAT_COMPRESSED_ETC1_RGB : + case RL_PIXELFORMAT_COMPRESSED_ETC2_RGB : + case RL_PIXELFORMAT_COMPRESSED_PVRT_RGB : + case RL_PIXELFORMAT_COMPRESSED_PVRT_RGBA : + 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/project/auxillary/vis_ast/dependencies/raylib/include/utils.h b/project/auxillary/vis_ast/dependencies/raylib/include/utils.h new file mode 100644 index 0000000..7e959b2 --- /dev/null +++ b/project/auxillary/vis_ast/dependencies/raylib/include/utils.h @@ -0,0 +1,82 @@ +/********************************************************************************************** + * + * raylib.utils - Some common utility functions + * + * + * LICENSE: zlib/libpng + * + * Copyright (c) 2014-2023 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 +//---------------------------------------------------------------------------------- +#if defined( __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 + +#if defined( __cplusplus ) +} +#endif + +#endif // UTILS_H diff --git a/project/auxillary/vis_ast/dependencies/raylib/raylib.c b/project/auxillary/vis_ast/dependencies/raylib/raylib.c new file mode 100644 index 0000000..2f52841 --- /dev/null +++ b/project/auxillary/vis_ast/dependencies/raylib/raylib.c @@ -0,0 +1,8 @@ +#include "raudio.c" +#include "rcore.c" +#include "rglfw.c" +#include "rmodels.c" +#include "rshapes.c" +#include "rtext.c" +#include "rtextures.c" +#include "rutils.c" diff --git a/project/auxillary/vis_ast/dependencies/raylib/raylib.refactor b/project/auxillary/vis_ast/dependencies/raylib/raylib.refactor new file mode 100644 index 0000000..21068a2 --- /dev/null +++ b/project/auxillary/vis_ast/dependencies/raylib/raylib.refactor @@ -0,0 +1,9 @@ + __VERSION 1 + + +word SUPPORT_MODULE_RSHAPES, RL_SUPPORT_MODULE_RSHAPES +word SUPPORT_MODULE_RTEXTURES, RL_SUPPORT_MODULE_RTEXTURES +word SUPPORT_MODULE_RTEXT, RL_SUPPORT_MODULE_RTEXT +word SUPPORT_MODULE_RMODELS, RL_SUPPORT_MODULE_RMODELS +word SUPPORT_MODULE_RAUDIO, RL_SUPPORT_MODULE_RAUDIO + diff --git a/project/auxillary/vis_ast/dependencies/raylib/raylib_refactor.cpp b/project/auxillary/vis_ast/dependencies/raylib/raylib_refactor.cpp new file mode 100644 index 0000000..e66e773 --- /dev/null +++ b/project/auxillary/vis_ast/dependencies/raylib/raylib_refactor.cpp @@ -0,0 +1,290 @@ +#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS +#define GEN_BENCHMARK +#define GEN_ENFORCE_STRONG_CODE_TYPES +// #define GEN_IMPLEMENTATION +#include "gen.cpp" +#include "gen.builder.cpp" + + +constexpr char const* path_config = "config.h"; +constexpr char const* path_raylib = "raylib.h"; +constexpr char const* path_raymath = "raymath.h"; +constexpr char const* path_rcamera = "rcamera.h"; +constexpr char const* path_rcore = "rcore.h"; +constexpr char const* path_rgestures = "rgestures.h"; +constexpr char const* path_rgl = "rgl.h"; +constexpr char const* path_rtext = "rtext.h"; + + +using namespace gen; + +StringCached upper_snake_to_mixed_snake(StringCached str) +{ + local_persist String scratch = String::make_reserve(GlobalAllocator, kilobytes(1)); + scratch.clear(); + + bool capitalizeNext = true; + + for (s32 index = 0; index < str.length(); ++index) + { + char c = str[index]; + + if (c == '_') + { + scratch.append(c); + capitalizeNext = true; + } + else if (capitalizeNext) + { + if (c >= 'a' && c <= 'z') + { + scratch.append(c - 32); // Convert to uppercase + } + else + { + scratch.append(c); + } + capitalizeNext = false; + } + else + { + if (c >= 'A' && c <= 'Z') + { + scratch.append(c + 32); // Convert to lowercase + } + else + { + scratch.append(c); + } + } + } + + StringCached result = get_cached_string(scratch); + return result; +} + +StringCached pascal_to_lower_snake(StringCached str) +{ + local_persist String scratch = String::make_reserve(GlobalAllocator, kilobytes(1)); + scratch.clear(); + + for (s32 index = 0; index < str.length(); ++index) + { + char c = str[index]; + char next = (index + 1 < str.length()) ? str[index + 1] : '\0'; // Ensure we don't go out of bounds + + // Whitelist check for "2D" and "3D" + if ((c == '2' || c == '3' | c == '4') && (next == 'D' || next == 'd')) + { + if (index > 0) // If it's not the start of the string, append an underscore + { + char* prev = str.Data + index - 1; + if (*prev != '_') // Avoid double underscores + { + scratch.append('_'); + } + } + scratch.append(c); + scratch.append('d'); // Convert to lowercase + index++; // Skip the next character since we've already processed it + continue; + } + + if (c >= 'A' && c <= 'Z') + { + char* prev = (index > 0) ? str.Data + index - 1 : nullptr; + + if ((index > 0 && prev && *prev >= 'a' && *prev <= 'z') || + (prev && char_is_digit(*prev) && (next >= 'A' && next <= 'Z'))) + { + scratch.append('_'); + } + + scratch.append(c + 32); + } + else if (char_is_digit(c) && (next >= 'A' && next <= 'Z')) // Check for a number followed by an uppercase letter + { + scratch.append(c); + scratch.append('_'); + } + else + { + scratch.append(c); + } + } + + StringCached result = get_cached_string(scratch); + return result; +} + +void refactor_enum( CodeEnum& code ) +{ + for ( Code elem : code->Body ) + { + if ( elem->Type == ECode::Untyped ) + { + elem->Content = upper_snake_to_mixed_snake( elem->Content ); + } + } +} + +void refactor_typename( CodeType& type ) +{ + local_persist CodeType t_unsigned_char = parse_type( code(unsigned char) ); + local_persist CodeType t_unsigned_char_ptr = parse_type( code(unsigned char*) ); + local_persist CodeType t_unsigned_short_ptr = parse_type( code(unsigned short*) ); + local_persist CodeType t_int = parse_type( code(int) ); + local_persist CodeType t_int_ptr = parse_type( code(int*) ); + local_persist CodeType t_unsigned_int = parse_type( code(unsigned int) ); + local_persist CodeType t_float = parse_type( code(float) ); + local_persist CodeType t_float_ptr = parse_type( code(float*) ); + + local_persist CodeType t_f32_ptr = parse_type( code(f32*) ); + local_persist CodeType t_u8_ptr = parse_type( code(u8*) ); + local_persist CodeType t_s32_ptr = parse_type( code(s32*) ); + + String type_str = type.to_string(); + + if ( str_compare( type_str, t_unsigned_char.to_string() ) == 0 ) + { + type.ast = t_u8.ast; + } + if ( str_compare( type_str, t_unsigned_char_ptr.to_string() ) == 0 ) + { + type.ast = t_u8_ptr.ast; + } + if ( str_compare( type_str, t_unsigned_short_ptr.to_string() ) == 0 ) + { + type.ast = t_u8_ptr.ast; + } + if ( str_compare( type_str, t_int.to_string() ) == 0 ) + { + type.ast = t_s32.ast; + } + if ( str_compare( type_str, t_int_ptr.to_string() ) == 0 ) + { + type.ast = t_s32_ptr.ast; + } + if ( str_compare( type_str, t_unsigned_int.to_string() ) == 0 ) + { + type.ast = t_u32.ast; + } + if ( str_compare( type_str, t_float.to_string() ) == 0 ) + { + type.ast = t_f32.ast; + } + if ( str_compare( type_str, t_float_ptr.to_string() ) == 0 ) + { + type.ast = t_f32_ptr.ast; + } +} + +void refactor_fn( CodeFn& fn ) +{ + fn->Name = pascal_to_lower_snake( fn->Name ); + + for ( CodeParam param : fn->Params ) + { + refactor_typename( param->ValueType ); + } +} + +void refactor_struct( CodeStruct& code ) +{ + for ( Code field : code->Body ) + { + if ( field->Type == ECode::Variable ) + { + CodeVar var = field.cast(); + refactor_typename( var->ValueType ); + } + } +} + +void refactor_file( char const* path ) +{ + FileContents contents = file_read_contents( GlobalAllocator, true, path ); + CodeBody code = parse_global_body( { contents.size, rcast(char const*, contents.data) } ); + + String name_scratch = String::make_reserve( GlobalAllocator, kilobytes(1) ); + + // CodeBody includes + // CodeBody nspace_body = def_body( ECode::Namespace ); + CodeBody new_code = def_body( ECode::Global_Body ); + + for ( Code elem : code ) + { + if ( elem->Type == ECode::Preprocess_Define ) + { + if ( str_compare( elem->Name, txt("RL"), 2 ) == 0 || str_compare( elem->Name, txt("RAYLIB"), 6 ) == 0 ) + continue; + + name_scratch.append_fmt( "%RL_%S", elem->Name ); + elem->Name = get_cached_string( name_scratch ); + name_scratch.clear(); + } + + if ( elem->Type == ECode::Enum ) + { + refactor_enum( elem.cast() ); + } + + if ( elem->Type == ECode::Typedef ) + { + CodeTypedef td = elem.cast(); + if ( td->UnderlyingType->Type == ECode::Enum ) + { + CodeEnum code = td->UnderlyingType.cast(); + refactor_enum( code ); + } + if ( td->UnderlyingType->Type == ECode::Struct ) + { + CodeStruct code = td->UnderlyingType.cast(); + refactor_struct( code ); + } + } + + if ( elem->Type == ECode::Struct ) + { + refactor_struct( elem.cast() ); + } + + if ( elem->Type == ECode::Function || elem->Type == ECode::Function_Fwd ) + { + refactor_fn( elem.cast() ); + } + + if ( elem->Type == ECode::Extern_Linkage ) + { + CodeBody body = elem.cast()->Body; + for ( Code elem : body ) + { + if ( elem->Type == ECode::Function || elem->Type == ECode::Function_Fwd ) + { + refactor_fn( elem.cast() ); + } + } + + Code nspace = def_namespace( txt("raylib"), def_namespace_body( args(elem) ) ); + elem = nspace; + } + + new_code.append( elem ); + } + + Builder builder = Builder::open( path ); + builder.print( new_code ); + builder.write(); +} + +int gen_main() +{ + gen::init(); + + refactor_file( path_config ); + refactor_file( path_raylib ); + refactor_file( path_raymath ); + refactor_file( path_rcamera ); + + return 0; +} diff --git a/project/auxillary/vis_ast/readme.md b/project/auxillary/vis_ast/readme.md new file mode 100644 index 0000000..c866943 --- /dev/null +++ b/project/auxillary/vis_ast/readme.md @@ -0,0 +1,10 @@ +# Vis AST + +AST visualizer for gencpp + +This is a early start to creating frontend tooling for c/c++ using gencpp as a core component. +I'll be exploring creating an AST explorer for this library with raylib as the graphical & general platform vendor for dependencies that go beyond the scope of gencpp. + +For now I'll have its build script in this file, however it will heavily rely on gencpp's helper scripts. + +Whatever sort of UX tooling I setup for this will be reused for the other tools I'll be creating for gencpp. diff --git a/project/auxillary/vis_ast/rebuild.ps1 b/project/auxillary/vis_ast/rebuild.ps1 new file mode 100644 index 0000000..e69de29 diff --git a/project/auxillary/vis_ast/update_deps.ps1 b/project/auxillary/vis_ast/update_deps.ps1 new file mode 100644 index 0000000..35367c7 --- /dev/null +++ b/project/auxillary/vis_ast/update_deps.ps1 @@ -0,0 +1,178 @@ +Clear-Host + +$path_root = git rev-parse --show-toplevel +$path_scripts = Join-Path $path_root 'scripts' + +$target_arch = Join-Path $path_scripts 'helpers/target_arch.psm1' +$devshell = Join-Path $path_scripts 'helpers/devshell.ps1' +$format_cpp = Join-Path $path_scripts 'helpers/format_cpp.psm1' +$incremental_checks = Join-Path $path_scripts 'helpers/incremental_checks.ps1' +$vendor_toolchain = Join-Path $path_scripts 'helpers/vendor_toolchain.ps1' + +$path_project = Join-Path $path_root 'project' +$path_aux = Join-Path $path_project 'auxillary' +$path_vis_root = Join-Path $path_aux 'vis_ast' +$path_binaries = Join-Path $path_vis_root 'binaries' + +$path_deps = Join-Path $path_vis_root 'dependencies' +$path_temp = Join-Path $path_deps 'temp' + +Import-Module $target_arch +Import-Module $format_cpp + +#region Arguments +$vendor = $null +$optimize = $null +$debug = $null +$analysis = $false +$dev = $false +$verbose = $null + +[array] $vendors = @( "clang", "msvc" ) + +# This is a really lazy way of parsing the args, could use actual params down the line... + +if ( $args ) { $args | ForEach-Object { +switch ($_){ + { $_ -in $vendors } { $vendor = $_; break } + "optimize" { $optimize = $true } + "debug" { $debug = $true } + "analysis" { $analysis = $true } + "dev" { $dev = $true } + "verbose" { $verbose = $true } +} +}} +#endregion Argument + +# Load up toolchain configuraion +. $vendor_toolchain +. $incremental_checks + +# Clear out the current content first +# remove-item $path_temp -Recurse +# New-Item -ItemType Directory -Path $path_temp + +if ( -not (Test-Path $path_binaries) ) { + New-Item -ItemType Directory -Path $path_binaries +} + +function setup-raylib { + $path_raylib = join-path $path_deps 'raylib' + $path_raylib_inc = join-path $path_raylib 'include' + $path_raylib_lib = join-path $path_raylib 'lib' + if ( test-path $path_raylib_inc ) { + remove-item $path_raylib_inc -recurse + remove-item $path_raylib_lib -recurse + } + new-item -path $path_raylib_inc -ItemType Directory + new-item -path $path_raylib_lib -ItemType Directory + + $url_raylib_zip = 'https://github.com/raysan5/raylib/archive/refs/heads/master.zip' + $path_raylib_zip = join-path $path_temp 'raylib.zip' + + $path_raylib_master = join-path $path_temp 'raylib-master' + $path_raylib_src = join-path $path_raylib_master 'src' + $path_raylib_glfw_inc = join-path $path_raylib_src 'external/glfw/include' + + remove-item $path_raylib_master -Recurse + # invoke-webrequest -uri $url_raylib_zip -outfile $path_raylib_zip + expand-archive -path $path_raylib_zip -destinationpath $path_temp + + write-host "Building raylib with $vendor" + + $path_build = Join-Path $path_raylib 'build' + if ( (Test-Path $path_build) -eq $false ) { + New-Item $path_build -ItemType Directory + } + + $raylib_headers = Get-ChildItem -Path $path_raylib_src -Filter "*.h" -File + $raylib_modules = get-childitem -path $path_raylib_src -filter "*.c" -file + + # Refactor raylib + if ( $true ) { + # if ( $false ) { + $path_gencpp = join-path $path_root 'project/gen' + + $includes = @( + $path_gencpp + ) + + $compiler_args = @( + ($flag_define + 'GEN_TIME') + ) + + $linker_args = @( + + ) + + $unit = join-path $path_raylib 'raylib_refactor.cpp' + $executable = join-path $path_build 'raylib_refactor.exe' + + $build_result = build-simple $path_build $includes $compiler_args $linker_args $unit $executable + Push-Location $path_raylib_src + if ( Test-Path( $executable ) ) { + Measure-Command { & $executable + | ForEach-Object { + write-host `t $_ -ForegroundColor Green + } + } + } + Pop-Location + + push-location $path_scripts + # Time to format + $fmt_includes = @() + foreach ( $header in $raylib_headers ) { + $fmt_includes += split-path $header -leaf + } + foreach ( $module in $raylib_modules ) { + $fmt_includes += split-path $module -leaf + } + format-cpp $path_raylib_src $fmt_includes $null + pop-location + } + + # Build raylib + if ( $false ) { + # Microsoft + $lib_gdi32 = 'Gdi32.lib' + $lib_shell32 = 'Shell32.lib' + $lib_xinput = 'Xinput.lib' + $lib_user32 = 'User32.lib' + $lib_winmm = 'Winmm.lib' + + $includes = @( + $path_raylib_src, + $path_raylib_glfw_inc + ) + foreach ($include in $includes) { + write-host $include + } + + $compiler_args = @( + ($flag_define + 'PLATFORM_DESKTOP'), + ($flag_define + 'BUILD_LIBTYPE_SHARED') + ) + $linker_args = @( + $flag_link_dll, + + # $lib_xinput, + $lib_gdi32, + $lib_shell32, + $lib_user32, + $lib_winmm + ) + + # $unit = join-path $path_raylib 'raylib.c' + $dll = join-path $path_raylib_lib 'raylib.dll' + # $build_result = build-simple $path_build $includes $compiler_args $linker_args $unit $dll + + $build_result = build $path_build $includes $compiler_args $linker_args $raylib_modules $dll + } + + # Move headers to used include + foreach ($header in $raylib_headers) { + Copy-Item -Path $header -Destination (join-path $path_raylib_inc (split-path $header -Leaf)) + } +} +setup-raylib diff --git a/project/components/ast.cpp b/project/components/ast.cpp index 572c459..764ffba 100644 --- a/project/components/ast.cpp +++ b/project/components/ast.cpp @@ -1317,6 +1317,8 @@ String AST::to_string() // Keep the chain going... if ( NextVar ) result.append_fmt( ", %S", NextVar->to_string() ); + + break; } if ( bitfield_is_equal( u32, ModuleFlags, ModuleFlag::Export )) diff --git a/project/components/ast.hpp b/project/components/ast.hpp index 4ddcb90..ea06500 100644 --- a/project/components/ast.hpp +++ b/project/components/ast.hpp @@ -475,7 +475,8 @@ struct CodeParam } CodeParam end() { - return { (AST_Param*) rcast( AST*, ast)->Last }; + // return { (AST_Param*) rcast( AST*, ast)->Last }; + return { nullptr }; } CodeParam& operator++(); CodeParam operator*() diff --git a/project/components/header_end.hpp b/project/components/header_end.hpp index 01ebf53..d00e31d 100644 --- a/project/components/header_end.hpp +++ b/project/components/header_end.hpp @@ -7,7 +7,7 @@ #pragma region Constants #ifndef GEN_GLOBAL_BUCKET_SIZE -# define GEN_GLOBAL_BUCKET_SIZE megabytes(4) +# define GEN_GLOBAL_BUCKET_SIZE megabytes(8) #endif #ifndef GEN_CODEPOOL_NUM_BLOCKS # define GEN_CODEPOOL_NUM_BLOCKS kilobytes(16) @@ -31,7 +31,7 @@ # define GEN_LEX_ALLOCATOR_SIZE megabytes(4) #endif #ifndef GEN_BUILDER_STR_BUFFER_RESERVE -# define GEN_BUILDER_STR_BUFFER_RESERVE megabytes(1) +# define GEN_BUILDER_STR_BUFFER_RESERVE megabytes(2) #endif // These constexprs are used for allocation behavior of data structures diff --git a/project/components/interface.parsing.cpp b/project/components/interface.parsing.cpp index 1f2c3ed..91d7339 100644 --- a/project/components/interface.parsing.cpp +++ b/project/components/interface.parsing.cpp @@ -1294,7 +1294,7 @@ internal Code parse_compilcated_definition (); internal CodeBody parse_class_struct_body ( Parser::TokType which, Parser::Token name = Parser::NullToken ); internal Code parse_class_struct ( Parser::TokType which, bool inplace_def ); internal CodeDefine parse_define (); -internal Code parse_foward_or_definition ( Parser::TokType which, bool is_inplace ); +internal Code parse_forward_or_definition ( Parser::TokType which, bool is_inplace ); internal CodeFn parse_function_after_name ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeType ret_type, Parser::Token name ); internal Code parse_function_body (); internal Code parse_global_nspace (); @@ -1309,6 +1309,7 @@ internal Code parse_simple_preprocess ( Parser::TokType internal Code parse_static_assert (); internal void parse_template_args ( Parser::Token& token ); internal CodeVar parse_variable_after_name ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeType type, StrC name ); +internal CodeVar parse_variable_declaration_list (); internal CodeClass parse_class ( bool inplace_def = false ); internal CodeConstructor parse_constructor (); @@ -1316,7 +1317,7 @@ internal CodeDestructor parse_destructor ( CodeSpecifiers specifiers = NoC internal CodeEnum parse_enum ( bool inplace_def = false ); internal CodeBody parse_export_body (); internal CodeBody parse_extern_link_body(); -internal CodeExtern parse_exten_link (); +internal CodeExtern parse_extern_link (); internal CodeFriend parse_friend (); internal CodeFn parse_function (); internal CodeNS parse_namespace (); @@ -1783,7 +1784,9 @@ Code parse_complicated_definition( Parser::TokType which ) if ( (idx - 2 ) == tokens.Idx ) { // Its a forward declaration only - return parse_foward_or_definition( which, is_inplace ); + Code result = parse_forward_or_definition( which, is_inplace ); + Context.pop(); + return result; } Token tok = tokens[ idx - 1 ]; @@ -1831,7 +1834,9 @@ Code parse_complicated_definition( Parser::TokType which ) { // Its a definition // { ... }; - return parse_foward_or_definition( which, is_inplace ); + Code result = parse_forward_or_definition( which, is_inplace ); + Context.pop(); + return result; } else if ( tok.Type == TokType::BraceSquare_Close) { @@ -2262,7 +2267,7 @@ CodeDefine parse_define() } internal inline -Code parse_foward_or_definition( Parser::TokType which, bool is_inplace ) +Code parse_forward_or_definition( Parser::TokType which, bool is_inplace ) { using namespace Parser; @@ -2272,22 +2277,18 @@ Code parse_foward_or_definition( Parser::TokType which, bool is_inplace ) { case TokType::Decl_Class: result = parse_class( is_inplace ); - Context.pop(); return result; case TokType::Decl_Enum: result = parse_enum( is_inplace ); - Context.pop(); return result; case TokType::Decl_Struct: result = parse_struct( is_inplace ); - Context.pop(); return result; case TokType::Decl_Union: result = parse_union( is_inplace ); - Context.pop(); return result; default: @@ -2295,7 +2296,6 @@ Code parse_foward_or_definition( Parser::TokType which, bool is_inplace ) "(only supports class, enum, struct, union) \n%s" , Context.to_string() ); - Context.pop(); return CodeInvalid; } @@ -2499,7 +2499,7 @@ CodeBody parse_global_nspace( CodeT which ) if ( which == Extern_Linkage_Body ) log_failure( "Nested extern linkage\n%s", Context.to_string() ); - member = parse_extern_link_body(); + member = parse_extern_link(); break; case TokType::Decl_Namespace: @@ -3636,16 +3636,29 @@ CodeVar parse_variable_after_name( bitfield_expr = untyped_str( expr_tok ); } - Token stmt_end = currtok; - eat( TokType::Statement_End ); - - // Check for inline comment : = ; // + CodeVar next_var = NoCode; + Token stmt_end = NullToken; CodeComment inline_cmt = NoCode; - if ( left - && ( currtok_noskip.Type == TokType::Comment ) - && currtok_noskip.Line == stmt_end.Line ) + if ( type ) { - inline_cmt = parse_comment(); + if ( currtok.Type == TokType::Comma ) + { + // Were dealing with a statement with more than one declaration + // This is only handled this way if its the first declaration + // Otherwise its looped through in parse_variable_declaration_list + next_var = parse_variable_declaration_list(); + } + + // If we're dealing with a "comma-procedding then we cannot expect a statement end or inline comment + // Any comma procedding variable will not have a type provided so it can act as a indicator to skip this + Token stmt_end = currtok; + eat( TokType::Statement_End ); + + // Check for inline comment : = ; // + if ( left && ( currtok_noskip.Type == TokType::Comment ) && currtok_noskip.Line == stmt_end.Line ) + { + inline_cmt = parse_comment(); + } } using namespace ECode; @@ -3656,7 +3669,9 @@ CodeVar parse_variable_after_name( result->Name = get_cached_string( name ); result->ModuleFlags = mflags; - result->ValueType = type; + // Type can be null if we're dealing with a declaration from a variable declaration-list + if ( type ) + result->ValueType = type; if (array_expr ) type->ArrExpr = array_expr; @@ -3676,6 +3691,90 @@ CodeVar parse_variable_after_name( if ( inline_cmt ) result->InlineCmt = inline_cmt; + if ( next_var ) + { + result->NextVar = next_var; + result->NextVar->Parent = result; + } + + Context.pop(); + return result; +} + +/* + Note(Ed): This does not support the following: + * Function Pointers +*/ +internal CodeVar parse_variable_declaration_list() +{ + using namespace Parser; + push_scope(); + + CodeVar result = NoCode; + CodeVar last_var = NoCode; + while ( check( TokType::Comma ) ) + { + eat( TokType::Comma ); + + CodeSpecifiers specifiers = NoCode; + + while ( left && currtok.is_specifier() ) + { + SpecifierT spec = ESpecifier::to_type( currtok ); + + switch ( spec ) + { + case ESpecifier::Const: + if ( specifiers->NumEntries && specifiers->ArrSpecs[ specifiers->NumEntries - 1 ] != ESpecifier::Ptr ) + { + log_failure( "Error, const specifier must come after pointer specifier for variable declaration proceeding comma\n" + "(Parser will add and continue to specifiers, but will most likely fail to compile)\n%s" + , Context.to_string() ); + + specifiers.append( spec ); + } + break; + + case ESpecifier::Ptr: + case ESpecifier::Ref: + case ESpecifier::RValue: + break; + + default: + { + log_failure( "Error, invalid specifier '%s' proceeding comma\n" + "(Parser will add and continue to specifiers, but will most likely fail to compile)\n%s" + , currtok.Text, Context.to_string() ); + continue; + } + break; + } + + if ( specifiers ) + specifiers.append( spec ); + else + specifiers = def_specifier( spec ); + } + + StrC name = currtok; + eat( TokType::Identifier ); + + CodeVar var = parse_variable_after_name( ModuleFlag::None, NoCode, specifiers, NoCode, name ); + + // TODO(Ed) : CodeVar is going to need a procedure to append comma-defined vars to itself. + if ( ! result ) + { + result.ast = var.ast; + last_var.ast = var.ast; + } + else + { + last_var->NextVar.ast = var.ast; + last_var->NextVar->Parent.ast = rcast(AST*, var.ast); + last_var.ast = var.ast; + } + } + Context.pop(); return result; } @@ -4837,16 +4936,16 @@ CodeType parse_type( bool* typedef_is_function ) // Check if native type keywords are used, eat them for the signature. else if ( currtok.Type >= TokType::Type_Unsigned && currtok.Type <= TokType::Type_MS_W64 ) { + // TODO(Ed) : Review this... Its necessary for parsing however the algo's path to this is lost... name = currtok; eat( currtok.Type ); - while (currtok.Type >= TokType::Type_Unsigned && currtok.Type <= TokType::Type_MS_W64 ) + while ( left && currtok.Type >= TokType::Type_Unsigned && currtok.Type <= TokType::Type_MS_W64 ) { eat( currtok.Type ); } name.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)name.Text; - Context.Scope->Name = name; } // The usual Identifier type signature that may have namespace qualifiers @@ -4925,7 +5024,8 @@ CodeType parse_type( bool* typedef_is_function ) last_capture = scanner; } - bool is_for_opcast = str_compare( Context.Scope->Prev->ProcName, "parse_operator_cast" ) == 0; + bool has_context = Context.Scope && Context.Scope->Prev; + bool is_for_opcast = has_context && str_compare( Context.Scope->Prev->ProcName, "parse_operator_cast" ) == 0; if ( is_for_opcast && is_function_typename && last_capture ) { // If we're parsing for an operator cast, having one capture start is not enough @@ -5203,6 +5303,7 @@ CodeTypedef parse_typedef() || currtok.Type == TokType::Decl_Struct || currtok.Type == TokType::Decl_Union; + // This code is highly correlated with parse_compilcated_definition if ( is_complicated ) { TokArray tokens = Context.Tokens; @@ -5224,7 +5325,7 @@ CodeTypedef parse_typedef() if ( (idx - 2 ) == tokens.Idx ) { // Its a forward declaration only - type = parse_foward_or_definition( currtok.Type, from_typedef ); + type = parse_forward_or_definition( currtok.Type, from_typedef ); } Token tok = tokens[ idx - 1 ]; @@ -5263,13 +5364,15 @@ CodeTypedef parse_typedef() return CodeInvalid; } - type = parse_type(); + // TODO(Ed) : I'm not sure if I have to use parse_type here, I'd rather not as that would complicate parse_type. + // type = parse_type(); + type = parse_forward_or_definition( currtok.Type, from_typedef ); } else if ( tok.Type == TokType::BraceCurly_Close ) { // Its a definition // { ... }; - type = parse_foward_or_definition( currtok.Type, from_typedef ); + type = parse_forward_or_definition( currtok.Type, from_typedef ); } else if ( tok.Type == TokType::BraceSquare_Close) { @@ -5327,7 +5430,12 @@ CodeTypedef parse_typedef() result->IsFunction = false; } - result->UnderlyingType = type; + if ( type ) + { + result->UnderlyingType = type; + result->UnderlyingType->Parent = rcast(AST*, result.ast); + } + // Type needs to be aware of its parent so that it can be serialized properly. if ( type->Type == Typename && array_expr && array_expr->Type != Invalid ) type.cast()->ArrExpr = array_expr; diff --git a/scripts/build.ci.ps1 b/scripts/build.ci.ps1 index 4f3d812..4dc9920 100644 --- a/scripts/build.ci.ps1 +++ b/scripts/build.ci.ps1 @@ -3,14 +3,23 @@ # That or just rewrite it in an sh script and call it a day. Import-Module ./helpers/target_arch.psm1 -$devshell = Join-Path $PSScriptRoot 'helpers/devshell.ps1' +$target_arch = Join-Path $PSScriptRoot 'helpers/target_arch.psm1' +$devshell = Join-Path $PSScriptRoot 'helpers/devshell.ps1' +$format_cpp = Join-Path $PSScriptRoot 'helpers/format_cpp.psm1' +$incremental_checks = Join-Path $PSScriptRoot 'helpers/incremental_checks.ps1' +$vendor_toolchain = Join-Path $PSScriptRoot 'helpers/vendor_toolchain.ps1' + $path_root = git rev-parse --show-toplevel +Import-Module $target_arch +Import-Module $format_cpp + Push-Location $path_root #region Arguments $vendor = $null $release = $null + $verbose = $false [bool] $bootstrap = $false [bool] $singleheader = $false [bool] $test = $false @@ -21,7 +30,8 @@ Push-Location $path_root if ( $args ) { $args | ForEach-Object { switch ($_){ - { $_ -in $vendors } { $vendor = $_; break } + { $_ -in $vendors } { $vendor = $_; break } + "verbose" { $verbose = $true } "release" { $release = $true } "debug" { $release = $false } "bootstrap" { $bootstrap = $true } @@ -47,294 +57,23 @@ if ( $release -eq $null ) { write-host "No build type specified, assuming debug" $release = $false } - -if ( $bootstrap -eq $false -and $singleheader -eq $false -and $test -eq $false ) { - throw "No build target specified. One must be specified, this script will not assume one" -} - -write-host "Building gencpp with $vendor" -write-host "Build Type: $(if ($release) {"Release"} else {"Debug"} )" - -function run-compiler -{ - param( $compiler, $unit, $compiler_args ) - - write-host "`Compiling $unit" - write-host "Compiler config:" - $compiler_args | ForEach-Object { - write-host $_ -ForegroundColor Cyan - } - - $time_taken = Measure-Command { - & $compiler $compiler_args 2>&1 | ForEach-Object { - $color = 'White' - switch ($_){ - { $_ -match "error" } { $color = 'Red' ; break } - { $_ -match "warning" } { $color = 'Yellow'; break } - } - write-host `t $_ -ForegroundColor $color - } - } - - if ( Test-Path($unit) ) { - write-host "$unit compile finished in $($time_taken.TotalMilliseconds) ms" - } - else { - write-host "Compile failed for $unit" -ForegroundColor Red - } -} - -function run-linker -{ - param( $linker, $binary, $linker_args ) - - write-host "`Linking $binary" - write-host "Linker config:" - $linker_args | ForEach-Object { - write-host $_ -ForegroundColor Cyan - } - - $time_taken = Measure-Command { - & $linker $linker_args 2>&1 | ForEach-Object { - $color = 'White' - switch ($_){ - { $_ -match "error" } { $color = 'Red' ; break } - { $_ -match "warning" } { $color = 'Yellow'; break } - } - write-host `t $_ -ForegroundColor $color - } - } - - if ( Test-Path($binary) ) { - write-host "$binary linking finished in $($time_taken.TotalMilliseconds) ms" - } - else { - write-host "Linking failed for $binary" -ForegroundColor Red - } +elseif ( $release -eq $false ) { + $debug = $true } - -function run-compile-and-link -{ - param( $vendor, $unit, $compiler_args, $linker_args ) - - write-host "`Compiling & Linking $unit" - write-host "Compiler config:" - $compiler_args | ForEach-Object { - write-host $_ -ForegroundColor Cyan - } - write-host "Linker config:" - $linker_args | ForEach-Object { - write-host $_ -ForegroundColor Cyan - } - - $time_taken = Measure-Command { - & $vendor $compiler_args $linker_args 2>&1 | ForEach-Object { - $color = 'White' - switch ($_){ - { $_ -match "error" } { $color = 'Red' ; break } - { $_ -match "warning" } { $color = 'Yellow'; break } - } - write-host `t $_ -ForegroundColor $color - } - } - - # if ( Test-Path($binary) ) { - # write-host "$binary compile & link finished in $($time_taken.TotalMilliseconds) ms" - # } - # else { - # write-host "Compile & Link failed for $binary" -ForegroundColor Red - # } +else { + $optimize = treu } -if ( $vendor -match "clang" ) -{ - # https://clang.llvm.org/docs/ClangCommandLineReference.html - $flag_compile = '-c' - $flag_color_diagnostics = '-fcolor-diagnostics' - $flag_no_color_diagnostics = '-fno-color-diagnostics' - $flag_debug = '-g' - $flag_debug_codeview = '-gcodeview' - $flag_define = '-D' - $flag_preprocess = '-E' - $flag_include = '-I' - $flag_library = '-l' - $flag_library_path = '-L' - $flag_link_win = '-Wl,' - $flag_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE' - $flag_link_win_machine_32 = '/MACHINE:X86' - $flag_link_win_machine_64 = '/MACHINE:X64' - $flag_link_win_debug = '/DEBUG' - $flag_link_win_pdb = '/PDB:' - $flag_link_win_path_output = '/OUT:' - $flag_no_optimization = '-O0' - $flag_path_output = '-o' - $flag_preprocess_non_intergrated = '-no-integrated-cpp' - $flag_profiling_debug = '-fdebug-info-for-profiling' - $flag_target_arch = '-target' - $flag_wall = '-Wall' - $flag_warning = '-W' - $flag_warning_as_error = '-Werror' - $flag_win_nologo = '/nologo' - - $ignore_warning_ms_include = 'no-microsoft-include' - - $target_arch = Get-TargetArchClang - - $warning_ignores = @( - $ignore_warning_ms_include - ) - - # https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-170 - $libraries = @( - 'Kernel32' # For Windows API - # 'msvcrt', # For the C Runtime (Dynamically Linked) - # 'libucrt', - 'libcmt' # For the C Runtime (Static Linkage) - ) - - function build-simple - { - param( $includes, $unit, $executable ) - Write-Host "build-simple: clang" - - $object = $executable -replace '\.exe', '.obj' - $pdb = $executable -replace '\.exe', '.pdb' - - $compiler_args = @( - $flag_no_color_diagnostics, - $flag_target_arch, $target_arch, - $flag_wall, - $flag_preprocess_non_intergrated, - ( $flag_define + 'GEN_TIME' ), - # ( $flag_path_output + $object ), - ( $flag_path_output + $executable ) - ( $flag_include + $includes ) - ) - if ( $release -eq $false ) { - $compiler_args += ( $flag_define + 'Build_Debug' ) - $compiler_args += $flag_debug, $flag_debug_codeview, $flag_profiling_debug - $compiler_args += $flag_no_optimization - } - - $warning_ignores | ForEach-Object { - $compiler_args += $flag_warning + $_ - } - - # $compiler_args += $flag_preprocess - - # $compiler_args += $flag_compile, $unit - # run-compiler $compiler $unit $compiler_args - - $linker_args = @( - $flag_link_win_subsystem_console, - $flag_link_win_machine_64, - $( $flag_link_win_path_output + $executable ) - ) - if ( $release -eq $false ) { - $linker_args += $flag_link_win_debug - $linker_args += $flag_link_win_pdb + $pdb - } - else { - } - - $libraries | ForEach-Object { - $linker_args += $_ + '.lib' - } - - # $linker_args += $object - # run-linker $linker $executable $linker_args - - $compiler_args += $unit - # $linker_args += $object - run-compile-and-link $compiler $unit $compiler_args - } - - $compiler = 'clang++' - $linker = 'lld-link' +if ( $bootstrap -eq $false -and $singleheader -eq $false -and $test -eq $false ) { + throw "No build target specified. One must be specified, this script will not assume one" } -if ( $vendor -match "msvc" ) -{ - # https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170 - $flag_compile = '/c' - $flag_debug = '/Zi' - $flag_define = '/D' - $flag_include = '/I' - $flag_full_src_path = '/FC' - $flag_nologo = '/nologo' - $flag_dll = '/LD' - $flag_dll_debug = '/LDd' - $flag_linker = '/link' - $flag_link_debug = '/DEBUG' - $flag_link_pdb = '/PDB:' - $flag_link_machine_32 = '/MACHINE:X86' - $flag_link_machine_64 = '/MACHINE:X64' - $flag_link_path_output = '/OUT:' - $flag_link_rt_dll = '/MD' - $flag_link_rt_dll_debug = '/MDd' - $flag_link_rt_static = '/MT' - $flag_link_rt_static_debug = '/MTd' - $flag_link_subsystem_console = '/SUBSYSTEM:CONSOLE' - $flag_link_subsystem_windows = '/SUBSYSTEM:WINDOWS' - $flag_no_optimization = '/Od' - $flag_out_name = '/OUT:' - $flag_path_interm = '/Fo' - $flag_path_debug = '/Fd' - $flag_path_output = '/Fe' - $flag_preprocess_conform = '/Zc:preprocessor' - - # This works because this project uses a single unit to build - function build-simple - { - param( $includes, $unit, $executable ) - Write-Host "build-simple: msvc" - - $object = $executable -replace '\.exe', '.obj' - $pdb = $executable -replace '\.exe', '.pdb' - - $compiler_args = @( - $flag_nologo, - $flag_preprocess_conform, - $flag_debug, - ( $flag_define + 'GEN_TIME' ), - $flag_full_src_path, - ( $flag_path_interm + $path_build + '\' ), - ( $flag_path_output + $path_build + '\' ) - ) - if ( $release -eq $false ) { - $compiler_args += ( $flag_define + 'Build_Debug' ) - $compiler_args += ( $flag_path_debug + $path_build + '\' ) - $compiler_args += $flag_link_rt_static_debug - $compiler_args += $flag_no_optimization - } - else { - $compiler_args += $flag_link_rt_static - } - $compiler_args += $includes | ForEach-Object { $flag_include + $_ } - $compiler_args += $flag_compile, $unit - run-compiler $compiler $unit $compiler_args - - $linker_args = @( - $flag_nologo, - $flag_link_machine_64, - $flag_link_subsystem_console, - ( $flag_link_path_output + $executable ) - ) - if ( $release -eq $false ) { - $linker_args += $flag_link_debug - $linker_args += $flag_link_pdb + $pdb - } - else { - } - $linker_args += $object - run-linker $linker $executable $linker_args - } +. $vendor_toolchain +. $incremental_checks - $compiler = 'cl' - $linker = 'link' -} -#endregion Configuration +write-host "Building gencpp with $vendor" +write-host "Build Type: $(if ($release) {"Release"} else {"Debug"} )" #region Building $path_build = Join-Path $path_root build @@ -359,11 +98,18 @@ if ( $bootstrap ) New-Item -ItemType Directory -Path $path_comp_gen } + $compiler_args = @() + $compiler_args += ( $flag_define + 'GEN_TIME' ) + + $linker_args = @( + $flag_link_win_subsystem_console + ) + $includes = @( $path_project) $unit = join-path $path_project "bootstrap.cpp" $executable = join-path $path_build "bootstrap.exe" - build-simple $includes $unit $executable + build-simple $path_build $includes $compiler_args $linker_args $unit $executable Push-Location $path_project if ( Test-Path( $executable ) ) { @@ -394,7 +140,14 @@ if ( $singleheader ) $unit = join-path $path_singleheader "singleheader.cpp" $executable = join-path $path_build "singleheader.exe" - build-simple $includes $unit $executable + $compiler_args = @() + $compiler_args += ( $flag_define + 'GEN_TIME' ) + + $linker_args = @( + $flag_link_win_subsystem_console + ) + + build-simple $path_build $includes $compiler_args $linker_args $unit $executable Push-Location $path_singleheader if ( Test-Path( $executable ) ) { @@ -431,7 +184,14 @@ if ( $test ) $unit = join-path $path_test "test.cpp" $executable = join-path $path_build "test.exe" - build-simple $includes $unit $executable + $compiler_args = @() + $compiler_args += ( $flag_define + 'GEN_TIME' ) + + $linker_args = @( + $flag_link_win_subsystem_console + ) + + build-simple $path_build $includes $compiler_args $linker_args $unit $executable Push-Location $path_test Write-Host $path_test @@ -449,29 +209,7 @@ if ( $test ) #endregion Building #region Formatting -function format-cpp -{ - param( $path, $include, $exclude ) - - # Format generated gencpp - Write-Host "`nBeginning format" - $formatParams = @( - '-i' # In-place - '-style=file:./scripts/.clang-format' - '-verbose' - ) - - $targetFiles = @( - Get-ChildItem -Recurse -Path $path -Include $include -Exclude $exclude - | Select-Object -ExpandProperty FullName - ) - - $time_taken = Measure-Command { - clang-format $formatParams $targetFiles - } - Write-Host "`nFormatting complete in $($time_taken.TotalMilliseconds) ms" -} - +push-location $path_scripts if ( $bootstrap -and (Test-Path (Join-Path $path_project "gen/gen.hpp")) ) { $path_gen = join-path $path_project gen @@ -485,6 +223,7 @@ if ( $bootstrap -and (Test-Path (Join-Path $path_project "gen/gen.hpp")) ) $exclude = $null format-cpp $path_gen $include $exclude format-cpp $path_comp_gen @( 'ast_inlines.hpp', 'ecode.hpp', 'especifier.hpp', 'eoperator.hpp', 'etoktype.cpp' ) $null + } if ( $singleheader -and (Test-Path (Join-Path $path_singleheader "gen/gen.hpp")) ) @@ -506,6 +245,7 @@ if ( $test -and $false ) $exclude = $null format-cpp $path_gen $include $exclude } +pop-location #endregion Formatting Pop-Location # $path_root diff --git a/scripts/helpers/devshell.ps1 b/scripts/helpers/devshell.ps1 index dc68bd3..33ca0ce 100644 --- a/scripts/helpers/devshell.ps1 +++ b/scripts/helpers/devshell.ps1 @@ -23,5 +23,6 @@ if ( -not (Test-Path $vs_devshell) ) { # Launch the Visual Studio Developer Shell Push-Location +write-host @args & $vs_devshell @args Pop-Location diff --git a/scripts/helpers/format_cpp.psm1 b/scripts/helpers/format_cpp.psm1 new file mode 100644 index 0000000..e975494 --- /dev/null +++ b/scripts/helpers/format_cpp.psm1 @@ -0,0 +1,26 @@ +# format_cpp.psm1 + +function format-cpp +{ + param( $path, $include, $exclude ) + + # Format generated gencpp + Write-Host "Beginning format" + $formatParams = @( + '-i' # In-place + '-style=file:.clang-format' + '-verbose' + ) + + $targetFiles = @( + Get-ChildItem -Recurse -Path $path -Include $include -Exclude $exclude + | Select-Object -ExpandProperty FullName + ) + + $time_taken = Measure-Command { + clang-format $formatParams $targetFiles + } + Write-Host "Formatting complete in $($time_taken.TotalMilliseconds) ms`n" +} + +Export-ModuleMember -Function format-cpp diff --git a/scripts/helpers/incremental_checks.ps1 b/scripts/helpers/incremental_checks.ps1 new file mode 100644 index 0000000..97802ce --- /dev/null +++ b/scripts/helpers/incremental_checks.ps1 @@ -0,0 +1,73 @@ +# This is meant to be used with build.ps1, and is not a standalone script. + +function check-FileForChanges +{ + param( + [Parameter(Mandatory=$true)] + [string]$path_file + ) + + if (-not (Test-Path $path_file -PathType Leaf)) { + Write-Error "The provided path is not a valid file: $path_file" + return $false + } + $file_name = Split-Path $path_file -Leaf + $path_csv = Join-Path $path_build ($file_name + "_file_hash.csv") + + $csv_file_hash = $null + if (Test-Path $path_csv) { + $csv_file_hash = Import-Csv $path_csv | Select-Object -ExpandProperty value + } + + $current_hash_info = Get-FileHash -Path $path_file -Algorithm MD5 + $current_file_hash = $current_hash_info.Hash + + # Save the current hash to the CSV + [PSCustomObject]@{ + name = $path_file + value = $current_file_hash + } | Export-Csv $path_csv -NoTypeInformation + + if ($csv_file_hash -and $csv_file_hash -eq $current_file_hash) { + return $false + } else { + return $true + } +} + +# Check to see if the module has changed files since the last build +function check-ModuleForChanges +{ + param( [string]$path_module, [array]$excludes ) + + $module_name = split-path $path_module -leaf + $path_csv = Join-Path $path_build ($module_name + "_module_hashes.csv") + + $csv_file_hashes = $null + if ( test-path $path_csv ) { + $csv_file_hashes = @{} + import-csv $path_csv | foreach-object { + $csv_file_hashes[ $_.name ] = $_.value + } + } + + $file_hashes = @{} + get-childitem -path $path_module -recurse -file -Exclude $excludes | foreach-object { + $id = $_.fullname + $hash_info = get-filehash -path $id -Algorithm MD5 + $file_hashes[ $id ] = $hash_info.Hash + } + + $file_hashes.GetEnumerator() | foreach-object { [PSCustomObject]$_ } | + export-csv $path_csv -NoTypeInformation + + if ( -not $csv_file_hashes ) { return $true } + if ( $csv_file_hashes.Count -ne $file_hashes.Count ) { return $true } + + foreach ( $key in $csv_file_hashes.Keys ) { + if ( $csv_file_hashes[ $key ] -ne $file_hashes[ $key ] ) { + return $true + } + } + return $false +} diff --git a/scripts/helpers/vendor_toolchain.ps1 b/scripts/helpers/vendor_toolchain.ps1 new file mode 100644 index 0000000..39df19f --- /dev/null +++ b/scripts/helpers/vendor_toolchain.ps1 @@ -0,0 +1,525 @@ +# This is meant to be used with build.ps1, and is not a standalone script. + +if ($IsWindows) { + # This HandmadeHero implementation is only designed for 64-bit systems + & $devshell -arch amd64 +} + +if ( $vendor -eq $null ) { + write-host "No vendor specified, assuming clang available" + $vendor = "clang" +} + +if ( $dev ) { + if ( $debug -eq $null ) { + $debug = $true + } + if ( $optimize -eq $null ) { + $optimize = $false + } +} + +function run-compiler +{ + param( $compiler, $unit, $compiler_args ) + + if ( $analysis ) { + $compiler_args += $flag_syntax_only + } + + write-host "`Compiling $unit" + if ( $verbose ) { + write-host "Compiler config:" + $compiler_args | ForEach-Object { + write-host $_ -ForegroundColor Cyan + } + } + + $time_taken = Measure-Command { + & $compiler $compiler_args 2>&1 | ForEach-Object { + $color = 'White' + switch ($_){ + { $_ -match "error" } { $color = 'Red' ; break } + { $_ -match "warning" } { $color = 'Yellow'; break } + } + write-host `t $_ -ForegroundColor $color + } + } + + if ( $LASTEXITCODE -eq 0 ) { + write-host "$unit compile finished in $($time_taken.TotalMilliseconds) ms`n" + return $true + } + else { + write-host "Compile failed for $unit`n" -ForegroundColor Red + return $false + } +} + +function run-linker +{ + param( $linker, $binary, $linker_args ) + + write-host "`Linking $binary" + if ( $verbose ) { + write-host "Linker config:" + $linker_args | ForEach-Object { + write-host $_ -ForegroundColor Cyan + } + } + + $time_taken = Measure-Command { + & $linker $linker_args 2>&1 | ForEach-Object { + $color = 'White' + switch ($_){ + { $_ -match "error" } { $color = 'Red' ; break } + { $_ -match "warning" } { $color = 'Yellow'; break } + } + write-host `t $_ -ForegroundColor $color + } + } + + if ( $LASTEXITCODE -eq 0 ) { + write-host "$binary linking finished in $($time_taken.TotalMilliseconds) ms`n" + return $true + } + else { + write-host "Linking failed for $binary`n" -ForegroundColor Red + return $false + } +} + +if ( $vendor -match "clang" ) +{ + # https://clang.llvm.org/docs/ClangCommandLineReference.html + $flag_all_c = '/TC' + $flag_all_cpp = '/TP' + $flag_compile = '-c' + $flag_color_diagnostics = '-fcolor-diagnostics' + $flag_no_color_diagnostics = '-fno-color-diagnostics' + $flag_debug = '-g' + $flag_debug_codeview = '-gcodeview' + $flag_define = '-D' + $flag_exceptions_disabled = '-fno-exceptions' + $flag_preprocess = '-E' + $flag_include = '-I' + $flag_section_data = '-fdata-sections' + $flag_section_functions = '-ffunction-sections' + $flag_library = '-l' + $flag_library_path = '-L' + $flag_linker = '-Wl,' + if ( $IsWindows ) { + $flag_link_dll = '/DLL' + $flag_link_mapfile = '/MAP:' + $flag_link_optimize_references = '/OPT:REF' + } + if ( $IsLinux ) { + $flag_link_mapfile = '--Map=' + $flag_link_optimize_references = '--gc-sections' + } + $flag_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE' + $flag_link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS' + $flag_link_win_machine_32 = '/MACHINE:X86' + $flag_link_win_machine_64 = '/MACHINE:X64' + $flag_link_win_debug = '/DEBUG' + $flag_link_win_pdb = '/PDB:' + $flag_link_win_path_output = '/OUT:' + $flag_no_optimization = '-O0' + $flag_optimize_fast = '-O2' + $flag_optimize_size = '-O1' + $flag_optimize_intrinsics = '-Oi' + $flag_path_output = '-o' + $flag_preprocess_non_intergrated = '-no-integrated-cpp' + $flag_profiling_debug = '-fdebug-info-for-profiling' + $flag_set_stack_size = '-stack=' + $flag_syntax_only = '-fsyntax-only' + $flag_target_arch = '-target' + $flag_time_trace = '-ftime-trace' + $flag_verbose = '-v' + $flag_wall = '-Wall' + $flag_warning = '-W' + $flag_warnings_as_errors = '-Werror' + $flag_win_nologo = '/nologo' + + $ignore_warning_ms_include = 'no-microsoft-include' + $ignore_warning_return_type_c_linkage = 'no-return-type-c-linkage' + + $target_arch = Get-TargetArchClang + + $warning_ignores = @( + $ignore_warning_ms_include, + $ignore_warning_return_type_c_linkage + ) + + # https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-170 + if ( $IsWindows ) { + $libraries = @( + 'Kernel32' # For Windows API + # 'msvcrt', # For the C Runtime (Dynamically Linked) + # 'libucrt', + 'libcmt' # For the C Runtime (Static Linkage) + ) + } + + function build + { + param( [string]$path_output, [array]$includes, [array]$compiler_args, [array]$linker_args, [array]$units, [string]$binary ) + $result = $false + #Write-Host "build: clang" + + $map = $binary -replace '\.(exe|dll)$', '.map' + $map = join-path $path_output (split-path $map -Leaf) + + # This allows dll reloads at runtime to work (jankily, use below if not interested) + $pdb = $binary -replace '\.(exe|dll)$', "_$(get-random).pdb" + # $pdb = $binary -replace '\.(exe|dll)$', ".pdb" + + $compiler_args += @( + $flag_no_color_diagnostics, + $flag_exceptions_disabled, + $flag_target_arch, $target_arch, + $flag_wall, + $flag_preprocess_non_intergrated + # $flag_section_data, + # $flag_section_functions, + ) + if ( $verbose ) { + # $compiler_args += $flag_verbose + # $compiler_args += $flag_time_trace + } + if ( $optimize ) { + $compiler_args += $flag_optimize_fast + } + else { + $compiler_args += $flag_no_optimization + } + if ( $debug ) { + $compiler_args += ( $flag_define + 'Build_Debug=1' ) + $compiler_args += $flag_debug, $flag_debug_codeview, $flag_profiling_debug + } + else { + $compiler_args += ( $flag_define + 'Build_Debug=0' ) + } + + $warning_ignores | ForEach-Object { + $compiler_args += $flag_warning + $_ + } + $compiler_args += $includes | ForEach-Object { $flag_include + $_ } + + $objects = @() + foreach ( $unit in $units ) + { + $object = $unit -replace '\.(cpp|c)$', '.obj' + $object = join-path $path_output (split-path $object -Leaf) + $objects += $object + + $unit_compiler_args = $compiler_args + $unit_compiler_args += ( $flag_path_output + $object ) + + $unit_compiler_args += $flag_compile, $unit + run-compiler $compiler $unit $unit_compiler_args + } + + $linker_args += @( + $flag_link_win_machine_64, + $( $flag_link_win_path_output + $binary ) + ) + if ( $debug ) { + $linker_args += $flag_link_win_debug + $linker_args += $flag_link_win_pdb + $pdb + $linker_args += $flag_link_mapfile + $map + } + + $libraries | ForEach-Object { + $linker_args += $_ + '.lib' + } + + $linker_args += $objects + return run-linker $linker $binary $linker_args + } + + function build-simple + { + param( [string]$path_output, [array]$includes, [array]$compiler_args, [array]$linker_args, [string]$unit, [string]$binary ) + $result = $false + #Write-Host "build-simple: clang" + + $object = $unit -replace '\.(cpp|c)$', '.obj' + $map = $unit -replace '\.(cpp|c)$', '.map' + $object = join-path $path_output (split-path $object -Leaf) + $map = join-path $path_output (split-path $map -Leaf) + + # This allows dll reloads at runtime to work (jankily, use below if not interested) + $pdb = $binary -replace '\.(exe|dll)$', "_$(get-random).pdb" + # $pdb = $binary -replace '\.(exe|dll)$', ".pdb" + + $compiler_args += @( + $flag_no_color_diagnostics, + $flag_exceptions_disabled, + $flag_target_arch, $target_arch, + $flag_wall, + $flag_preprocess_non_intergrated, + # $flag_section_data, + # $flag_section_functions, + ( $flag_path_output + $object ) + ) + if ( $verbose ) { + # $compiler_args += $flag_verbose + # $compiler_args += $flag_time_trace + } + if ( $optimize ) { + $compiler_args += $flag_optimize_fast + } + else { + $compiler_args += $flag_no_optimization + } + if ( $debug ) { + $compiler_args += ( $flag_define + 'Build_Debug=1' ) + $compiler_args += $flag_debug, $flag_debug_codeview, $flag_profiling_debug + } + else { + $compiler_args += ( $flag_define + 'Build_Debug=0' ) + } + + $warning_ignores | ForEach-Object { + $compiler_args += $flag_warning + $_ + } + $compiler_args += $includes | ForEach-Object { $flag_include + $_ } + + $compiler_args += $flag_compile, $unit + if ( (run-compiler $compiler $unit $compiler_args) -eq $false ) { + return $false + } + + $linker_args += @( + $flag_link_win_machine_64, + $( $flag_link_win_path_output + $binary ) + ) + if ( $debug ) { + $linker_args += $flag_link_win_debug + $linker_args += $flag_link_win_pdb + $pdb + $linker_args += $flag_link_mapfile + $map + } + + $libraries | ForEach-Object { + $linker_args += $_ + '.lib' + } + + $linker_args += $object + return run-linker $linker $binary $linker_args + } + + $compiler = 'clang++' + $linker = 'lld-link' +} + +if ( $vendor -match "msvc" ) +{ + # https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170 + $flag_all_c = '/TC' + $flag_all_cpp = '/TP' + $flag_compile = '/c' + $flag_debug = '/Zi' + $flag_define = '/D' + $flag_exceptions_disabled = '/EHsc-' + $flag_RTTI_disabled = '/GR-' + $flag_include = '/I' + $flag_full_src_path = '/FC' + $flag_nologo = '/nologo' + $flag_dll = '/LD' + $flag_dll_debug = '/LDd' + $flag_linker = '/link' + $flag_link_dll = '/DLL' + $flag_link_no_incremental = '/INCREMENTAL:NO' + $flag_link_mapfile = '/MAP:' + $flag_link_optimize_references = '/OPT:REF' + $flag_link_win_debug = '/DEBUG' + $flag_link_win_pdb = '/PDB:' + $flag_link_win_machine_32 = '/MACHINE:X86' + $flag_link_win_machine_64 = '/MACHINE:X64' + $flag_link_win_path_output = '/OUT:' + $flag_link_win_rt_dll = '/MD' + $flag_link_win_rt_dll_debug = '/MDd' + $flag_link_win_rt_static = '/MT' + $flag_link_win_rt_static_debug = '/MTd' + $flag_link_win_subsystem_console = '/SUBSYSTEM:CONSOLE' + $flag_link_win_subsystem_windows = '/SUBSYSTEM:WINDOWS' + $flag_no_optimization = '/Od' + $flag_optimize_fast = '/O2' + $flag_optimize_size = '/O1' + $flag_optimize_intrinsics = '/Oi' + $flag_optimized_debug = '/Zo' + $flag_out_name = '/OUT:' + $flag_path_interm = '/Fo' + $flag_path_debug = '/Fd' + $flag_path_output = '/Fe' + $flag_preprocess_conform = '/Zc:preprocessor' + $flag_set_stack_size = '/F' + $flag_syntax_only = '/Zs' + $flag_wall = '/Wall' + $flag_warnings_as_errors = '/WX' + + function build + { + param( [string]$path_output, [array]$includes, [array]$compiler_args, [array]$linker_args, [array]$units, [string]$binary ) + $result = $false + #Write-Host "build-simple: msvc" + + $map = $binary -replace '\.(exe|dll)$', '.map' + $map = join-path $path_output (split-path $map -Leaf) + + # This allows dll reloads at runtime to work (jankily, use below if not interested) + $pdb = $binary -replace '\.(exe|dll)$', "_$(get-random).pdb" + # $pdb = $binary -replace '\.(exe|dll)$', ".pdb" + + $compiler_args += @( + $flag_nologo, + # $flag_all_cpp, + $flag_exceptions_disabled, + ( $flag_define + '_HAS_EXCEPTIONS=0' ), + $flag_RTTI_disabled, + $flag_preprocess_conform, + $flag_full_src_path, + ( $flag_path_interm + $path_output + '\' ), + ( $flag_path_output + $path_output + '\' ) + ) + + if ( $verbose ) { + } + + if ( $optimize ) { + $compiler_args += $flag_optimize_fast + } + else { + $compiler_args += $flag_no_optimization + } + + if ( $debug ) + { + $compiler_args += $flag_debug + $compiler_args += ( $flag_define + 'Build_Debug=1' ) + $compiler_args += ( $flag_path_debug + $path_output + '\' ) + $compiler_args += $flag_link_win_rt_static_debug + + if ( $optimize ) { + $compiler_args += $flag_optimized_debug + } + } + else { + $compiler_args += ( $flag_define + 'Build_Debug=0' ) + $compiler_args += $flag_link_win_rt_static + } + $compiler_args += $includes | ForEach-Object { $flag_include + $_ } + + $objects = @() + foreach ( $unit in $units ) + { + $object = $unit -replace '\.(cpp|c)$', '.obj' + $object = join-path $path_output (split-path $object -Leaf) + $objects += $object + + $unit_compiler_args = $compiler_args + # $unit_compiler_args += ( $flag_path_output + $object ) + + $unit_compiler_args += $flag_compile, $unit + run-compiler $compiler $unit $unit_compiler_args + } + + $linker_args += @( + $flag_nologo, + $flag_link_win_machine_64, + $flag_link_no_incremental, + ( $flag_link_win_path_output + $binary ) + ) + if ( $debug ) { + $linker_args += $flag_link_win_debug + $linker_args += $flag_link_win_pdb + $pdb + $linker_args += $flag_link_mapfile + $map + } + else { + } + + $linker_args += $objects + return run-linker $linker $binary $linker_args + } + + function build-simple + { + param( [string]$path_output, [array]$includes, [array]$compiler_args, [array]$linker_args, [string]$unit, [string]$binary ) + $result = $false + #Write-Host "build-simple: msvc" + + $object = $unit -replace '\.(cpp|c)$', '.obj' + $map = $unit -replace '\.(cpp|c)$', '.map' + $object = join-path $path_output (split-path $object -Leaf) + $map = join-path $path_output (split-path $map -Leaf) + + # This allows dll reloads at runtime to work (jankily, use below if not interested) + $pdb = $binary -replace '\.(exe|dll)$', "_$(get-random).pdb" + # $pdb = $binary -replace '\.(exe|dll)$', ".pdb" + + $compiler_args += @( + $flag_nologo, + # $flag_all_cpp, + $flag_exceptions_disabled, + ( $flag_define + '_HAS_EXCEPTIONS=0' ), + $flag_RTTI_disabled, + $flag_preprocess_conform, + $flag_full_src_path, + ( $flag_path_interm + $path_output + '\' ), + ( $flag_path_output + $path_output + '\' ) + ) + + if ( $verbose ) { + } + + if ( $optimize ) { + $compiler_args += $flag_optimize_fast + } + else { + $compiler_args += $flag_no_optimization + } + + if ( $debug ) + { + $compiler_args += $flag_debug + $compiler_args += ( $flag_define + 'Build_Debug=1' ) + $compiler_args += ( $flag_path_debug + $path_output + '\' ) + $compiler_args += $flag_link_win_rt_static_debug + + if ( $optimize ) { + $compiler_args += $flag_optimized_debug + } + } + else { + $compiler_args += ( $flag_define + 'Build_Debug=0' ) + $compiler_args += $flag_link_win_rt_static + } + $compiler_args += $includes | ForEach-Object { $flag_include + $_ } + + $compiler_args += $flag_compile, $unit + if ( (run-compiler $compiler $unit $compiler_args) -eq $false ) { + return $false; + } + + $linker_args += @( + $flag_nologo, + $flag_link_win_machine_64, + $flag_link_no_incremental, + ( $flag_link_win_path_output + $binary ) + ) + if ( $debug ) { + $linker_args += $flag_link_win_debug + $linker_args += $flag_link_win_pdb + $pdb + $linker_args += $flag_link_mapfile + $map + } + else { + } + + $linker_args += $object + return run-linker $linker $binary $linker_args + } + + $compiler = 'cl' + $linker = 'link' +}