Update C sources
This commit is contained in:
parent
dd222de786
commit
b83dec57b5
14 changed files with 2900 additions and 1289 deletions
|
@ -6,7 +6,7 @@
|
||||||
*
|
*
|
||||||
* LICENSE: zlib/libpng
|
* LICENSE: zlib/libpng
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018-2021 Ahmad Fatoum & Ramon Santamaria (@raysan5)
|
* Copyright (c) 2018-2022 Ahmad Fatoum & Ramon Santamaria (@raysan5)
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
* 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.
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -26,7 +26,17 @@
|
||||||
**********************************************************************************************/
|
**********************************************************************************************/
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: core - Configuration Flags
|
// Module selection - Some modules could be avoided
|
||||||
|
// Mandatory modules: rcore, rlgl, utils
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
#define SUPPORT_MODULE_RSHAPES 1
|
||||||
|
#define SUPPORT_MODULE_RTEXTURES 1
|
||||||
|
#define SUPPORT_MODULE_RTEXT 1 // WARNING: It requires SUPPORT_MODULE_RTEXTURES to load sprite font textures
|
||||||
|
#define SUPPORT_MODULE_RMODELS 1
|
||||||
|
#define 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
|
// Camera module is included (rcamera.h) and multiple predefined cameras are available: free, 1st/3rd person, orbital
|
||||||
#define SUPPORT_CAMERA_SYSTEM 1
|
#define SUPPORT_CAMERA_SYSTEM 1
|
||||||
|
@ -36,8 +46,6 @@
|
||||||
#define SUPPORT_MOUSE_GESTURES 1
|
#define SUPPORT_MOUSE_GESTURES 1
|
||||||
// Reconfigure standard input to receive key inputs, works with SSH connection.
|
// Reconfigure standard input to receive key inputs, works with SSH connection.
|
||||||
#define SUPPORT_SSH_KEYBOARD_RPI 1
|
#define SUPPORT_SSH_KEYBOARD_RPI 1
|
||||||
// Draw a mouse pointer on screen
|
|
||||||
//#define SUPPORT_MOUSE_CURSOR_POINT 1
|
|
||||||
// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions.
|
// 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.
|
// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often.
|
||||||
#define SUPPORT_WINMM_HIGHRES_TIMER 1
|
#define SUPPORT_WINMM_HIGHRES_TIMER 1
|
||||||
|
@ -53,8 +61,6 @@
|
||||||
#define SUPPORT_GIF_RECORDING 1
|
#define SUPPORT_GIF_RECORDING 1
|
||||||
// Support CompressData() and DecompressData() functions
|
// Support CompressData() and DecompressData() functions
|
||||||
#define SUPPORT_COMPRESSION_API 1
|
#define SUPPORT_COMPRESSION_API 1
|
||||||
// Support saving binary data automatically to a generated storage.data file. This file is managed internally.
|
|
||||||
#define SUPPORT_DATA_STORAGE 1
|
|
||||||
// Support automatic generated events, loading and recording of those events when required
|
// Support automatic generated events, loading and recording of those events when required
|
||||||
//#define SUPPORT_EVENTS_AUTOMATION 1
|
//#define SUPPORT_EVENTS_AUTOMATION 1
|
||||||
// Support custom frame control, only for advance users
|
// Support custom frame control, only for advance users
|
||||||
|
@ -62,21 +68,19 @@
|
||||||
// Enabling this flag allows manual control of the frame processes, use at your own risk
|
// Enabling this flag allows manual control of the frame processes, use at your own risk
|
||||||
//#define SUPPORT_CUSTOM_FRAME_CONTROL 1
|
//#define SUPPORT_CUSTOM_FRAME_CONTROL 1
|
||||||
|
|
||||||
// core: Configuration values
|
// rcore: Configuration values
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
#if defined(__linux__)
|
#define MAX_FILEPATH_CAPACITY 8192 // Maximum file paths capacity
|
||||||
#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
|
#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
|
||||||
#else
|
|
||||||
#define MAX_FILEPATH_LENGTH 512 // Maximum length supported for filepaths
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define MAX_GAMEPADS 4 // Max number of gamepads supported
|
#define MAX_KEYBOARD_KEYS 512 // Maximum number of keyboard keys supported
|
||||||
#define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad)
|
#define MAX_MOUSE_BUTTONS 8 // Maximum number of mouse buttons supported
|
||||||
#define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad)
|
#define MAX_GAMEPADS 4 // Maximum number of gamepads supported
|
||||||
|
#define MAX_GAMEPAD_AXIS 8 // Maximum number of axis supported (per gamepad)
|
||||||
|
#define MAX_GAMEPAD_BUTTONS 32 // Maximum number of buttons supported (per gamepad)
|
||||||
#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
|
#define MAX_TOUCH_POINTS 8 // Maximum number of touch points supported
|
||||||
#define MAX_KEY_PRESSED_QUEUE 16 // Max number of characters in the key input queue
|
#define MAX_KEY_PRESSED_QUEUE 16 // Maximum number of keys in the key input queue
|
||||||
|
#define MAX_CHAR_PRESSED_QUEUE 16 // Maximum number of characters in the char input queue
|
||||||
#define STORAGE_DATA_FILE "storage.data" // Automatic storage filename
|
|
||||||
|
|
||||||
#define MAX_DECOMPRESSION_SIZE 64 // Max size allocated for decompression in MB
|
#define MAX_DECOMPRESSION_SIZE 64 // Max size allocated for decompression in MB
|
||||||
|
|
||||||
|
@ -124,7 +128,7 @@
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: shapes - Configuration Flags
|
// Module: rshapes - Configuration Flags
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Use QUADS instead of TRIANGLES for drawing when possible
|
// Use QUADS instead of TRIANGLES for drawing when possible
|
||||||
// Some lines-based shapes could still use lines
|
// Some lines-based shapes could still use lines
|
||||||
|
@ -132,7 +136,7 @@
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: textures - Configuration Flags
|
// Module: rtextures - Configuration Flags
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Selecte desired fileformats to be supported for image data loading
|
// Selecte desired fileformats to be supported for image data loading
|
||||||
#define SUPPORT_FILEFORMAT_PNG 1
|
#define SUPPORT_FILEFORMAT_PNG 1
|
||||||
|
@ -140,6 +144,7 @@
|
||||||
//#define SUPPORT_FILEFORMAT_TGA 1
|
//#define SUPPORT_FILEFORMAT_TGA 1
|
||||||
#define SUPPORT_FILEFORMAT_JPG 1
|
#define SUPPORT_FILEFORMAT_JPG 1
|
||||||
#define SUPPORT_FILEFORMAT_GIF 1
|
#define SUPPORT_FILEFORMAT_GIF 1
|
||||||
|
#define SUPPORT_FILEFORMAT_QOI 1
|
||||||
//#define SUPPORT_FILEFORMAT_PSD 1
|
//#define SUPPORT_FILEFORMAT_PSD 1
|
||||||
#define SUPPORT_FILEFORMAT_DDS 1
|
#define SUPPORT_FILEFORMAT_DDS 1
|
||||||
#define SUPPORT_FILEFORMAT_HDR 1
|
#define SUPPORT_FILEFORMAT_HDR 1
|
||||||
|
@ -148,7 +153,7 @@
|
||||||
//#define SUPPORT_FILEFORMAT_PKM 1
|
//#define SUPPORT_FILEFORMAT_PKM 1
|
||||||
//#define SUPPORT_FILEFORMAT_PVR 1
|
//#define SUPPORT_FILEFORMAT_PVR 1
|
||||||
|
|
||||||
// Support image export functionality (.png, .bmp, .tga, .jpg)
|
// Support image export functionality (.png, .bmp, .tga, .jpg, .qoi)
|
||||||
#define SUPPORT_IMAGE_EXPORT 1
|
#define SUPPORT_IMAGE_EXPORT 1
|
||||||
// Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
|
// Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
|
||||||
#define SUPPORT_IMAGE_GENERATION 1
|
#define SUPPORT_IMAGE_GENERATION 1
|
||||||
|
@ -158,7 +163,7 @@
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: text - Configuration Flags
|
// Module: rtext - Configuration Flags
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Default font is loaded on window initialization to be available for the user to render simple text
|
// 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
|
// NOTE: If enabled, uses external module functions to load default raylib font
|
||||||
|
@ -171,7 +176,7 @@
|
||||||
// If not defined, still some functions are supported: TextLength(), TextFormat()
|
// If not defined, still some functions are supported: TextLength(), TextFormat()
|
||||||
#define SUPPORT_TEXT_MANIPULATION 1
|
#define SUPPORT_TEXT_MANIPULATION 1
|
||||||
|
|
||||||
// text: Configuration values
|
// rtext: Configuration values
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
|
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
|
||||||
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
|
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
|
||||||
|
@ -179,7 +184,7 @@
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: models - Configuration Flags
|
// Module: rmodels - Configuration Flags
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Selected desired model fileformats to be supported for loading
|
// Selected desired model fileformats to be supported for loading
|
||||||
#define SUPPORT_FILEFORMAT_OBJ 1
|
#define SUPPORT_FILEFORMAT_OBJ 1
|
||||||
|
@ -187,17 +192,18 @@
|
||||||
#define SUPPORT_FILEFORMAT_IQM 1
|
#define SUPPORT_FILEFORMAT_IQM 1
|
||||||
#define SUPPORT_FILEFORMAT_GLTF 1
|
#define SUPPORT_FILEFORMAT_GLTF 1
|
||||||
#define SUPPORT_FILEFORMAT_VOX 1
|
#define SUPPORT_FILEFORMAT_VOX 1
|
||||||
|
#define SUPPORT_FILEFORMAT_M3D 1
|
||||||
// Support procedural mesh generation functions, uses external par_shapes.h library
|
// Support procedural mesh generation functions, uses external par_shapes.h library
|
||||||
// NOTE: Some generated meshes DO NOT include generated texture coordinates
|
// NOTE: Some generated meshes DO NOT include generated texture coordinates
|
||||||
#define SUPPORT_MESH_GENERATION 1
|
#define SUPPORT_MESH_GENERATION 1
|
||||||
|
|
||||||
// models: Configuration values
|
// rmodels: Configuration values
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
#define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported
|
#define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported
|
||||||
#define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh
|
#define MAX_MESH_VERTEX_BUFFERS 7 // Maximum vertex buffers (VBO) per mesh
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: audio - Configuration Flags
|
// Module: raudio - Configuration Flags
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Desired audio fileformats to be supported for loading
|
// Desired audio fileformats to be supported for loading
|
||||||
#define SUPPORT_FILEFORMAT_WAV 1
|
#define SUPPORT_FILEFORMAT_WAV 1
|
||||||
|
@ -207,7 +213,7 @@
|
||||||
#define SUPPORT_FILEFORMAT_MP3 1
|
#define SUPPORT_FILEFORMAT_MP3 1
|
||||||
//#define SUPPORT_FILEFORMAT_FLAC 1
|
//#define SUPPORT_FILEFORMAT_FLAC 1
|
||||||
|
|
||||||
// audio: Configuration values
|
// raudio: Configuration values
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
#define AUDIO_DEVICE_FORMAT ma_format_f32 // Device output format (miniaudio: float-32bit)
|
#define AUDIO_DEVICE_FORMAT ma_format_f32 // Device output format (miniaudio: float-32bit)
|
||||||
#define AUDIO_DEVICE_CHANNELS 2 // Device output channels: stereo
|
#define AUDIO_DEVICE_CHANNELS 2 // Device output channels: stereo
|
||||||
|
|
539
raylib/raudio.c
539
raylib/raudio.c
File diff suppressed because it is too large
Load diff
117
raylib/raylib.h
117
raylib/raylib.h
|
@ -1,6 +1,6 @@
|
||||||
/**********************************************************************************************
|
/**********************************************************************************************
|
||||||
*
|
*
|
||||||
* raylib v4.0 - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com)
|
* raylib v4.2 - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com)
|
||||||
*
|
*
|
||||||
* FEATURES:
|
* FEATURES:
|
||||||
* - NO external dependencies, all required libraries included with raylib
|
* - NO external dependencies, all required libraries included with raylib
|
||||||
|
@ -33,8 +33,8 @@
|
||||||
*
|
*
|
||||||
* OPTIONAL DEPENDENCIES (included):
|
* OPTIONAL DEPENDENCIES (included):
|
||||||
* [rcore] msf_gif (Miles Fogle) for GIF recording
|
* [rcore] msf_gif (Miles Fogle) for GIF recording
|
||||||
* [rcore] sinfl (Micha Mettke) for DEFLATE decompression algorythm
|
* [rcore] sinfl (Micha Mettke) for DEFLATE decompression algorithm
|
||||||
* [rcore] sdefl (Micha Mettke) for DEFLATE compression algorythm
|
* [rcore] sdefl (Micha Mettke) for DEFLATE compression algorithm
|
||||||
* [rtextures] stb_image (Sean Barret) for images loading (BMP, TGA, PNG, JPEG, HDR...)
|
* [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_write (Sean Barret) for image writing (BMP, TGA, PNG, JPG)
|
||||||
* [rtextures] stb_image_resize (Sean Barret) for image resizing algorithms
|
* [rtextures] stb_image_resize (Sean Barret) for image resizing algorithms
|
||||||
|
@ -43,6 +43,7 @@
|
||||||
* [rmodels] par_shapes (Philip Rideout) for parametric 3d shapes generation
|
* [rmodels] par_shapes (Philip Rideout) for parametric 3d shapes generation
|
||||||
* [rmodels] tinyobj_loader_c (Syoyo Fujita) for models loading (OBJ, MTL)
|
* [rmodels] tinyobj_loader_c (Syoyo Fujita) for models loading (OBJ, MTL)
|
||||||
* [rmodels] cgltf (Johannes Kuhlmann) for models loading (glTF)
|
* [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_wav (David Reid) for WAV audio file loading
|
||||||
* [raudio] dr_flac (David Reid) for FLAC audio file loading
|
* [raudio] dr_flac (David Reid) for FLAC audio file loading
|
||||||
* [raudio] dr_mp3 (David Reid) for MP3 audio file loading
|
* [raudio] dr_mp3 (David Reid) for MP3 audio file loading
|
||||||
|
@ -56,7 +57,7 @@
|
||||||
* raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
* 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:
|
* BSD-like license that allows static linking with closed source software:
|
||||||
*
|
*
|
||||||
* Copyright (c) 2013-2021 Ramon Santamaria (@raysan5)
|
* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5)
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
* 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.
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -80,12 +81,15 @@
|
||||||
|
|
||||||
#include <stdarg.h> // Required for: va_list - Only used by TraceLogCallback
|
#include <stdarg.h> // Required for: va_list - Only used by TraceLogCallback
|
||||||
|
|
||||||
#define RAYLIB_VERSION "4.0"
|
#define RAYLIB_VERSION "4.2"
|
||||||
|
|
||||||
// Function specifiers in case library is build/used as a shared library (Windows)
|
// 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
|
// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#if defined(BUILD_LIBTYPE_SHARED)
|
#if defined(BUILD_LIBTYPE_SHARED)
|
||||||
|
#if defined(__TINYC__)
|
||||||
|
#define __declspec(x) __attribute__((x))
|
||||||
|
#endif
|
||||||
#define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll)
|
#define RLAPI __declspec(dllexport) // We are building the library as a Win32 shared library (.dll)
|
||||||
#elif defined(USE_LIBTYPE_SHARED)
|
#elif defined(USE_LIBTYPE_SHARED)
|
||||||
#define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll)
|
#define RLAPI __declspec(dllimport) // We are using the library as a Win32 shared library (.dll)
|
||||||
|
@ -110,6 +114,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Allow custom memory allocators
|
// Allow custom memory allocators
|
||||||
|
// NOTE: Require recompiling raylib sources
|
||||||
#ifndef RL_MALLOC
|
#ifndef RL_MALLOC
|
||||||
#define RL_MALLOC(sz) malloc(sz)
|
#define RL_MALLOC(sz) malloc(sz)
|
||||||
#endif
|
#endif
|
||||||
|
@ -177,10 +182,10 @@
|
||||||
// Structures Definition
|
// Structures Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Boolean type
|
// Boolean type
|
||||||
#if defined(__STDC__) && __STDC_VERSION__ >= 199901L
|
#if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#elif !defined(__cplusplus) && !defined(bool)
|
#elif !defined(__cplusplus) && !defined(bool)
|
||||||
typedef enum bool { false, true } bool;
|
typedef enum bool { false = 0, true = !false } bool;
|
||||||
#define RL_BOOL_TYPE
|
#define RL_BOOL_TYPE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -322,7 +327,7 @@ typedef struct Mesh {
|
||||||
// Vertex attributes data
|
// Vertex attributes data
|
||||||
float *vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
|
float *vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
|
||||||
float *texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
|
float *texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
|
||||||
float *texcoords2; // Vertex second texture coordinates (useful for lightmaps) (shader-location = 5)
|
float *texcoords2; // Vertex texture second coordinates (UV - 2 components per vertex) (shader-location = 5)
|
||||||
float *normals; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
|
float *normals; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
|
||||||
float *tangents; // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4)
|
float *tangents; // Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4)
|
||||||
unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
|
unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
|
||||||
|
@ -425,11 +430,15 @@ typedef struct Wave {
|
||||||
void *data; // Buffer data pointer
|
void *data; // Buffer data pointer
|
||||||
} Wave;
|
} Wave;
|
||||||
|
|
||||||
|
// Opaque structs declaration
|
||||||
|
// NOTE: Actual structs are defined internally in raudio module
|
||||||
typedef struct rAudioBuffer rAudioBuffer;
|
typedef struct rAudioBuffer rAudioBuffer;
|
||||||
|
typedef struct rAudioProcessor rAudioProcessor;
|
||||||
|
|
||||||
// AudioStream, custom audio stream
|
// AudioStream, custom audio stream
|
||||||
typedef struct AudioStream {
|
typedef struct AudioStream {
|
||||||
rAudioBuffer *buffer; // Pointer to internal data used by the audio system
|
rAudioBuffer *buffer; // Pointer to internal data used by the audio system
|
||||||
|
rAudioProcessor *processor; // Pointer to internal data processor, useful for audio effects
|
||||||
|
|
||||||
unsigned int sampleRate; // Frequency (samples per second)
|
unsigned int sampleRate; // Frequency (samples per second)
|
||||||
unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
|
unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
|
||||||
|
@ -478,6 +487,13 @@ typedef struct VrStereoConfig {
|
||||||
float scaleIn[2]; // VR distortion scale in
|
float scaleIn[2]; // VR distortion scale in
|
||||||
} VrStereoConfig;
|
} VrStereoConfig;
|
||||||
|
|
||||||
|
// File path list
|
||||||
|
typedef struct FilePathList {
|
||||||
|
unsigned int capacity; // Filepaths max entries
|
||||||
|
unsigned int count; // Filepaths entries count
|
||||||
|
char **paths; // Filepaths entries
|
||||||
|
} FilePathList;
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Enumerators Definition
|
// Enumerators Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -497,6 +513,7 @@ typedef enum {
|
||||||
FLAG_WINDOW_ALWAYS_RUN = 0x00000100, // Set to allow windows running while minimized
|
FLAG_WINDOW_ALWAYS_RUN = 0x00000100, // Set to allow windows running while minimized
|
||||||
FLAG_WINDOW_TRANSPARENT = 0x00000010, // Set to allow transparent framebuffer
|
FLAG_WINDOW_TRANSPARENT = 0x00000010, // Set to allow transparent framebuffer
|
||||||
FLAG_WINDOW_HIGHDPI = 0x00002000, // Set to support HighDPI
|
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_MSAA_4X_HINT = 0x00000020, // Set to try enabling MSAA 4X
|
FLAG_MSAA_4X_HINT = 0x00000020, // Set to try enabling MSAA 4X
|
||||||
FLAG_INTERLACED_HINT = 0x00010000 // Set to try enabling interlaced video format (for V3D)
|
FLAG_INTERLACED_HINT = 0x00010000 // Set to try enabling interlaced video format (for V3D)
|
||||||
} ConfigFlags;
|
} ConfigFlags;
|
||||||
|
@ -799,7 +816,7 @@ typedef enum {
|
||||||
// NOTE 1: Filtering considers mipmaps if available in the texture
|
// NOTE 1: Filtering considers mipmaps if available in the texture
|
||||||
// NOTE 2: Filter is accordingly set for minification and magnification
|
// NOTE 2: Filter is accordingly set for minification and magnification
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TEXTURE_FILTER_POINT = 0, // No filter, just pixel aproximation
|
TEXTURE_FILTER_POINT = 0, // No filter, just pixel approximation
|
||||||
TEXTURE_FILTER_BILINEAR, // Linear filtering
|
TEXTURE_FILTER_BILINEAR, // Linear filtering
|
||||||
TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps)
|
TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps)
|
||||||
TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x
|
TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x
|
||||||
|
@ -839,7 +856,8 @@ typedef enum {
|
||||||
BLEND_MULTIPLIED, // Blend textures multiplying colors
|
BLEND_MULTIPLIED, // Blend textures multiplying colors
|
||||||
BLEND_ADD_COLORS, // Blend textures adding colors (alternative)
|
BLEND_ADD_COLORS, // Blend textures adding colors (alternative)
|
||||||
BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative)
|
BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative)
|
||||||
BLEND_CUSTOM // Belnd textures using custom src/dst factors (use rlSetBlendMode())
|
BLEND_ALPHA_PREMULTIPLY, // Blend premultiplied textures considering alpha
|
||||||
|
BLEND_CUSTOM // Blend textures using custom src/dst factors (use rlSetBlendMode())
|
||||||
} BlendMode;
|
} BlendMode;
|
||||||
|
|
||||||
// Gesture
|
// Gesture
|
||||||
|
@ -913,7 +931,7 @@ RLAPI bool IsWindowMaximized(void); // Check if wi
|
||||||
RLAPI bool IsWindowFocused(void); // Check if window is currently focused (only PLATFORM_DESKTOP)
|
RLAPI bool IsWindowFocused(void); // Check if window is currently focused (only PLATFORM_DESKTOP)
|
||||||
RLAPI bool IsWindowResized(void); // Check if window has been resized last frame
|
RLAPI bool IsWindowResized(void); // Check if window has been resized last frame
|
||||||
RLAPI bool IsWindowState(unsigned int flag); // Check if one specific window flag is enabled
|
RLAPI bool IsWindowState(unsigned int flag); // Check if one specific window flag is enabled
|
||||||
RLAPI void SetWindowState(unsigned int flags); // Set window configuration state using flags
|
RLAPI void SetWindowState(unsigned int flags); // Set window configuration state using flags (only PLATFORM_DESKTOP)
|
||||||
RLAPI void ClearWindowState(unsigned int flags); // Clear window configuration state flags
|
RLAPI void ClearWindowState(unsigned int flags); // Clear window configuration state flags
|
||||||
RLAPI void ToggleFullscreen(void); // Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP)
|
RLAPI void ToggleFullscreen(void); // Toggle window state: fullscreen/windowed (only PLATFORM_DESKTOP)
|
||||||
RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable (only PLATFORM_DESKTOP)
|
RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable (only PLATFORM_DESKTOP)
|
||||||
|
@ -925,14 +943,17 @@ RLAPI void SetWindowPosition(int x, int y); // Set window
|
||||||
RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window (fullscreen mode)
|
RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window (fullscreen mode)
|
||||||
RLAPI void SetWindowMinSize(int width, int height); // Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE)
|
RLAPI void SetWindowMinSize(int width, int height); // Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE)
|
||||||
RLAPI void SetWindowSize(int width, int height); // Set window dimensions
|
RLAPI void SetWindowSize(int width, int height); // Set window dimensions
|
||||||
|
RLAPI void SetWindowOpacity(float opacity); // Set window opacity [0.0f..1.0f] (only PLATFORM_DESKTOP)
|
||||||
RLAPI void *GetWindowHandle(void); // Get native window handle
|
RLAPI void *GetWindowHandle(void); // Get native window handle
|
||||||
RLAPI int GetScreenWidth(void); // Get current screen width
|
RLAPI int GetScreenWidth(void); // Get current screen width
|
||||||
RLAPI int GetScreenHeight(void); // Get current screen height
|
RLAPI int GetScreenHeight(void); // Get current screen height
|
||||||
|
RLAPI int GetRenderWidth(void); // Get current render width (it considers HiDPI)
|
||||||
|
RLAPI int GetRenderHeight(void); // Get current render height (it considers HiDPI)
|
||||||
RLAPI int GetMonitorCount(void); // Get number of connected monitors
|
RLAPI int GetMonitorCount(void); // Get number of connected monitors
|
||||||
RLAPI int GetCurrentMonitor(void); // Get current connected monitor
|
RLAPI int GetCurrentMonitor(void); // Get current connected monitor
|
||||||
RLAPI Vector2 GetMonitorPosition(int monitor); // Get specified monitor position
|
RLAPI Vector2 GetMonitorPosition(int monitor); // Get specified monitor position
|
||||||
RLAPI int GetMonitorWidth(int monitor); // Get specified monitor width (max available by monitor)
|
RLAPI int GetMonitorWidth(int monitor); // Get specified monitor width (current video mode used by monitor)
|
||||||
RLAPI int GetMonitorHeight(int monitor); // Get specified monitor height (max available by monitor)
|
RLAPI int GetMonitorHeight(int monitor); // Get specified monitor height (current video mode used by monitor)
|
||||||
RLAPI int GetMonitorPhysicalWidth(int monitor); // Get specified monitor physical width in millimetres
|
RLAPI int GetMonitorPhysicalWidth(int monitor); // Get specified monitor physical width in millimetres
|
||||||
RLAPI int GetMonitorPhysicalHeight(int monitor); // Get specified monitor physical height in millimetres
|
RLAPI int GetMonitorPhysicalHeight(int monitor); // Get specified monitor physical height in millimetres
|
||||||
RLAPI int GetMonitorRefreshRate(int monitor); // Get specified monitor refresh rate
|
RLAPI int GetMonitorRefreshRate(int monitor); // Get specified monitor refresh rate
|
||||||
|
@ -941,6 +962,8 @@ RLAPI Vector2 GetWindowScaleDPI(void); // Get window
|
||||||
RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the primary monitor
|
RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the primary monitor
|
||||||
RLAPI void SetClipboardText(const char *text); // Set clipboard text content
|
RLAPI void SetClipboardText(const char *text); // Set clipboard text content
|
||||||
RLAPI const char *GetClipboardText(void); // Get clipboard text content
|
RLAPI const char *GetClipboardText(void); // Get clipboard text content
|
||||||
|
RLAPI void EnableEventWaiting(void); // Enable waiting for events on EndDrawing(), no automatic event polling
|
||||||
|
RLAPI void DisableEventWaiting(void); // Disable waiting for events on EndDrawing(), automatic events polling
|
||||||
|
|
||||||
// Custom frame control functions
|
// Custom frame control functions
|
||||||
// NOTE: Those functions are intended for advance users that want full control over the frame processing
|
// NOTE: Those functions are intended for advance users that want full control over the frame processing
|
||||||
|
@ -948,7 +971,7 @@ RLAPI const char *GetClipboardText(void); // Get clipboa
|
||||||
// To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL
|
// To avoid that behaviour and control frame processes manually, enable in config.h: SUPPORT_CUSTOM_FRAME_CONTROL
|
||||||
RLAPI void SwapScreenBuffer(void); // Swap back buffer with front buffer (screen drawing)
|
RLAPI void SwapScreenBuffer(void); // Swap back buffer with front buffer (screen drawing)
|
||||||
RLAPI void PollInputEvents(void); // Register all input events
|
RLAPI void PollInputEvents(void); // Register all input events
|
||||||
RLAPI void WaitTime(float ms); // Wait for some milliseconds (halt program execution)
|
RLAPI void WaitTime(double seconds); // Wait for some time (halt program execution)
|
||||||
|
|
||||||
// Cursor-related functions
|
// Cursor-related functions
|
||||||
RLAPI void ShowCursor(void); // Shows cursor
|
RLAPI void ShowCursor(void); // Shows cursor
|
||||||
|
@ -998,9 +1021,9 @@ RLAPI Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Get a ray t
|
||||||
RLAPI Matrix GetCameraMatrix(Camera camera); // Get camera transform matrix (view matrix)
|
RLAPI Matrix GetCameraMatrix(Camera camera); // Get camera transform matrix (view matrix)
|
||||||
RLAPI Matrix GetCameraMatrix2D(Camera2D camera); // Get camera 2d transform matrix
|
RLAPI Matrix GetCameraMatrix2D(Camera2D camera); // Get camera 2d transform matrix
|
||||||
RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Get the screen space position for a 3d world space position
|
RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Get the screen space position for a 3d world space position
|
||||||
|
RLAPI Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera); // Get the world space position for a 2d camera screen space position
|
||||||
RLAPI Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height); // Get size position for a 3d world space position
|
RLAPI Vector2 GetWorldToScreenEx(Vector3 position, Camera camera, int width, int height); // Get size position for a 3d world space position
|
||||||
RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); // Get the screen space position for a 2d camera world space position
|
RLAPI Vector2 GetWorldToScreen2D(Vector2 position, Camera2D camera); // Get the screen space position for a 2d camera world space position
|
||||||
RLAPI Vector2 GetScreenToWorld2D(Vector2 position, Camera2D camera); // Get the world space position for a 2d camera screen space position
|
|
||||||
|
|
||||||
// Timing-related functions
|
// Timing-related functions
|
||||||
RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum)
|
RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum)
|
||||||
|
@ -1020,6 +1043,8 @@ RLAPI void *MemAlloc(int size); // Internal me
|
||||||
RLAPI void *MemRealloc(void *ptr, int size); // Internal memory reallocator
|
RLAPI void *MemRealloc(void *ptr, int size); // Internal memory reallocator
|
||||||
RLAPI void MemFree(void *ptr); // Internal memory free
|
RLAPI void MemFree(void *ptr); // Internal memory free
|
||||||
|
|
||||||
|
RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available)
|
||||||
|
|
||||||
// Set custom callbacks
|
// Set custom callbacks
|
||||||
// WARNING: Callbacks setup is intended for advance users
|
// WARNING: Callbacks setup is intended for advance users
|
||||||
RLAPI void SetTraceLogCallback(TraceLogCallback callback); // Set custom trace log
|
RLAPI void SetTraceLogCallback(TraceLogCallback callback); // Set custom trace log
|
||||||
|
@ -1032,37 +1057,36 @@ RLAPI void SetSaveFileTextCallback(SaveFileTextCallback callback); // Set custom
|
||||||
RLAPI unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead); // Load file data as byte array (read)
|
RLAPI unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead); // Load file data as byte array (read)
|
||||||
RLAPI void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData()
|
RLAPI void UnloadFileData(unsigned char *data); // Unload file data allocated by LoadFileData()
|
||||||
RLAPI bool SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite); // Save data to file from byte array (write), returns true on success
|
RLAPI bool SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite); // Save data to file from byte array (write), returns true on success
|
||||||
|
RLAPI bool ExportDataAsCode(const char *data, unsigned int size, const char *fileName); // Export data to code (.h), returns true on success
|
||||||
RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string
|
RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string
|
||||||
RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText()
|
RLAPI void UnloadFileText(char *text); // Unload file text data allocated by LoadFileText()
|
||||||
RLAPI bool SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success
|
RLAPI bool SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated, returns true on success
|
||||||
RLAPI bool FileExists(const char *fileName); // Check if file exists
|
RLAPI bool FileExists(const char *fileName); // Check if file exists
|
||||||
RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists
|
RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists
|
||||||
RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension (including point: .png, .wav)
|
RLAPI bool IsFileExtension(const char *fileName, const char *ext); // Check file extension (including point: .png, .wav)
|
||||||
|
RLAPI int GetFileLength(const char *fileName); // Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h)
|
||||||
RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: '.png')
|
RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: '.png')
|
||||||
RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string
|
RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string
|
||||||
RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string)
|
RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string)
|
||||||
RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string)
|
RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string)
|
||||||
RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string)
|
RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string)
|
||||||
RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string)
|
RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string)
|
||||||
RLAPI char **GetDirectoryFiles(const char *dirPath, int *count); // Get filenames in a directory path (memory should be freed)
|
RLAPI const char *GetApplicationDirectory(void); // Get the directory if the running application (uses static string)
|
||||||
RLAPI void ClearDirectoryFiles(void); // Clear directory files paths buffers (free memory)
|
|
||||||
RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success
|
RLAPI bool ChangeDirectory(const char *dir); // Change working directory, return true on success
|
||||||
|
RLAPI bool IsPathFile(const char *path); // Check if a given path is a file or a directory
|
||||||
|
RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths
|
||||||
|
RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and recursive directory scan
|
||||||
|
RLAPI void UnloadDirectoryFiles(FilePathList files); // Unload filepaths
|
||||||
RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window
|
RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window
|
||||||
RLAPI char **GetDroppedFiles(int *count); // Get dropped files names (memory should be freed)
|
RLAPI FilePathList LoadDroppedFiles(void); // Load dropped filepaths
|
||||||
RLAPI void ClearDroppedFiles(void); // Clear dropped files paths buffer (free memory)
|
RLAPI void UnloadDroppedFiles(FilePathList files); // Unload dropped filepaths
|
||||||
RLAPI long GetFileModTime(const char *fileName); // Get file modification time (last write time)
|
RLAPI long GetFileModTime(const char *fileName); // Get file modification time (last write time)
|
||||||
|
|
||||||
// Compression/Encoding functionality
|
// Compression/Encoding functionality
|
||||||
RLAPI unsigned char *CompressData(unsigned char *data, int dataLength, int *compDataLength); // Compress data (DEFLATE algorithm)
|
RLAPI unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDataSize); // Compress data (DEFLATE algorithm), memory must be MemFree()
|
||||||
RLAPI unsigned char *DecompressData(unsigned char *compData, int compDataLength, int *dataLength); // Decompress data (DEFLATE algorithm)
|
RLAPI unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // Decompress data (DEFLATE algorithm), memory must be MemFree()
|
||||||
RLAPI char *EncodeDataBase64(const unsigned char *data, int dataLength, int *outputLength); // Encode data to Base64 string
|
RLAPI char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize); // Encode data to Base64 string, memory must be MemFree()
|
||||||
RLAPI unsigned char *DecodeDataBase64(unsigned char *data, int *outputLength); // Decode Base64 string data
|
RLAPI unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize); // Decode Base64 string data, memory must be MemFree()
|
||||||
|
|
||||||
// Persistent storage management
|
|
||||||
RLAPI bool SaveStorageValue(unsigned int position, int value); // Save integer value to storage file (to defined position), returns true on success
|
|
||||||
RLAPI int LoadStorageValue(unsigned int position); // Load integer value from storage file (from defined position)
|
|
||||||
|
|
||||||
RLAPI void OpenURL(const char *url); // Open URL with default system browser (if available)
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Input Handling Functions (Module: core)
|
// Input Handling Functions (Module: core)
|
||||||
|
@ -1101,7 +1125,8 @@ RLAPI Vector2 GetMouseDelta(void); // Get mouse delta
|
||||||
RLAPI void SetMousePosition(int x, int y); // Set mouse position XY
|
RLAPI void SetMousePosition(int x, int y); // Set mouse position XY
|
||||||
RLAPI void SetMouseOffset(int offsetX, int offsetY); // Set mouse offset
|
RLAPI void SetMouseOffset(int offsetX, int offsetY); // Set mouse offset
|
||||||
RLAPI void SetMouseScale(float scaleX, float scaleY); // Set mouse scaling
|
RLAPI void SetMouseScale(float scaleX, float scaleY); // Set mouse scaling
|
||||||
RLAPI float GetMouseWheelMove(void); // Get mouse wheel movement Y
|
RLAPI float GetMouseWheelMove(void); // Get mouse wheel movement for X or Y, whichever is larger
|
||||||
|
RLAPI Vector2 GetMouseWheelMoveV(void); // Get mouse wheel movement for both X and Y
|
||||||
RLAPI void SetMouseCursor(int cursor); // Set mouse cursor
|
RLAPI void SetMouseCursor(int cursor); // Set mouse cursor
|
||||||
|
|
||||||
// Input-related functions: touch
|
// Input-related functions: touch
|
||||||
|
@ -1316,13 +1341,14 @@ RLAPI int GetPixelDataSize(int width, int height, int format); // G
|
||||||
// Font loading/unloading functions
|
// Font loading/unloading functions
|
||||||
RLAPI Font GetFontDefault(void); // Get the default Font
|
RLAPI Font GetFontDefault(void); // Get the default Font
|
||||||
RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM)
|
RLAPI Font LoadFont(const char *fileName); // Load font from file into GPU memory (VRAM)
|
||||||
RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int glyphCount); // Load font from file with extended parameters
|
RLAPI Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int glyphCount); // Load font from file with extended parameters, use NULL for fontChars and 0 for glyphCount to load the default character set
|
||||||
RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style)
|
RLAPI Font LoadFontFromImage(Image image, Color key, int firstChar); // Load font from Image (XNA style)
|
||||||
RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf'
|
RLAPI Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount); // Load font from memory buffer, fileType refers to extension: i.e. '.ttf'
|
||||||
RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount, int type); // Load font data for further use
|
RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount, int type); // Load font data for further use
|
||||||
RLAPI Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **recs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info
|
RLAPI Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **recs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info
|
||||||
RLAPI void UnloadFontData(GlyphInfo *chars, int glyphCount); // Unload font chars info data (RAM)
|
RLAPI void UnloadFontData(GlyphInfo *chars, int glyphCount); // Unload font chars info data (RAM)
|
||||||
RLAPI void UnloadFont(Font font); // Unload Font from GPU memory (VRAM)
|
RLAPI void UnloadFont(Font font); // Unload font from GPU memory (VRAM)
|
||||||
|
RLAPI bool ExportFontAsCode(Font font, const char *fileName); // Export font as code file, returns true on success
|
||||||
|
|
||||||
// Text drawing functions
|
// Text drawing functions
|
||||||
RLAPI void DrawFPS(int posX, int posY); // Draw current FPS
|
RLAPI void DrawFPS(int posX, int posY); // Draw current FPS
|
||||||
|
@ -1330,6 +1356,7 @@ RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color co
|
||||||
RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters
|
RLAPI void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text using font and additional parameters
|
||||||
RLAPI void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint); // Draw text using Font and pro parameters (rotation)
|
RLAPI void DrawTextPro(Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint); // Draw text using Font and pro parameters (rotation)
|
||||||
RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint)
|
RLAPI void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSize, Color tint); // Draw one character (codepoint)
|
||||||
|
RLAPI void DrawTextCodepoints(Font font, const int *codepoints, int count, Vector2 position, float fontSize, float spacing, Color tint); // Draw multiple character (codepoint)
|
||||||
|
|
||||||
// Text font info functions
|
// Text font info functions
|
||||||
RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font
|
RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font
|
||||||
|
@ -1344,7 +1371,7 @@ RLAPI void UnloadCodepoints(int *codepoints); // Unload
|
||||||
RLAPI int GetCodepointCount(const char *text); // Get total number of codepoints in a UTF-8 encoded string
|
RLAPI int GetCodepointCount(const char *text); // Get total number of codepoints in a UTF-8 encoded string
|
||||||
RLAPI int GetCodepoint(const char *text, int *bytesProcessed); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
|
RLAPI int GetCodepoint(const char *text, int *bytesProcessed); // Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure
|
||||||
RLAPI const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode one codepoint into UTF-8 byte array (array length returned as parameter)
|
RLAPI const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode one codepoint into UTF-8 byte array (array length returned as parameter)
|
||||||
RLAPI char *TextCodepointsToUTF8(int *codepoints, int length); // Encode text as codepoints array into UTF-8 text string (WARNING: memory must be freed!)
|
RLAPI char *TextCodepointsToUTF8(const int *codepoints, int length); // Encode text as codepoints array into UTF-8 text string (WARNING: memory must be freed!)
|
||||||
|
|
||||||
// Text strings management functions (no UTF-8 strings, only byte chars)
|
// Text strings management functions (no UTF-8 strings, only byte chars)
|
||||||
// NOTE: Some strings allocate memory internally for returned strings, just be careful!
|
// NOTE: Some strings allocate memory internally for returned strings, just be careful!
|
||||||
|
@ -1414,14 +1441,13 @@ RLAPI void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source,
|
||||||
|
|
||||||
// Mesh management functions
|
// Mesh management functions
|
||||||
RLAPI void UploadMesh(Mesh *mesh, bool dynamic); // Upload mesh vertex data in GPU and provide VAO/VBO ids
|
RLAPI void UploadMesh(Mesh *mesh, bool dynamic); // Upload mesh vertex data in GPU and provide VAO/VBO ids
|
||||||
RLAPI void UpdateMeshBuffer(Mesh mesh, int index, void *data, int dataSize, int offset); // Update mesh vertex data in GPU for a specific buffer index
|
RLAPI void UpdateMeshBuffer(Mesh mesh, int index, const void *data, int dataSize, int offset); // Update mesh vertex data in GPU for a specific buffer index
|
||||||
RLAPI void UnloadMesh(Mesh mesh); // Unload mesh data from CPU and GPU
|
RLAPI void UnloadMesh(Mesh mesh); // Unload mesh data from CPU and GPU
|
||||||
RLAPI void DrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform
|
RLAPI void DrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform
|
||||||
RLAPI void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int instances); // Draw multiple mesh instances with material and different transforms
|
RLAPI void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, int instances); // Draw multiple mesh instances with material and different transforms
|
||||||
RLAPI bool ExportMesh(Mesh mesh, const char *fileName); // Export mesh data to file, returns true on success
|
RLAPI bool ExportMesh(Mesh mesh, const char *fileName); // Export mesh data to file, returns true on success
|
||||||
RLAPI BoundingBox GetMeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits
|
RLAPI BoundingBox GetMeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits
|
||||||
RLAPI void GenMeshTangents(Mesh *mesh); // Compute mesh tangents
|
RLAPI void GenMeshTangents(Mesh *mesh); // Compute mesh tangents
|
||||||
RLAPI void GenMeshBinormals(Mesh *mesh); // Compute mesh binormals
|
|
||||||
|
|
||||||
// Mesh generation functions
|
// Mesh generation functions
|
||||||
RLAPI Mesh GenMeshPoly(int sides, float radius); // Generate polygonal mesh
|
RLAPI Mesh GenMeshPoly(int sides, float radius); // Generate polygonal mesh
|
||||||
|
@ -1447,7 +1473,7 @@ RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId);
|
||||||
RLAPI ModelAnimation *LoadModelAnimations(const char *fileName, unsigned int *animCount); // Load model animations from file
|
RLAPI ModelAnimation *LoadModelAnimations(const char *fileName, unsigned int *animCount); // Load model animations from file
|
||||||
RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); // Update model animation pose
|
RLAPI void UpdateModelAnimation(Model model, ModelAnimation anim, int frame); // Update model animation pose
|
||||||
RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data
|
RLAPI void UnloadModelAnimation(ModelAnimation anim); // Unload animation data
|
||||||
RLAPI void UnloadModelAnimations(ModelAnimation* animations, unsigned int count); // Unload animation array data
|
RLAPI void UnloadModelAnimations(ModelAnimation *animations, unsigned int count); // Unload animation array data
|
||||||
RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match
|
RLAPI bool IsModelAnimationValid(Model model, ModelAnimation anim); // Check model animation skeleton match
|
||||||
|
|
||||||
// Collision detection functions
|
// Collision detection functions
|
||||||
|
@ -1456,7 +1482,6 @@ RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2);
|
||||||
RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius); // Check collision between box and sphere
|
RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 center, float radius); // Check collision between box and sphere
|
||||||
RLAPI RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius); // Get collision info between ray and sphere
|
RLAPI RayCollision GetRayCollisionSphere(Ray ray, Vector3 center, float radius); // Get collision info between ray and sphere
|
||||||
RLAPI RayCollision GetRayCollisionBox(Ray ray, BoundingBox box); // Get collision info between ray and box
|
RLAPI RayCollision GetRayCollisionBox(Ray ray, BoundingBox box); // Get collision info between ray and box
|
||||||
RLAPI RayCollision GetRayCollisionModel(Ray ray, Model model); // Get collision info between ray and model
|
|
||||||
RLAPI RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform); // Get collision info between ray and mesh
|
RLAPI RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform); // Get collision info between ray and mesh
|
||||||
RLAPI RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle
|
RLAPI RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle
|
||||||
RLAPI RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4); // Get collision info between ray and quad
|
RLAPI RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4); // Get collision info between ray and quad
|
||||||
|
@ -1464,6 +1489,7 @@ RLAPI RayCollision GetRayCollisionQuad(Ray ray, Vector3 p1, Vector3 p2, Vector3
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Audio Loading and Playing Functions (Module: audio)
|
// Audio Loading and Playing Functions (Module: audio)
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
|
typedef void (*AudioCallback)(void *bufferData, unsigned int frames);
|
||||||
|
|
||||||
// Audio device management functions
|
// Audio device management functions
|
||||||
RLAPI void InitAudioDevice(void); // Initialize audio device and context
|
RLAPI void InitAudioDevice(void); // Initialize audio device and context
|
||||||
|
@ -1493,15 +1519,16 @@ RLAPI int GetSoundsPlaying(void); // Get num
|
||||||
RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing
|
RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing
|
||||||
RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level)
|
RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level)
|
||||||
RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level)
|
RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level)
|
||||||
RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format
|
RLAPI void SetSoundPan(Sound sound, float pan); // Set pan for a sound (0.5 is center)
|
||||||
RLAPI Wave WaveCopy(Wave wave); // Copy a wave to a new wave
|
RLAPI Wave WaveCopy(Wave wave); // Copy a wave to a new wave
|
||||||
RLAPI void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range
|
RLAPI void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range
|
||||||
RLAPI float *LoadWaveSamples(Wave wave); // Load samples data from wave as a floats array
|
RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format
|
||||||
|
RLAPI float *LoadWaveSamples(Wave wave); // Load samples data from wave as a 32bit float data array
|
||||||
RLAPI void UnloadWaveSamples(float *samples); // Unload samples data loaded with LoadWaveSamples()
|
RLAPI void UnloadWaveSamples(float *samples); // Unload samples data loaded with LoadWaveSamples()
|
||||||
|
|
||||||
// Music management functions
|
// Music management functions
|
||||||
RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file
|
RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file
|
||||||
RLAPI Music LoadMusicStreamFromMemory(const char *fileType, unsigned char *data, int dataSize); // Load music stream from data
|
RLAPI Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, int dataSize); // Load music stream from data
|
||||||
RLAPI void UnloadMusicStream(Music music); // Unload music stream
|
RLAPI void UnloadMusicStream(Music music); // Unload music stream
|
||||||
RLAPI void PlayMusicStream(Music music); // Start music playing
|
RLAPI void PlayMusicStream(Music music); // Start music playing
|
||||||
RLAPI bool IsMusicStreamPlaying(Music music); // Check if music is playing
|
RLAPI bool IsMusicStreamPlaying(Music music); // Check if music is playing
|
||||||
|
@ -1512,6 +1539,7 @@ RLAPI void ResumeMusicStream(Music music); // Resume
|
||||||
RLAPI void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds)
|
RLAPI void SeekMusicStream(Music music, float position); // Seek music to a position (in seconds)
|
||||||
RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
|
RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
|
||||||
RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
|
RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
|
||||||
|
RLAPI void SetMusicPan(Music music, float pan); // Set pan for a music (0.5 is center)
|
||||||
RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds)
|
RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds)
|
||||||
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
|
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
|
||||||
|
|
||||||
|
@ -1527,7 +1555,12 @@ RLAPI bool IsAudioStreamPlaying(AudioStream stream); // Check i
|
||||||
RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream
|
RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream
|
||||||
RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
|
RLAPI void SetAudioStreamVolume(AudioStream stream, float volume); // Set volume for audio stream (1.0 is max level)
|
||||||
RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
|
RLAPI void SetAudioStreamPitch(AudioStream stream, float pitch); // Set pitch for audio stream (1.0 is base level)
|
||||||
|
RLAPI void SetAudioStreamPan(AudioStream stream, float pan); // Set pan for audio stream (0.5 is centered)
|
||||||
RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams
|
RLAPI void SetAudioStreamBufferSizeDefault(int size); // Default size for new audio streams
|
||||||
|
RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback); // Audio thread callback to request new data
|
||||||
|
|
||||||
|
RLAPI void AttachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Attach audio stream processor to stream
|
||||||
|
RLAPI void DetachAudioStreamProcessor(AudioStream stream, AudioCallback processor); // Detach audio stream processor from stream
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
|
|
532
raylib/raymath.h
532
raylib/raymath.h
|
@ -18,14 +18,14 @@
|
||||||
* - Functions are always self-contained, no function use another raymath function inside,
|
* - Functions are always self-contained, no function use another raymath function inside,
|
||||||
* required code is directly re-implemented inside
|
* required code is directly re-implemented inside
|
||||||
* - Functions input parameters are always received by value (2 unavoidable exceptions)
|
* - Functions input parameters are always received by value (2 unavoidable exceptions)
|
||||||
* - Functions use always a "result" anmed variable for return
|
* - Functions use always a "result" variable for return
|
||||||
* - Functions are always defined inline
|
* - Functions are always defined inline
|
||||||
* - Angles are always in radians (DEG2RAD/RAD2DEG macros provided for convenience)
|
* - Angles are always in radians (DEG2RAD/RAD2DEG macros provided for convenience)
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* LICENSE: zlib/libpng
|
* LICENSE: zlib/libpng
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2021 Ramon Santamaria (@raysan5)
|
* Copyright (c) 2015-2022 Ramon Santamaria (@raysan5)
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
* 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.
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -77,6 +77,10 @@
|
||||||
#define PI 3.14159265358979323846f
|
#define PI 3.14159265358979323846f
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef EPSILON
|
||||||
|
#define EPSILON 0.000001f
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef DEG2RAD
|
#ifndef DEG2RAD
|
||||||
#define DEG2RAD (PI/180.0f)
|
#define DEG2RAD (PI/180.0f)
|
||||||
#endif
|
#endif
|
||||||
|
@ -154,7 +158,7 @@ typedef struct float16 {
|
||||||
float v[16];
|
float v[16];
|
||||||
} float16;
|
} float16;
|
||||||
|
|
||||||
#include <math.h> // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), fminf(), fmaxf(), fabs()
|
#include <math.h> // Required for: sinf(), cosf(), tan(), atan2f(), sqrtf(), floor(), fminf(), fmaxf(), fabs()
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module Functions Definition - Utils math
|
// Module Functions Definition - Utils math
|
||||||
|
@ -189,7 +193,23 @@ RMAPI float Normalize(float value, float start, float end)
|
||||||
// Remap input value within input range to output range
|
// Remap input value within input range to output range
|
||||||
RMAPI float Remap(float value, float inputStart, float inputEnd, float outputStart, float outputEnd)
|
RMAPI float Remap(float value, float inputStart, float inputEnd, float outputStart, float outputEnd)
|
||||||
{
|
{
|
||||||
float result =(value - inputStart)/(inputEnd - inputStart)*(outputEnd - outputStart) + outputStart;
|
float result = (value - inputStart)/(inputEnd - inputStart)*(outputEnd - outputStart) + outputStart;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap input value from min to max
|
||||||
|
RMAPI float Wrap(float value, float min, float max)
|
||||||
|
{
|
||||||
|
float result = value - (max - min)*floorf((value - min)/(max - min));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether two given floats are almost equal
|
||||||
|
RMAPI int FloatEquals(float x, float y)
|
||||||
|
{
|
||||||
|
int result = (fabsf(x - y)) <= (EPSILON*fmaxf(1.0f, fmaxf(fabsf(x), fabsf(y))));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -278,12 +298,18 @@ RMAPI float Vector2Distance(Vector2 v1, Vector2 v2)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate angle from two vectors in X-axis
|
// Calculate square distance between two vectors
|
||||||
|
RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2)
|
||||||
|
{
|
||||||
|
float result = ((v1.x - v2.x)*(v1.x - v2.x) + (v1.y - v2.y)*(v1.y - v2.y));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate angle from two vectors
|
||||||
RMAPI float Vector2Angle(Vector2 v1, Vector2 v2)
|
RMAPI float Vector2Angle(Vector2 v1, Vector2 v2)
|
||||||
{
|
{
|
||||||
float result = atan2f(v2.y - v1.y, v2.x - v1.x)*(180.0f/PI);
|
float result = atan2f(v2.y, v2.x) - atan2f(v1.y, v1.x);
|
||||||
|
|
||||||
if (result < 0) result += 360.0f;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -328,13 +354,29 @@ RMAPI Vector2 Vector2Normalize(Vector2 v)
|
||||||
|
|
||||||
if (length > 0)
|
if (length > 0)
|
||||||
{
|
{
|
||||||
result.x = v.x*1.0f/length;
|
float ilength = 1.0f/length;
|
||||||
result.y = v.y*1.0f/length;
|
result.x = v.x*ilength;
|
||||||
|
result.y = v.y*ilength;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transforms a Vector2 by a given Matrix
|
||||||
|
RMAPI Vector2 Vector2Transform(Vector2 v, Matrix mat)
|
||||||
|
{
|
||||||
|
Vector2 result = { 0 };
|
||||||
|
|
||||||
|
float x = v.x;
|
||||||
|
float y = v.y;
|
||||||
|
float z = 0;
|
||||||
|
|
||||||
|
result.x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12;
|
||||||
|
result.y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate linear interpolation between two vectors
|
// Calculate linear interpolation between two vectors
|
||||||
RMAPI Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount)
|
RMAPI Vector2 Vector2Lerp(Vector2 v1, Vector2 v2, float amount)
|
||||||
{
|
{
|
||||||
|
@ -364,8 +406,11 @@ RMAPI Vector2 Vector2Rotate(Vector2 v, float angle)
|
||||||
{
|
{
|
||||||
Vector2 result = { 0 };
|
Vector2 result = { 0 };
|
||||||
|
|
||||||
result.x = v.x*cosf(angle) - v.y*sinf(angle);
|
float cosres = cosf(angle);
|
||||||
result.y = v.x*sinf(angle) + v.y*cosf(angle);
|
float sinres = sinf(angle);
|
||||||
|
|
||||||
|
result.x = v.x*cosres - v.y*sinres;
|
||||||
|
result.y = v.x*sinres + v.y*cosres;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -389,6 +434,62 @@ RMAPI Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invert the given vector
|
||||||
|
RMAPI Vector2 Vector2Invert(Vector2 v)
|
||||||
|
{
|
||||||
|
Vector2 result = { 1.0f/v.x, 1.0f/v.y };
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp the components of the vector between
|
||||||
|
// min and max values specified by the given vectors
|
||||||
|
RMAPI Vector2 Vector2Clamp(Vector2 v, Vector2 min, Vector2 max)
|
||||||
|
{
|
||||||
|
Vector2 result = { 0 };
|
||||||
|
|
||||||
|
result.x = fminf(max.x, fmaxf(min.x, v.x));
|
||||||
|
result.y = fminf(max.y, fmaxf(min.y, v.y));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp the magnitude of the vector between two min and max values
|
||||||
|
RMAPI Vector2 Vector2ClampValue(Vector2 v, float min, float max)
|
||||||
|
{
|
||||||
|
Vector2 result = v;
|
||||||
|
|
||||||
|
float length = (v.x*v.x) + (v.y*v.y);
|
||||||
|
if (length > 0.0f)
|
||||||
|
{
|
||||||
|
length = sqrtf(length);
|
||||||
|
|
||||||
|
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 Vector2Equals(Vector2 p, Vector2 q)
|
||||||
|
{
|
||||||
|
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
|
// Module Functions Definition - Vector3 math
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -473,14 +574,14 @@ RMAPI Vector3 Vector3Perpendicular(Vector3 v)
|
||||||
float min = (float) fabs(v.x);
|
float min = (float) fabs(v.x);
|
||||||
Vector3 cardinalAxis = {1.0f, 0.0f, 0.0f};
|
Vector3 cardinalAxis = {1.0f, 0.0f, 0.0f};
|
||||||
|
|
||||||
if (fabs(v.y) < min)
|
if (fabsf(v.y) < min)
|
||||||
{
|
{
|
||||||
min = (float) fabs(v.y);
|
min = (float) fabs(v.y);
|
||||||
Vector3 tmp = {0.0f, 1.0f, 0.0f};
|
Vector3 tmp = {0.0f, 1.0f, 0.0f};
|
||||||
cardinalAxis = tmp;
|
cardinalAxis = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fabs(v.z) < min)
|
if (fabsf(v.z) < min)
|
||||||
{
|
{
|
||||||
Vector3 tmp = {0.0f, 0.0f, 1.0f};
|
Vector3 tmp = {0.0f, 0.0f, 1.0f};
|
||||||
cardinalAxis = tmp;
|
cardinalAxis = tmp;
|
||||||
|
@ -531,17 +632,28 @@ RMAPI float Vector3Distance(Vector3 v1, Vector3 v2)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate angle between two vectors in XY and XZ
|
// Calculate square distance between two vectors
|
||||||
RMAPI Vector2 Vector3Angle(Vector3 v1, Vector3 v2)
|
RMAPI float Vector3DistanceSqr(Vector3 v1, Vector3 v2)
|
||||||
{
|
{
|
||||||
Vector2 result = { 0 };
|
float result = 0.0f;
|
||||||
|
|
||||||
float dx = v2.x - v1.x;
|
float dx = v2.x - v1.x;
|
||||||
float dy = v2.y - v1.y;
|
float dy = v2.y - v1.y;
|
||||||
float dz = v2.z - v1.z;
|
float dz = v2.z - v1.z;
|
||||||
|
result = dx*dx + dy*dy + dz*dz;
|
||||||
|
|
||||||
result.x = atan2f(dx, dz); // Angle in XZ
|
return result;
|
||||||
result.y = atan2f(dy, sqrtf(dx*dx + dz*dz)); // Angle in XY
|
}
|
||||||
|
|
||||||
|
// Calculate angle between two vectors
|
||||||
|
RMAPI float Vector3Angle(Vector3 v1, Vector3 v2)
|
||||||
|
{
|
||||||
|
float result = 0.0f;
|
||||||
|
|
||||||
|
Vector3 cross = { v1.y*v2.z - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x };
|
||||||
|
float len = sqrtf(cross.x*cross.x + cross.y*cross.y + cross.z*cross.z);
|
||||||
|
float dot = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);
|
||||||
|
result = atan2f(len, dot);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -641,6 +753,58 @@ RMAPI Vector3 Vector3RotateByQuaternion(Vector3 v, Quaternion q)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rotates a vector around an axis
|
||||||
|
RMAPI Vector3 Vector3RotateByAxisAngle(Vector3 v, Vector3 axis, float angle)
|
||||||
|
{
|
||||||
|
// Using Euler-Rodrigues Formula
|
||||||
|
// Ref.: https://en.wikipedia.org/w/index.php?title=Euler%E2%80%93Rodrigues_formula
|
||||||
|
|
||||||
|
Vector3 result = v;
|
||||||
|
|
||||||
|
// Vector3Normalize(axis);
|
||||||
|
float length = sqrtf(axis.x * axis.x + axis.y * axis.y + axis.z * axis.z);
|
||||||
|
if (length == 0.0f) length = 1.0f;
|
||||||
|
float ilength = 1.0f / length;
|
||||||
|
axis.x *= ilength;
|
||||||
|
axis.y *= ilength;
|
||||||
|
axis.z *= ilength;
|
||||||
|
|
||||||
|
angle /= 2.0f;
|
||||||
|
float a = sinf(angle);
|
||||||
|
float b = axis.x * a;
|
||||||
|
float c = axis.y * a;
|
||||||
|
float d = axis.z * a;
|
||||||
|
a = cosf(angle);
|
||||||
|
Vector3 w = { b, c, d };
|
||||||
|
|
||||||
|
// Vector3CrossProduct(w, v)
|
||||||
|
Vector3 wv = { w.y * v.z - w.z * v.y, w.z * v.x - w.x * v.z, w.x * v.y - w.y * v.x };
|
||||||
|
|
||||||
|
// Vector3CrossProduct(w, wv)
|
||||||
|
Vector3 wwv = { w.y * wv.z - w.z * wv.y, w.z * wv.x - w.x * wv.z, w.x * wv.y - w.y * wv.x };
|
||||||
|
|
||||||
|
// Vector3Scale(wv, 2 * a)
|
||||||
|
a *= 2;
|
||||||
|
wv.x *= a;
|
||||||
|
wv.y *= a;
|
||||||
|
wv.z *= a;
|
||||||
|
|
||||||
|
// Vector3Scale(wwv, 2)
|
||||||
|
wwv.x *= 2;
|
||||||
|
wwv.y *= 2;
|
||||||
|
wwv.z *= 2;
|
||||||
|
|
||||||
|
result.x += wv.x;
|
||||||
|
result.y += wv.y;
|
||||||
|
result.z += wv.z;
|
||||||
|
|
||||||
|
result.x += wwv.x;
|
||||||
|
result.y += wwv.y;
|
||||||
|
result.z += wwv.z;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate linear interpolation between two vectors
|
// Calculate linear interpolation between two vectors
|
||||||
RMAPI Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount)
|
RMAPI Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount)
|
||||||
{
|
{
|
||||||
|
@ -815,6 +979,92 @@ RMAPI float3 Vector3ToFloatV(Vector3 v)
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invert the given vector
|
||||||
|
RMAPI Vector3 Vector3Invert(Vector3 v)
|
||||||
|
{
|
||||||
|
Vector3 result = { 1.0f/v.x, 1.0f/v.y, 1.0f/v.z };
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp the components of the vector between
|
||||||
|
// min and max values specified by the given vectors
|
||||||
|
RMAPI Vector3 Vector3Clamp(Vector3 v, Vector3 min, Vector3 max)
|
||||||
|
{
|
||||||
|
Vector3 result = { 0 };
|
||||||
|
|
||||||
|
result.x = fminf(max.x, fmaxf(min.x, v.x));
|
||||||
|
result.y = fminf(max.y, fmaxf(min.y, v.y));
|
||||||
|
result.z = fminf(max.z, fmaxf(min.z, v.z));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamp the magnitude of the vector between two values
|
||||||
|
RMAPI Vector3 Vector3ClampValue(Vector3 v, float min, float max)
|
||||||
|
{
|
||||||
|
Vector3 result = v;
|
||||||
|
|
||||||
|
float length = (v.x*v.x) + (v.y*v.y) + (v.z*v.z);
|
||||||
|
if (length > 0.0f)
|
||||||
|
{
|
||||||
|
length = sqrtf(length);
|
||||||
|
|
||||||
|
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 Vector3Equals(Vector3 p, Vector3 q)
|
||||||
|
{
|
||||||
|
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 where v specifies the
|
||||||
|
// normalized direction of the incoming ray, n specifies the
|
||||||
|
// normalized normal vector of the interface of two optical media,
|
||||||
|
// and r specifies the ratio of the refractive index of the medium
|
||||||
|
// from where the ray comes to the refractive index of the medium
|
||||||
|
// on the other side of the surface
|
||||||
|
RMAPI Vector3 Vector3Refract(Vector3 v, Vector3 n, float r)
|
||||||
|
{
|
||||||
|
Vector3 result = { 0 };
|
||||||
|
|
||||||
|
float dot = v.x*n.x + v.y*n.y + v.z*n.z;
|
||||||
|
float d = 1.0f - r*r*(1.0f - dot*dot);
|
||||||
|
|
||||||
|
if (d >= 0.0f)
|
||||||
|
{
|
||||||
|
d = sqrtf(d);
|
||||||
|
v.x = r*v.x - (r*dot + d)*n.x;
|
||||||
|
v.y = r*v.y - (r*dot + d)*n.y;
|
||||||
|
v.z = r*v.z - (r*dot + d)*n.z;
|
||||||
|
|
||||||
|
result = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module Functions Definition - Matrix math
|
// Module Functions Definition - Matrix math
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -920,45 +1170,6 @@ RMAPI Matrix MatrixInvert(Matrix mat)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize provided matrix
|
|
||||||
RMAPI Matrix MatrixNormalize(Matrix mat)
|
|
||||||
{
|
|
||||||
Matrix result = { 0 };
|
|
||||||
|
|
||||||
// Cache the matrix values (speed optimization)
|
|
||||||
float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;
|
|
||||||
float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7;
|
|
||||||
float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;
|
|
||||||
float a30 = mat.m12, a31 = mat.m13, a32 = mat.m14, a33 = mat.m15;
|
|
||||||
|
|
||||||
// MatrixDeterminant(mat)
|
|
||||||
float det = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 +
|
|
||||||
a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 +
|
|
||||||
a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 +
|
|
||||||
a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 +
|
|
||||||
a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 +
|
|
||||||
a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33;
|
|
||||||
|
|
||||||
result.m0 = mat.m0/det;
|
|
||||||
result.m1 = mat.m1/det;
|
|
||||||
result.m2 = mat.m2/det;
|
|
||||||
result.m3 = mat.m3/det;
|
|
||||||
result.m4 = mat.m4/det;
|
|
||||||
result.m5 = mat.m5/det;
|
|
||||||
result.m6 = mat.m6/det;
|
|
||||||
result.m7 = mat.m7/det;
|
|
||||||
result.m8 = mat.m8/det;
|
|
||||||
result.m9 = mat.m9/det;
|
|
||||||
result.m10 = mat.m10/det;
|
|
||||||
result.m11 = mat.m11/det;
|
|
||||||
result.m12 = mat.m12/det;
|
|
||||||
result.m13 = mat.m13/det;
|
|
||||||
result.m14 = mat.m14/det;
|
|
||||||
result.m15 = mat.m15/det;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get identity matrix
|
// Get identity matrix
|
||||||
RMAPI Matrix MatrixIdentity(void)
|
RMAPI Matrix MatrixIdentity(void)
|
||||||
{
|
{
|
||||||
|
@ -1102,7 +1313,8 @@ RMAPI Matrix MatrixRotate(Vector3 axis, float angle)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get x-rotation matrix (angle in radians)
|
// Get x-rotation matrix
|
||||||
|
// NOTE: Angle must be provided in radians
|
||||||
RMAPI Matrix MatrixRotateX(float angle)
|
RMAPI Matrix MatrixRotateX(float angle)
|
||||||
{
|
{
|
||||||
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
|
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
@ -1114,14 +1326,15 @@ RMAPI Matrix MatrixRotateX(float angle)
|
||||||
float sinres = sinf(angle);
|
float sinres = sinf(angle);
|
||||||
|
|
||||||
result.m5 = cosres;
|
result.m5 = cosres;
|
||||||
result.m6 = -sinres;
|
result.m6 = sinres;
|
||||||
result.m9 = sinres;
|
result.m9 = -sinres;
|
||||||
result.m10 = cosres;
|
result.m10 = cosres;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get y-rotation matrix (angle in radians)
|
// Get y-rotation matrix
|
||||||
|
// NOTE: Angle must be provided in radians
|
||||||
RMAPI Matrix MatrixRotateY(float angle)
|
RMAPI Matrix MatrixRotateY(float angle)
|
||||||
{
|
{
|
||||||
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
|
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
@ -1133,14 +1346,15 @@ RMAPI Matrix MatrixRotateY(float angle)
|
||||||
float sinres = sinf(angle);
|
float sinres = sinf(angle);
|
||||||
|
|
||||||
result.m0 = cosres;
|
result.m0 = cosres;
|
||||||
result.m2 = sinres;
|
result.m2 = -sinres;
|
||||||
result.m8 = -sinres;
|
result.m8 = sinres;
|
||||||
result.m10 = cosres;
|
result.m10 = cosres;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get z-rotation matrix (angle in radians)
|
// Get z-rotation matrix
|
||||||
|
// NOTE: Angle must be provided in radians
|
||||||
RMAPI Matrix MatrixRotateZ(float angle)
|
RMAPI Matrix MatrixRotateZ(float angle)
|
||||||
{
|
{
|
||||||
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
|
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
@ -1152,74 +1366,76 @@ RMAPI Matrix MatrixRotateZ(float angle)
|
||||||
float sinres = sinf(angle);
|
float sinres = sinf(angle);
|
||||||
|
|
||||||
result.m0 = cosres;
|
result.m0 = cosres;
|
||||||
result.m1 = -sinres;
|
result.m1 = sinres;
|
||||||
result.m4 = sinres;
|
result.m4 = -sinres;
|
||||||
result.m5 = cosres;
|
result.m5 = cosres;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Get xyz-rotation matrix (angles in radians)
|
// Get xyz-rotation matrix
|
||||||
RMAPI Matrix MatrixRotateXYZ(Vector3 ang)
|
// NOTE: Angle must be provided in radians
|
||||||
|
RMAPI Matrix MatrixRotateXYZ(Vector3 angle)
|
||||||
{
|
{
|
||||||
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
|
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||||
0.0f, 1.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, 1.0f, 0.0f,
|
||||||
0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()
|
0.0f, 0.0f, 0.0f, 1.0f }; // MatrixIdentity()
|
||||||
|
|
||||||
float cosz = cosf(-ang.z);
|
float cosz = cosf(-angle.z);
|
||||||
float sinz = sinf(-ang.z);
|
float sinz = sinf(-angle.z);
|
||||||
float cosy = cosf(-ang.y);
|
float cosy = cosf(-angle.y);
|
||||||
float siny = sinf(-ang.y);
|
float siny = sinf(-angle.y);
|
||||||
float cosx = cosf(-ang.x);
|
float cosx = cosf(-angle.x);
|
||||||
float sinx = sinf(-ang.x);
|
float sinx = sinf(-angle.x);
|
||||||
|
|
||||||
result.m0 = cosz*cosy;
|
result.m0 = cosz*cosy;
|
||||||
result.m4 = (cosz*siny*sinx) - (sinz*cosx);
|
result.m1 = (cosz*siny*sinx) - (sinz*cosx);
|
||||||
result.m8 = (cosz*siny*cosx) + (sinz*sinx);
|
result.m2 = (cosz*siny*cosx) + (sinz*sinx);
|
||||||
|
|
||||||
result.m1 = sinz*cosy;
|
result.m4 = sinz*cosy;
|
||||||
result.m5 = (sinz*siny*sinx) + (cosz*cosx);
|
result.m5 = (sinz*siny*sinx) + (cosz*cosx);
|
||||||
result.m9 = (sinz*siny*cosx) - (cosz*sinx);
|
result.m6 = (sinz*siny*cosx) - (cosz*sinx);
|
||||||
|
|
||||||
result.m2 = -siny;
|
result.m8 = -siny;
|
||||||
result.m6 = cosy*sinx;
|
result.m9 = cosy*sinx;
|
||||||
result.m10= cosy*cosx;
|
result.m10= cosy*cosx;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get zyx-rotation matrix (angles in radians)
|
// Get zyx-rotation matrix
|
||||||
RMAPI Matrix MatrixRotateZYX(Vector3 ang)
|
// NOTE: Angle must be provided in radians
|
||||||
|
RMAPI Matrix MatrixRotateZYX(Vector3 angle)
|
||||||
{
|
{
|
||||||
Matrix result = { 0 };
|
Matrix result = { 0 };
|
||||||
|
|
||||||
float cz = cosf(ang.z);
|
float cz = cosf(angle.z);
|
||||||
float sz = sinf(ang.z);
|
float sz = sinf(angle.z);
|
||||||
float cy = cosf(ang.y);
|
float cy = cosf(angle.y);
|
||||||
float sy = sinf(ang.y);
|
float sy = sinf(angle.y);
|
||||||
float cx = cosf(ang.x);
|
float cx = cosf(angle.x);
|
||||||
float sx = sinf(ang.x);
|
float sx = sinf(angle.x);
|
||||||
|
|
||||||
result.m0 = cz*cy;
|
result.m0 = cz*cy;
|
||||||
result.m1 = cz*sy*sx - cx*sz;
|
result.m4 = cz*sy*sx - cx*sz;
|
||||||
result.m2 = sz*sx + cz*cx*sy;
|
result.m8 = sz*sx + cz*cx*sy;
|
||||||
result.m3 = 0;
|
|
||||||
|
|
||||||
result.m4 = cy*sz;
|
|
||||||
result.m5 = cz*cx + sz*sy*sx;
|
|
||||||
result.m6 = cx*sz*sy - cz*sx;
|
|
||||||
result.m7 = 0;
|
|
||||||
|
|
||||||
result.m8 = -sy;
|
|
||||||
result.m9 = cy*sx;
|
|
||||||
result.m10 = cy*cx;
|
|
||||||
result.m11 = 0;
|
|
||||||
|
|
||||||
result.m12 = 0;
|
result.m12 = 0;
|
||||||
|
|
||||||
|
result.m1 = cy*sz;
|
||||||
|
result.m5 = cz*cx + sz*sy*sx;
|
||||||
|
result.m9 = cx*sz*sy - cz*sx;
|
||||||
result.m13 = 0;
|
result.m13 = 0;
|
||||||
|
|
||||||
|
result.m2 = -sy;
|
||||||
|
result.m6 = cy*sx;
|
||||||
|
result.m10 = cy*cx;
|
||||||
result.m14 = 0;
|
result.m14 = 0;
|
||||||
|
|
||||||
|
result.m3 = 0;
|
||||||
|
result.m7 = 0;
|
||||||
|
result.m11 = 0;
|
||||||
result.m15 = 1;
|
result.m15 = 1;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -1269,7 +1485,7 @@ RMAPI Matrix MatrixFrustum(double left, double right, double bottom, double top,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get perspective projection matrix
|
// Get perspective projection matrix
|
||||||
// NOTE: Angle should be provided in radians
|
// NOTE: Fovy angle must be provided in radians
|
||||||
RMAPI Matrix MatrixPerspective(double fovy, double aspect, double near, double far)
|
RMAPI Matrix MatrixPerspective(double fovy, double aspect, double near, double far)
|
||||||
{
|
{
|
||||||
Matrix result = { 0 };
|
Matrix result = { 0 };
|
||||||
|
@ -1478,10 +1694,9 @@ RMAPI Quaternion QuaternionInvert(Quaternion q)
|
||||||
{
|
{
|
||||||
Quaternion result = q;
|
Quaternion result = q;
|
||||||
|
|
||||||
float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
|
float lengthSq = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w;
|
||||||
float lengthSq = length*length;
|
|
||||||
|
|
||||||
if (lengthSq != 0.0)
|
if (lengthSq != 0.0f)
|
||||||
{
|
{
|
||||||
float invLength = 1.0f/lengthSq;
|
float invLength = 1.0f/lengthSq;
|
||||||
|
|
||||||
|
@ -1515,12 +1730,10 @@ RMAPI Quaternion QuaternionScale(Quaternion q, float mul)
|
||||||
{
|
{
|
||||||
Quaternion result = { 0 };
|
Quaternion result = { 0 };
|
||||||
|
|
||||||
float qax = q.x, qay = q.y, qaz = q.z, qaw = q.w;
|
result.x = q.x*mul;
|
||||||
|
result.y = q.y*mul;
|
||||||
result.x = qax*mul + qaw*mul + qay*mul - qaz*mul;
|
result.z = q.z*mul;
|
||||||
result.y = qay*mul + qaw*mul + qaz*mul - qax*mul;
|
result.w = q.w*mul;
|
||||||
result.z = qaz*mul + qaw*mul + qax*mul - qay*mul;
|
|
||||||
result.w = qaw*mul - qax*mul - qay*mul - qaz*mul;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1584,14 +1797,14 @@ RMAPI Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
|
||||||
cosHalfTheta = -cosHalfTheta;
|
cosHalfTheta = -cosHalfTheta;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fabs(cosHalfTheta) >= 1.0f) result = q1;
|
if (fabsf(cosHalfTheta) >= 1.0f) result = q1;
|
||||||
else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount);
|
else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float halfTheta = acosf(cosHalfTheta);
|
float halfTheta = acosf(cosHalfTheta);
|
||||||
float sinHalfTheta = sqrtf(1.0f - cosHalfTheta*cosHalfTheta);
|
float sinHalfTheta = sqrtf(1.0f - cosHalfTheta*cosHalfTheta);
|
||||||
|
|
||||||
if (fabs(sinHalfTheta) < 0.001f)
|
if (fabsf(sinHalfTheta) < 0.001f)
|
||||||
{
|
{
|
||||||
result.x = (q1.x*0.5f + q2.x*0.5f);
|
result.x = (q1.x*0.5f + q2.x*0.5f);
|
||||||
result.y = (q1.y*0.5f + q2.y*0.5f);
|
result.y = (q1.y*0.5f + q2.y*0.5f);
|
||||||
|
@ -1646,30 +1859,60 @@ RMAPI Quaternion QuaternionFromMatrix(Matrix mat)
|
||||||
{
|
{
|
||||||
Quaternion result = { 0 };
|
Quaternion result = { 0 };
|
||||||
|
|
||||||
if ((mat.m0 > mat.m5) && (mat.m0 > mat.m10))
|
float fourWSquaredMinus1 = mat.m0 + mat.m5 + mat.m10;
|
||||||
{
|
float fourXSquaredMinus1 = mat.m0 - mat.m5 - mat.m10;
|
||||||
float s = sqrtf(1.0f + mat.m0 - mat.m5 - mat.m10)*2;
|
float fourYSquaredMinus1 = mat.m5 - mat.m0 - mat.m10;
|
||||||
|
float fourZSquaredMinus1 = mat.m10 - mat.m0 - mat.m5;
|
||||||
|
|
||||||
result.x = 0.25f*s;
|
int biggestIndex = 0;
|
||||||
result.y = (mat.m4 + mat.m1)/s;
|
float fourBiggestSquaredMinus1 = fourWSquaredMinus1;
|
||||||
result.z = (mat.m2 + mat.m8)/s;
|
if (fourXSquaredMinus1 > fourBiggestSquaredMinus1)
|
||||||
result.w = (mat.m9 - mat.m6)/s;
|
|
||||||
}
|
|
||||||
else if (mat.m5 > mat.m10)
|
|
||||||
{
|
{
|
||||||
float s = sqrtf(1.0f + mat.m5 - mat.m0 - mat.m10)*2;
|
fourBiggestSquaredMinus1 = fourXSquaredMinus1;
|
||||||
result.x = (mat.m4 + mat.m1)/s;
|
biggestIndex = 1;
|
||||||
result.y = 0.25f*s;
|
|
||||||
result.z = (mat.m9 + mat.m6)/s;
|
|
||||||
result.w = (mat.m2 - mat.m8)/s;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (fourYSquaredMinus1 > fourBiggestSquaredMinus1)
|
||||||
{
|
{
|
||||||
float s = sqrtf(1.0f + mat.m10 - mat.m0 - mat.m5)*2;
|
fourBiggestSquaredMinus1 = fourYSquaredMinus1;
|
||||||
result.x = (mat.m2 + mat.m8)/s;
|
biggestIndex = 2;
|
||||||
result.y = (mat.m9 + mat.m6)/s;
|
}
|
||||||
result.z = 0.25f*s;
|
|
||||||
result.w = (mat.m4 - mat.m1)/s;
|
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;
|
return result;
|
||||||
|
@ -1709,7 +1952,7 @@ RMAPI Matrix QuaternionToMatrix(Quaternion q)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get rotation quaternion for an angle and axis
|
// Get rotation quaternion for an angle and axis
|
||||||
// NOTE: angle must be provided in radians
|
// NOTE: Angle must be provided in radians
|
||||||
RMAPI Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle)
|
RMAPI Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle)
|
||||||
{
|
{
|
||||||
Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f };
|
Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||||
|
@ -1757,7 +2000,7 @@ RMAPI Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle)
|
||||||
// Get the rotation angle and axis for a given quaternion
|
// Get the rotation angle and axis for a given quaternion
|
||||||
RMAPI void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle)
|
RMAPI void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle)
|
||||||
{
|
{
|
||||||
if (fabs(q.w) > 1.0f)
|
if (fabsf(q.w) > 1.0f)
|
||||||
{
|
{
|
||||||
// QuaternionNormalize(q);
|
// QuaternionNormalize(q);
|
||||||
float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
|
float length = sqrtf(q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w);
|
||||||
|
@ -1850,4 +2093,19 @@ RMAPI Quaternion QuaternionTransform(Quaternion q, Matrix mat)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check whether two given quaternions are almost equal
|
||||||
|
RMAPI int QuaternionEquals(Quaternion p, Quaternion q)
|
||||||
|
{
|
||||||
|
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
|
#endif // RAYMATH_H
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
*
|
*
|
||||||
* LICENSE: zlib/libpng
|
* LICENSE: zlib/libpng
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2021 Ramon Santamaria (@raysan5)
|
* Copyright (c) 2015-2022 Ramon Santamaria (@raysan5)
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
* 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.
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -103,7 +103,7 @@
|
||||||
// Module Functions Declaration
|
// Module Functions Declaration
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#if defined(__cplusplus)
|
||||||
extern "C" { // Prevents name mangling of functions
|
extern "C" { // Prevents name mangling of functions
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ void SetCameraMoveControls(int keyFront, int keyBack,
|
||||||
int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras)
|
int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ void SetCameraMoveControls(int keyFront, int keyBack,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Camera mouse movement sensitivity
|
// Camera mouse movement sensitivity
|
||||||
#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f
|
#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.5f // TODO: it should be independant of framerate
|
||||||
#define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f
|
#define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f
|
||||||
|
|
||||||
// FREE_CAMERA
|
// FREE_CAMERA
|
||||||
|
@ -163,7 +163,7 @@ void SetCameraMoveControls(int keyFront, int keyBack,
|
||||||
#define CAMERA_FREE_PANNING_DIVIDER 5.1f
|
#define CAMERA_FREE_PANNING_DIVIDER 5.1f
|
||||||
|
|
||||||
// ORBITAL_CAMERA
|
// ORBITAL_CAMERA
|
||||||
#define CAMERA_ORBITAL_SPEED 0.01f // Radians per frame
|
#define CAMERA_ORBITAL_SPEED 0.5f // Radians per second
|
||||||
|
|
||||||
// FIRST_PERSON
|
// FIRST_PERSON
|
||||||
//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY 0.003f
|
//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY 0.003f
|
||||||
|
@ -171,9 +171,11 @@ void SetCameraMoveControls(int keyFront, int keyBack,
|
||||||
#define CAMERA_FIRST_PERSON_MIN_CLAMP 89.0f
|
#define CAMERA_FIRST_PERSON_MIN_CLAMP 89.0f
|
||||||
#define CAMERA_FIRST_PERSON_MAX_CLAMP -89.0f
|
#define CAMERA_FIRST_PERSON_MAX_CLAMP -89.0f
|
||||||
|
|
||||||
#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 8.0f
|
// When walking, y-position of the player moves up-down at step frequency (swinging) but
|
||||||
#define CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f
|
// also the body slightly tilts left-right on every step, when all the body weight is left over one foot (tilting)
|
||||||
#define CAMERA_FIRST_PERSON_WAVING_DIVIDER 200.0f
|
#define CAMERA_FIRST_PERSON_STEP_FREQUENCY 1.8f // Step frequency when walking (steps per second)
|
||||||
|
#define CAMERA_FIRST_PERSON_SWINGING_DELTA 0.03f // Maximum up-down swinging distance when walking
|
||||||
|
#define CAMERA_FIRST_PERSON_TILTING_DELTA 0.005f // Maximum left-right tilting distance when walking
|
||||||
|
|
||||||
// THIRD_PERSON
|
// THIRD_PERSON
|
||||||
//#define CAMERA_THIRD_PERSON_MOUSE_SENSITIVITY 0.003f
|
//#define CAMERA_THIRD_PERSON_MOUSE_SENSITIVITY 0.003f
|
||||||
|
@ -183,7 +185,7 @@ void SetCameraMoveControls(int keyFront, int keyBack,
|
||||||
#define CAMERA_THIRD_PERSON_OFFSET (Vector3){ 0.4f, 0.0f, 0.0f }
|
#define CAMERA_THIRD_PERSON_OFFSET (Vector3){ 0.4f, 0.0f, 0.0f }
|
||||||
|
|
||||||
// PLAYER (used by camera)
|
// PLAYER (used by camera)
|
||||||
#define PLAYER_MOVEMENT_SENSITIVITY 20.0f
|
#define PLAYER_MOVEMENT_SENSITIVITY 2.0f
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Types and Structures Definition
|
// Types and Structures Definition
|
||||||
|
@ -204,7 +206,6 @@ typedef struct {
|
||||||
float targetDistance; // Camera distance from position to target
|
float targetDistance; // Camera distance from position to target
|
||||||
float playerEyesPosition; // Player eyes position from ground (in meters)
|
float playerEyesPosition; // Player eyes position from ground (in meters)
|
||||||
Vector2 angle; // Camera angle in plane XZ
|
Vector2 angle; // Camera angle in plane XZ
|
||||||
Vector2 previousMousePosition; // Previous mouse position
|
|
||||||
|
|
||||||
// Camera movement control keys
|
// Camera movement control keys
|
||||||
int moveControl[6]; // Move controls (CAMERA_FIRST_PERSON)
|
int moveControl[6]; // Move controls (CAMERA_FIRST_PERSON)
|
||||||
|
@ -221,7 +222,6 @@ static CameraData CAMERA = { // Global CAMERA state context
|
||||||
.targetDistance = 0,
|
.targetDistance = 0,
|
||||||
.playerEyesPosition = 1.85f,
|
.playerEyesPosition = 1.85f,
|
||||||
.angle = { 0 },
|
.angle = { 0 },
|
||||||
.previousMousePosition = { 0 },
|
|
||||||
.moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' },
|
.moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' },
|
||||||
.smoothZoomControl = 341, // raylib: KEY_LEFT_CONTROL
|
.smoothZoomControl = 341, // raylib: KEY_LEFT_CONTROL
|
||||||
.altControl = 342, // raylib: KEY_LEFT_ALT
|
.altControl = 342, // raylib: KEY_LEFT_ALT
|
||||||
|
@ -265,8 +265,6 @@ void SetCameraMode(Camera camera, int mode)
|
||||||
|
|
||||||
CAMERA.playerEyesPosition = camera.position.y; // Init player eyes position to camera Y position
|
CAMERA.playerEyesPosition = camera.position.y; // Init player eyes position to camera Y position
|
||||||
|
|
||||||
CAMERA.previousMousePosition = GetMousePosition(); // Init mouse position
|
|
||||||
|
|
||||||
// Lock cursor for first person and third person cameras
|
// Lock cursor for first person and third person cameras
|
||||||
if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor();
|
if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor();
|
||||||
else EnableCursor();
|
else EnableCursor();
|
||||||
|
@ -281,13 +279,12 @@ void SetCameraMode(Camera camera, int mode)
|
||||||
// Keys: IsKeyDown()
|
// Keys: IsKeyDown()
|
||||||
void UpdateCamera(Camera *camera)
|
void UpdateCamera(Camera *camera)
|
||||||
{
|
{
|
||||||
static int swingCounter = 0; // Used for 1st person swinging movement
|
static float swingCounter = 0.0f; // Used for 1st person swinging movement
|
||||||
|
|
||||||
// TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?)
|
// TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?)
|
||||||
|
|
||||||
// Mouse movement detection
|
// Mouse movement detection
|
||||||
Vector2 mousePositionDelta = { 0.0f, 0.0f };
|
Vector2 mousePositionDelta = GetMouseDelta();
|
||||||
Vector2 mousePosition = GetMousePosition();
|
|
||||||
float mouseWheelMove = GetMouseWheelMove();
|
float mouseWheelMove = GetMouseWheelMove();
|
||||||
|
|
||||||
// Keys input detection
|
// Keys input detection
|
||||||
|
@ -302,14 +299,6 @@ void UpdateCamera(Camera *camera)
|
||||||
IsKeyDown(CAMERA.moveControl[MOVE_UP]),
|
IsKeyDown(CAMERA.moveControl[MOVE_UP]),
|
||||||
IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) };
|
IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) };
|
||||||
|
|
||||||
if (CAMERA.mode != CAMERA_CUSTOM)
|
|
||||||
{
|
|
||||||
mousePositionDelta.x = mousePosition.x - CAMERA.previousMousePosition.x;
|
|
||||||
mousePositionDelta.y = mousePosition.y - CAMERA.previousMousePosition.y;
|
|
||||||
|
|
||||||
CAMERA.previousMousePosition = mousePosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Support for multiple automatic camera modes
|
// Support for multiple automatic camera modes
|
||||||
// NOTE: In case of CAMERA_CUSTOM nothing happens here, user must update it manually
|
// NOTE: In case of CAMERA_CUSTOM nothing happens here, user must update it manually
|
||||||
switch (CAMERA.mode)
|
switch (CAMERA.mode)
|
||||||
|
@ -388,9 +377,9 @@ void UpdateCamera(Camera *camera)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Camera panning
|
// Camera panning
|
||||||
camera->target.x += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
|
camera->target.x += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
|
||||||
camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
|
camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
|
||||||
camera->target.z += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
|
camera->target.z += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,7 +391,7 @@ void UpdateCamera(Camera *camera)
|
||||||
} break;
|
} break;
|
||||||
case CAMERA_ORBITAL: // Camera just orbits around target, only zoom allowed
|
case CAMERA_ORBITAL: // Camera just orbits around target, only zoom allowed
|
||||||
{
|
{
|
||||||
CAMERA.angle.x += CAMERA_ORBITAL_SPEED; // Camera orbit angle
|
CAMERA.angle.x += CAMERA_ORBITAL_SPEED*GetFrameTime(); // Camera orbit angle
|
||||||
CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom
|
CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom
|
||||||
|
|
||||||
// Camera distance clamp
|
// Camera distance clamp
|
||||||
|
@ -419,20 +408,20 @@ void UpdateCamera(Camera *camera)
|
||||||
camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
|
camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
|
||||||
sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
|
sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
|
||||||
cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
|
cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
|
||||||
cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
|
cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
|
||||||
|
|
||||||
camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
|
camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
|
||||||
sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
|
sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
|
||||||
1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY;
|
1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
|
||||||
|
|
||||||
camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
|
camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
|
||||||
cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
|
cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
|
||||||
sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
|
sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
|
||||||
sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
|
sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
|
||||||
|
|
||||||
// Camera orientation calculation
|
// Camera orientation calculation
|
||||||
CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
|
CAMERA.angle.x -= mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY*GetFrameTime();
|
||||||
CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
|
CAMERA.angle.y -= mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY*GetFrameTime();
|
||||||
|
|
||||||
// Angle clamp
|
// Angle clamp
|
||||||
if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD;
|
if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD;
|
||||||
|
@ -490,15 +479,17 @@ void UpdateCamera(Camera *camera)
|
||||||
camera->target.y = camera->position.y - matTransform.m13;
|
camera->target.y = camera->position.y - matTransform.m13;
|
||||||
camera->target.z = camera->position.z - matTransform.m14;
|
camera->target.z = camera->position.z - matTransform.m14;
|
||||||
|
|
||||||
// If movement detected (some key pressed), increase swinging
|
|
||||||
for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter++; break; }
|
|
||||||
|
|
||||||
// Camera position update
|
// Camera position update
|
||||||
// NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position'
|
// NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position'
|
||||||
camera->position.y = CAMERA.playerEyesPosition - sinf(swingCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER;
|
camera->position.y = CAMERA.playerEyesPosition;
|
||||||
|
|
||||||
camera->up.x = sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
|
// Camera swinging (y-movement), only when walking (some key pressed)
|
||||||
camera->up.z = -sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
|
for (int i = 0; i < 6; i++) if (direction[i]) { swingCounter += GetFrameTime(); break; }
|
||||||
|
camera->position.y -= sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_SWINGING_DELTA;
|
||||||
|
|
||||||
|
// Camera waiving (xz-movement), only when walking (some key pressed)
|
||||||
|
camera->up.x = sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_TILTING_DELTA;
|
||||||
|
camera->up.z = -sinf(2*PI*CAMERA_FIRST_PERSON_STEP_FREQUENCY*swingCounter)*CAMERA_FIRST_PERSON_TILTING_DELTA;
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
case CAMERA_THIRD_PERSON: // Camera moves as in a third-person game, following target at a distance, controls are configurable
|
case CAMERA_THIRD_PERSON: // Camera moves as in a third-person game, following target at a distance, controls are configurable
|
||||||
|
@ -506,16 +497,16 @@ void UpdateCamera(Camera *camera)
|
||||||
camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
|
camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
|
||||||
sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
|
sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
|
||||||
cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
|
cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
|
||||||
cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
|
cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
|
||||||
|
|
||||||
camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
|
camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
|
||||||
sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
|
sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
|
||||||
1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY;
|
1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
|
||||||
|
|
||||||
camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
|
camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
|
||||||
cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
|
cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
|
||||||
sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
|
sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
|
||||||
sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
|
sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
|
||||||
|
|
||||||
// Camera orientation calculation
|
// Camera orientation calculation
|
||||||
CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
|
CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
|
||||||
|
|
1251
raylib/rcore.c
1251
raylib/rcore.c
File diff suppressed because it is too large
Load diff
|
@ -24,7 +24,7 @@
|
||||||
*
|
*
|
||||||
* LICENSE: zlib/libpng
|
* LICENSE: zlib/libpng
|
||||||
*
|
*
|
||||||
* Copyright (c) 2014-2021 Ramon Santamaria (@raysan5)
|
* Copyright (c) 2014-2022 Ramon Santamaria (@raysan5)
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
* 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.
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -62,10 +62,10 @@
|
||||||
// NOTE: Below types are required for GESTURES_STANDALONE usage
|
// NOTE: Below types are required for GESTURES_STANDALONE usage
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Boolean type
|
// Boolean type
|
||||||
#if defined(__STDC__) && __STDC_VERSION__ >= 199901L
|
#if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE)
|
#elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE)
|
||||||
typedef enum bool { false, true } bool;
|
typedef enum bool { false = 0, true = !false } bool;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(RL_VECTOR2_TYPE)
|
#if !defined(RL_VECTOR2_TYPE)
|
||||||
|
@ -118,7 +118,7 @@ typedef struct {
|
||||||
// Module Functions Declaration
|
// Module Functions Declaration
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#if defined(__cplusplus)
|
||||||
extern "C" { // Prevents name mangling of functions
|
extern "C" { // Prevents name mangling of functions
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ Vector2 GetGesturePinchVector(void); // Get gesture pinch del
|
||||||
float GetGesturePinchAngle(void); // Get gesture pinch angle
|
float GetGesturePinchAngle(void); // Get gesture pinch angle
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
172
raylib/rlgl.h
172
raylib/rlgl.h
|
@ -85,7 +85,7 @@
|
||||||
*
|
*
|
||||||
* LICENSE: zlib/libpng
|
* LICENSE: zlib/libpng
|
||||||
*
|
*
|
||||||
* Copyright (c) 2014-2021 Ramon Santamaria (@raysan5)
|
* Copyright (c) 2014-2022 Ramon Santamaria (@raysan5)
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
* 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.
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -358,11 +358,11 @@ typedef struct rlRenderBatch {
|
||||||
float currentDepth; // Current depth value for next draw
|
float currentDepth; // Current depth value for next draw
|
||||||
} rlRenderBatch;
|
} rlRenderBatch;
|
||||||
|
|
||||||
#if defined(__STDC__) && __STDC_VERSION__ >= 199901L
|
#if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE)
|
#elif !defined(__cplusplus) && !defined(bool) && !defined(RL_BOOL_TYPE)
|
||||||
// Boolean type
|
// Boolean type
|
||||||
typedef enum bool { false, true } bool;
|
typedef enum bool { false = 0, true = !false } bool;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(RL_MATRIX_TYPE)
|
#if !defined(RL_MATRIX_TYPE)
|
||||||
|
@ -418,7 +418,7 @@ typedef enum {
|
||||||
// NOTE 1: Filtering considers mipmaps if available in the texture
|
// NOTE 1: Filtering considers mipmaps if available in the texture
|
||||||
// NOTE 2: Filter is accordingly set for minification and magnification
|
// NOTE 2: Filter is accordingly set for minification and magnification
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RL_TEXTURE_FILTER_POINT = 0, // No filter, just pixel aproximation
|
RL_TEXTURE_FILTER_POINT = 0, // No filter, just pixel approximation
|
||||||
RL_TEXTURE_FILTER_BILINEAR, // Linear filtering
|
RL_TEXTURE_FILTER_BILINEAR, // Linear filtering
|
||||||
RL_TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps)
|
RL_TEXTURE_FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps)
|
||||||
RL_TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x
|
RL_TEXTURE_FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x
|
||||||
|
@ -433,7 +433,8 @@ typedef enum {
|
||||||
RL_BLEND_MULTIPLIED, // Blend textures multiplying colors
|
RL_BLEND_MULTIPLIED, // Blend textures multiplying colors
|
||||||
RL_BLEND_ADD_COLORS, // Blend textures adding colors (alternative)
|
RL_BLEND_ADD_COLORS, // Blend textures adding colors (alternative)
|
||||||
RL_BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative)
|
RL_BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative)
|
||||||
RL_BLEND_CUSTOM // Belnd textures using custom src/dst factors (use SetBlendModeCustom())
|
RL_BLEND_ALPHA_PREMULTIPLY, // Blend premultiplied textures considering alpha
|
||||||
|
RL_BLEND_CUSTOM // Blend textures using custom src/dst factors (use rlSetBlendFactors())
|
||||||
} rlBlendMode;
|
} rlBlendMode;
|
||||||
|
|
||||||
// Shader location point type
|
// Shader location point type
|
||||||
|
@ -597,7 +598,9 @@ RLAPI void rlglInit(int width, int height); // Initialize rlgl (buffer
|
||||||
RLAPI void rlglClose(void); // De-inititialize rlgl (buffers, shaders, textures)
|
RLAPI void rlglClose(void); // De-inititialize rlgl (buffers, shaders, textures)
|
||||||
RLAPI void rlLoadExtensions(void *loader); // Load OpenGL extensions (loader function required)
|
RLAPI void rlLoadExtensions(void *loader); // Load OpenGL extensions (loader function required)
|
||||||
RLAPI int rlGetVersion(void); // Get current OpenGL version
|
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 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 int rlGetFramebufferHeight(void); // Get default framebuffer height
|
||||||
|
|
||||||
RLAPI unsigned int rlGetTextureIdDefault(void); // Get default texture id
|
RLAPI unsigned int rlGetTextureIdDefault(void); // Get default texture id
|
||||||
|
@ -619,25 +622,26 @@ RLAPI void rlSetTexture(unsigned int id); // Set current texture for r
|
||||||
|
|
||||||
// Vertex buffers management
|
// Vertex buffers management
|
||||||
RLAPI unsigned int rlLoadVertexArray(void); // Load vertex array (vao) if supported
|
RLAPI unsigned int rlLoadVertexArray(void); // Load vertex array (vao) if supported
|
||||||
RLAPI unsigned int rlLoadVertexBuffer(void *buffer, int size, bool dynamic); // Load a vertex buffer attribute
|
RLAPI unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic); // Load a vertex buffer attribute
|
||||||
RLAPI unsigned int rlLoadVertexBufferElement(void *buffer, int size, bool dynamic); // Load a new attributes element buffer
|
RLAPI unsigned int rlLoadVertexBufferElement(const void *buffer, int size, bool dynamic); // Load a new attributes element buffer
|
||||||
RLAPI void rlUpdateVertexBuffer(unsigned int bufferId, void *data, int dataSize, int offset); // Update GPU buffer with new data
|
RLAPI void 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 rlUnloadVertexArray(unsigned int vaoId);
|
||||||
RLAPI void rlUnloadVertexBuffer(unsigned int vboId);
|
RLAPI void rlUnloadVertexBuffer(unsigned int vboId);
|
||||||
RLAPI void rlSetVertexAttribute(unsigned int index, int compSize, int type, bool normalized, int stride, void *pointer);
|
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 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 rlSetVertexAttributeDefault(int locIndex, const void *value, int attribType, int count); // Set vertex attribute default value
|
||||||
RLAPI void rlDrawVertexArray(int offset, int count);
|
RLAPI void rlDrawVertexArray(int offset, int count);
|
||||||
RLAPI void rlDrawVertexArrayElements(int offset, int count, void *buffer);
|
RLAPI void rlDrawVertexArrayElements(int offset, int count, const void *buffer);
|
||||||
RLAPI void rlDrawVertexArrayInstanced(int offset, int count, int instances);
|
RLAPI void rlDrawVertexArrayInstanced(int offset, int count, int instances);
|
||||||
RLAPI void rlDrawVertexArrayElementsInstanced(int offset, int count, void *buffer, int instances);
|
RLAPI void rlDrawVertexArrayElementsInstanced(int offset, int count, const void *buffer, int instances);
|
||||||
|
|
||||||
// Textures management
|
// Textures management
|
||||||
RLAPI unsigned int rlLoadTexture(void *data, int width, int height, int format, int mipmapCount); // Load texture in GPU
|
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 rlLoadTextureDepth(int width, int height, bool useRenderBuffer); // Load depth texture/renderbuffer (to be attached to fbo)
|
||||||
RLAPI unsigned int rlLoadTextureCubemap(void *data, int size, int format); // Load texture cubemap
|
RLAPI 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 rlUpdateTexture(unsigned int id, int offsetX, int offsetY, int width, int height, int format, const void *data); // Update GPU texture with new data
|
||||||
RLAPI void rlGetGlTextureFormats(int format, int *glInternalFormat, int *glFormat, int *glType); // Get OpenGL internal formats
|
RLAPI 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 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 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 rlGenTextureMipmaps(unsigned int id, int width, int height, int format, int *mipmaps); // Generate mipmap data for selected texture
|
||||||
|
@ -713,7 +717,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
|
||||||
#include <OpenGL/glext.h> // OpenGL extensions library
|
#include <OpenGL/glext.h> // OpenGL extensions library
|
||||||
#else
|
#else
|
||||||
// APIENTRY for OpenGL function pointer declarations is required
|
// APIENTRY for OpenGL function pointer declarations is required
|
||||||
#ifndef APIENTRY
|
#if !defined(APIENTRY)
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#define APIENTRY __stdcall
|
#define APIENTRY __stdcall
|
||||||
#else
|
#else
|
||||||
|
@ -925,8 +929,8 @@ typedef struct rlglData {
|
||||||
int glBlendDstFactor; // Blending destination factor
|
int glBlendDstFactor; // Blending destination factor
|
||||||
int glBlendEquation; // Blending equation
|
int glBlendEquation; // Blending equation
|
||||||
|
|
||||||
int framebufferWidth; // Default framebuffer width
|
int framebufferWidth; // Current framebuffer width
|
||||||
int framebufferHeight; // Default framebuffer height
|
int framebufferHeight; // Current framebuffer height
|
||||||
|
|
||||||
} State; // Renderer state
|
} State; // Renderer state
|
||||||
struct {
|
struct {
|
||||||
|
@ -1228,6 +1232,7 @@ void rlOrtho(double left, double right, double bottom, double top, double znear,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Set the viewport area (transformation from normalized device coordinates to window coordinates)
|
// 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)
|
void rlViewport(int x, int y, int width, int height)
|
||||||
{
|
{
|
||||||
glViewport(x, y, width, height);
|
glViewport(x, y, width, height);
|
||||||
|
@ -1512,6 +1517,11 @@ void rlTextureParameters(unsigned int id, int param, int value)
|
||||||
{
|
{
|
||||||
glBindTexture(GL_TEXTURE_2D, id);
|
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)
|
switch (param)
|
||||||
{
|
{
|
||||||
case RL_TEXTURE_WRAP_S:
|
case RL_TEXTURE_WRAP_S:
|
||||||
|
@ -1535,7 +1545,7 @@ void rlTextureParameters(unsigned int id, int param, int value)
|
||||||
if (value <= RLGL.ExtSupported.maxAnisotropyLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value);
|
if (value <= RLGL.ExtSupported.maxAnisotropyLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value);
|
||||||
else if (RLGL.ExtSupported.maxAnisotropyLevel > 0.0f)
|
else if (RLGL.ExtSupported.maxAnisotropyLevel > 0.0f)
|
||||||
{
|
{
|
||||||
TRACELOG(RL_LOG_WARNING, "GL: Maximum anisotropic filter level supported is %iX", id, RLGL.ExtSupported.maxAnisotropyLevel);
|
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);
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value);
|
||||||
}
|
}
|
||||||
else TRACELOG(RL_LOG_WARNING, "GL: Anisotropic filtering not supported");
|
else TRACELOG(RL_LOG_WARNING, "GL: Anisotropic filtering not supported");
|
||||||
|
@ -1778,7 +1788,12 @@ void rlSetBlendMode(int mode)
|
||||||
case RL_BLEND_MULTIPLIED: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); 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_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_SUBTRACT_COLORS: glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_SUBTRACT); break;
|
||||||
case RL_BLEND_CUSTOM: glBlendFunc(RLGL.State.glBlendSrcFactor, RLGL.State.glBlendDstFactor); glBlendEquation(RLGL.State.glBlendEquation); break;
|
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;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2212,6 +2227,22 @@ int rlGetVersion(void)
|
||||||
return glVersion;
|
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
|
// Get default framebuffer width
|
||||||
int rlGetFramebufferWidth(void)
|
int rlGetFramebufferWidth(void)
|
||||||
{
|
{
|
||||||
|
@ -2594,6 +2625,9 @@ void rlDrawRenderBatch(rlRenderBatch *batch)
|
||||||
|
|
||||||
glUseProgram(0); // Unbind shader program
|
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 batch buffers
|
||||||
|
@ -2676,12 +2710,12 @@ bool rlCheckRenderBatchLimit(int vCount)
|
||||||
// Textures data management
|
// Textures data management
|
||||||
//-----------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------------
|
||||||
// Convert image data to OpenGL texture (returns OpenGL valid Id)
|
// Convert image data to OpenGL texture (returns OpenGL valid Id)
|
||||||
unsigned int rlLoadTexture(void *data, int width, int height, int format, int mipmapCount)
|
unsigned int rlLoadTexture(const void *data, int width, int height, int format, int mipmapCount)
|
||||||
{
|
{
|
||||||
glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding
|
|
||||||
|
|
||||||
unsigned int id = 0;
|
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)
|
// Check texture format support by OpenGL 1.1 (compressed textures not supported)
|
||||||
#if defined(GRAPHICS_API_OPENGL_11)
|
#if defined(GRAPHICS_API_OPENGL_11)
|
||||||
if (format >= RL_PIXELFORMAT_COMPRESSED_DXT1_RGB)
|
if (format >= RL_PIXELFORMAT_COMPRESSED_DXT1_RGB)
|
||||||
|
@ -2738,7 +2772,7 @@ unsigned int rlLoadTexture(void *data, int width, int height, int format, int mi
|
||||||
{
|
{
|
||||||
unsigned int mipSize = rlGetPixelDataSize(mipWidth, mipHeight, format);
|
unsigned int mipSize = rlGetPixelDataSize(mipWidth, mipHeight, format);
|
||||||
|
|
||||||
int glInternalFormat, glFormat, glType;
|
unsigned int glInternalFormat, glFormat, glType;
|
||||||
rlGetGlTextureFormats(format, &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);
|
TRACELOGD("TEXTURE: Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset);
|
||||||
|
@ -2878,7 +2912,7 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer)
|
||||||
// Load texture cubemap
|
// Load texture cubemap
|
||||||
// NOTE: Cubemap data is expected to be 6 images in a single data array (one after the other),
|
// 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
|
// expected the following convention: +X, -X, +Y, -Y, +Z, -Z
|
||||||
unsigned int rlLoadTextureCubemap(void *data, int size, int format)
|
unsigned int rlLoadTextureCubemap(const void *data, int size, int format)
|
||||||
{
|
{
|
||||||
unsigned int id = 0;
|
unsigned int id = 0;
|
||||||
|
|
||||||
|
@ -2888,7 +2922,7 @@ unsigned int rlLoadTextureCubemap(void *data, int size, int format)
|
||||||
glGenTextures(1, &id);
|
glGenTextures(1, &id);
|
||||||
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
|
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
|
||||||
|
|
||||||
int glInternalFormat, glFormat, glType;
|
unsigned int glInternalFormat, glFormat, glType;
|
||||||
rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
|
rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
|
||||||
|
|
||||||
if (glInternalFormat != -1)
|
if (glInternalFormat != -1)
|
||||||
|
@ -2960,22 +2994,22 @@ void rlUpdateTexture(unsigned int id, int offsetX, int offsetY, int width, int h
|
||||||
{
|
{
|
||||||
glBindTexture(GL_TEXTURE_2D, id);
|
glBindTexture(GL_TEXTURE_2D, id);
|
||||||
|
|
||||||
int glInternalFormat, glFormat, glType;
|
unsigned int glInternalFormat, glFormat, glType;
|
||||||
rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
|
rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
|
||||||
|
|
||||||
if ((glInternalFormat != -1) && (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB))
|
if ((glInternalFormat != -1) && (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB))
|
||||||
{
|
{
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, offsetX, offsetY, width, height, glFormat, glType, (unsigned char *)data);
|
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);
|
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
|
// Get OpenGL internal formats and data type from raylib PixelFormat
|
||||||
void rlGetGlTextureFormats(int format, int *glInternalFormat, int *glFormat, int *glType)
|
void rlGetGlTextureFormats(int format, unsigned int *glInternalFormat, unsigned int *glFormat, unsigned int *glType)
|
||||||
{
|
{
|
||||||
*glInternalFormat = -1;
|
*glInternalFormat = 0;
|
||||||
*glFormat = -1;
|
*glFormat = 0;
|
||||||
*glType = -1;
|
*glType = 0;
|
||||||
|
|
||||||
switch (format)
|
switch (format)
|
||||||
{
|
{
|
||||||
|
@ -3081,14 +3115,11 @@ void rlGenTextureMipmaps(unsigned int id, int width, int height, int format, int
|
||||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
if ((texIsPOT) || (RLGL.ExtSupported.texNPOT))
|
if ((texIsPOT) || (RLGL.ExtSupported.texNPOT))
|
||||||
{
|
{
|
||||||
//glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorythm: GL_FASTEST, GL_NICEST, GL_DONT_CARE
|
//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
|
glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
#define MIN(a,b) (((a)<(b))? (a):(b))
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate Trilinear filtering for mipmaps
|
#define MAX(a,b) (((a)>(b))? (a):(b))
|
||||||
|
|
||||||
#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));
|
*mipmaps = 1 + (int)floor(log(MAX(width, height))/log(2));
|
||||||
TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Mipmaps generated automatically, total: %i", id, *mipmaps);
|
TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Mipmaps generated automatically, total: %i", id, *mipmaps);
|
||||||
|
@ -3121,7 +3152,7 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format)
|
||||||
// GL_UNPACK_ALIGNMENT affects operations that write to OpenGL memory (glTexImage, etc.)
|
// GL_UNPACK_ALIGNMENT affects operations that write to OpenGL memory (glTexImage, etc.)
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
int glInternalFormat, glFormat, glType;
|
unsigned int glInternalFormat, glFormat, glType;
|
||||||
rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
|
rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
|
||||||
unsigned int size = rlGetPixelDataSize(width, height, format);
|
unsigned int size = rlGetPixelDataSize(width, height, format);
|
||||||
|
|
||||||
|
@ -3164,7 +3195,6 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format)
|
||||||
return pixels;
|
return pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Read screen pixel data (color buffer)
|
// Read screen pixel data (color buffer)
|
||||||
unsigned char *rlReadScreenPixels(int width, int height)
|
unsigned char *rlReadScreenPixels(int width, int height)
|
||||||
{
|
{
|
||||||
|
@ -3313,7 +3343,7 @@ void rlUnloadFramebuffer(unsigned int id)
|
||||||
// Vertex data management
|
// Vertex data management
|
||||||
//-----------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------------
|
||||||
// Load a new attributes buffer
|
// Load a new attributes buffer
|
||||||
unsigned int rlLoadVertexBuffer(void *buffer, int size, bool dynamic)
|
unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic)
|
||||||
{
|
{
|
||||||
unsigned int id = 0;
|
unsigned int id = 0;
|
||||||
|
|
||||||
|
@ -3327,7 +3357,7 @@ unsigned int rlLoadVertexBuffer(void *buffer, int size, bool dynamic)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load a new attributes element buffer
|
// Load a new attributes element buffer
|
||||||
unsigned int rlLoadVertexBufferElement(void *buffer, int size, bool dynamic)
|
unsigned int rlLoadVertexBufferElement(const void *buffer, int size, bool dynamic)
|
||||||
{
|
{
|
||||||
unsigned int id = 0;
|
unsigned int id = 0;
|
||||||
|
|
||||||
|
@ -3374,7 +3404,7 @@ void rlDisableVertexBufferElement(void)
|
||||||
|
|
||||||
// Update vertex buffer with new data
|
// Update vertex buffer with new data
|
||||||
// NOTE: dataSize and offset must be provided in bytes
|
// NOTE: dataSize and offset must be provided in bytes
|
||||||
void rlUpdateVertexBuffer(unsigned int id, void *data, int dataSize, int offset)
|
void rlUpdateVertexBuffer(unsigned int id, const void *data, int dataSize, int offset)
|
||||||
{
|
{
|
||||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, id);
|
glBindBuffer(GL_ARRAY_BUFFER, id);
|
||||||
|
@ -3384,7 +3414,7 @@ void rlUpdateVertexBuffer(unsigned int id, void *data, int dataSize, int offset)
|
||||||
|
|
||||||
// Update vertex buffer elements with new data
|
// Update vertex buffer elements with new data
|
||||||
// NOTE: dataSize and offset must be provided in bytes
|
// NOTE: dataSize and offset must be provided in bytes
|
||||||
void rlUpdateVertexBufferElements(unsigned int id, void *data, int dataSize, int offset)
|
void rlUpdateVertexBufferElements(unsigned int id, const void *data, int dataSize, int offset)
|
||||||
{
|
{
|
||||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id);
|
||||||
|
@ -3437,9 +3467,9 @@ void rlDrawVertexArray(int offset, int count)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw vertex array elements
|
// Draw vertex array elements
|
||||||
void rlDrawVertexArrayElements(int offset, int count, void *buffer)
|
void rlDrawVertexArrayElements(int offset, int count, const void *buffer)
|
||||||
{
|
{
|
||||||
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (unsigned short *)buffer + offset);
|
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (const unsigned short *)buffer + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw vertex array instanced
|
// Draw vertex array instanced
|
||||||
|
@ -3451,10 +3481,10 @@ void rlDrawVertexArrayInstanced(int offset, int count, int instances)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw vertex array elements instanced
|
// Draw vertex array elements instanced
|
||||||
void rlDrawVertexArrayElementsInstanced(int offset, int count, void *buffer, int instances)
|
void rlDrawVertexArrayElementsInstanced(int offset, int count, const void *buffer, int instances)
|
||||||
{
|
{
|
||||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
glDrawElementsInstanced(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (unsigned short *)buffer + offset, instances);
|
glDrawElementsInstanced(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, (const unsigned short *)buffer + offset, instances);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3495,7 +3525,7 @@ unsigned int rlLoadVertexArray(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set vertex attribute
|
// Set vertex attribute
|
||||||
void rlSetVertexAttribute(unsigned int index, int compSize, int type, bool normalized, int stride, void *pointer)
|
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)
|
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
glVertexAttribPointer(index, compSize, type, normalized, stride, pointer);
|
glVertexAttribPointer(index, compSize, type, normalized, stride, pointer);
|
||||||
|
@ -3541,41 +3571,52 @@ unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode)
|
||||||
unsigned int id = 0;
|
unsigned int id = 0;
|
||||||
|
|
||||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
unsigned int vertexShaderId = RLGL.State.defaultVShaderId;
|
unsigned int vertexShaderId = 0;
|
||||||
unsigned int fragmentShaderId = RLGL.State.defaultFShaderId;
|
unsigned int fragmentShaderId = 0;
|
||||||
|
|
||||||
|
// Compile vertex shader (if provided)
|
||||||
if (vsCode != NULL) vertexShaderId = rlCompileShader(vsCode, GL_VERTEX_SHADER);
|
if (vsCode != NULL) vertexShaderId = rlCompileShader(vsCode, GL_VERTEX_SHADER);
|
||||||
if (fsCode != NULL) fragmentShaderId = rlCompileShader(fsCode, GL_FRAGMENT_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;
|
if ((vertexShaderId == RLGL.State.defaultVShaderId) && (fragmentShaderId == RLGL.State.defaultFShaderId)) id = RLGL.State.defaultShaderId;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// One of or both shader are new, we need to compile a new shader program
|
||||||
id = rlLoadShaderProgram(vertexShaderId, fragmentShaderId);
|
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)
|
if (vertexShaderId != RLGL.State.defaultVShaderId)
|
||||||
{
|
{
|
||||||
// Detach shader before deletion to make sure memory is freed
|
|
||||||
glDetachShader(id, vertexShaderId);
|
glDetachShader(id, vertexShaderId);
|
||||||
glDeleteShader(vertexShaderId);
|
glDeleteShader(vertexShaderId);
|
||||||
}
|
}
|
||||||
if (fragmentShaderId != RLGL.State.defaultFShaderId)
|
if (fragmentShaderId != RLGL.State.defaultFShaderId)
|
||||||
{
|
{
|
||||||
// Detach shader before deletion to make sure memory is freed
|
|
||||||
glDetachShader(id, fragmentShaderId);
|
glDetachShader(id, fragmentShaderId);
|
||||||
glDeleteShader(fragmentShaderId);
|
glDeleteShader(fragmentShaderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In case shader program loading failed, we assign default shader
|
||||||
if (id == 0)
|
if (id == 0)
|
||||||
{
|
{
|
||||||
TRACELOG(RL_LOG_WARNING, "SHADER: Failed to load custom shader code");
|
// 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;
|
id = RLGL.State.defaultShaderId;
|
||||||
}
|
}
|
||||||
}
|
/*
|
||||||
|
else
|
||||||
|
{
|
||||||
// Get available shader uniforms
|
// Get available shader uniforms
|
||||||
// NOTE: This information is useful for debug...
|
// NOTE: This information is useful for debug...
|
||||||
int uniformCount = -1;
|
int uniformCount = -1;
|
||||||
|
|
||||||
glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &uniformCount);
|
glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &uniformCount);
|
||||||
|
|
||||||
for (int i = 0; i < uniformCount; i++)
|
for (int i = 0; i < uniformCount; i++)
|
||||||
|
@ -3589,9 +3630,11 @@ unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode)
|
||||||
glGetActiveUniform(id, i, sizeof(name) - 1, &namelen, &num, &type, name);
|
glGetActiveUniform(id, i, sizeof(name) - 1, &namelen, &num, &type, name);
|
||||||
|
|
||||||
name[namelen] = 0;
|
name[namelen] = 0;
|
||||||
|
|
||||||
TRACELOGD("SHADER: [ID %i] Active uniform (%s) set at location: %i", id, name, glGetUniformLocation(id, name));
|
TRACELOGD("SHADER: [ID %i] Active uniform (%s) set at location: %i", id, name, glGetUniformLocation(id, name));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
|
@ -3629,7 +3672,7 @@ unsigned int rlCompileShader(const char *shaderCode, int type)
|
||||||
if (maxLength > 0)
|
if (maxLength > 0)
|
||||||
{
|
{
|
||||||
int length = 0;
|
int length = 0;
|
||||||
char *log = RL_CALLOC(maxLength, sizeof(char));
|
char *log = (char *)RL_CALLOC(maxLength, sizeof(char));
|
||||||
glGetShaderInfoLog(shader, maxLength, &length, log);
|
glGetShaderInfoLog(shader, maxLength, &length, log);
|
||||||
TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Compile error: %s", shader, log);
|
TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Compile error: %s", shader, log);
|
||||||
RL_FREE(log);
|
RL_FREE(log);
|
||||||
|
@ -3691,7 +3734,7 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId)
|
||||||
if (maxLength > 0)
|
if (maxLength > 0)
|
||||||
{
|
{
|
||||||
int length = 0;
|
int length = 0;
|
||||||
char *log = RL_CALLOC(maxLength, sizeof(char));
|
char *log = (char *)RL_CALLOC(maxLength, sizeof(char));
|
||||||
glGetProgramInfoLog(program, maxLength, &length, log);
|
glGetProgramInfoLog(program, maxLength, &length, log);
|
||||||
TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", program, log);
|
TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", program, log);
|
||||||
RL_FREE(log);
|
RL_FREE(log);
|
||||||
|
@ -3858,7 +3901,7 @@ unsigned int rlLoadComputeShaderProgram(unsigned int shaderId)
|
||||||
if (maxLength > 0)
|
if (maxLength > 0)
|
||||||
{
|
{
|
||||||
int length = 0;
|
int length = 0;
|
||||||
char *log = RL_CALLOC(maxLength, sizeof(char));
|
char *log = (char *)RL_CALLOC(maxLength, sizeof(char));
|
||||||
glGetProgramInfoLog(program, maxLength, &length, log);
|
glGetProgramInfoLog(program, maxLength, &length, log);
|
||||||
TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", program, log);
|
TRACELOG(RL_LOG_WARNING, "SHADER: [ID %i] Link error: %s", program, log);
|
||||||
RL_FREE(log);
|
RL_FREE(log);
|
||||||
|
@ -3899,6 +3942,8 @@ unsigned int rlLoadShaderBuffer(unsigned long long size, const void *data, int u
|
||||||
glGenBuffers(1, &ssbo);
|
glGenBuffers(1, &ssbo);
|
||||||
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
|
||||||
glBufferData(GL_SHADER_STORAGE_BUFFER, size, data, usageHint? usageHint : RL_STREAM_COPY);
|
glBufferData(GL_SHADER_STORAGE_BUFFER, size, data, usageHint? usageHint : RL_STREAM_COPY);
|
||||||
|
glClearBufferData(GL_SHADER_STORAGE_BUFFER, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, 0);
|
||||||
|
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return ssbo;
|
return ssbo;
|
||||||
|
@ -3965,7 +4010,7 @@ void rlCopyBuffersElements(unsigned int destId, unsigned int srcId, unsigned lon
|
||||||
void rlBindImageTexture(unsigned int id, unsigned int index, unsigned int format, int readonly)
|
void rlBindImageTexture(unsigned int id, unsigned int index, unsigned int format, int readonly)
|
||||||
{
|
{
|
||||||
#if defined(GRAPHICS_API_OPENGL_43)
|
#if defined(GRAPHICS_API_OPENGL_43)
|
||||||
int glInternalFormat = 0, glFormat = 0, glType = 0;
|
unsigned int glInternalFormat = 0, glFormat = 0, glType = 0;
|
||||||
|
|
||||||
rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
|
rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType);
|
||||||
glBindImageTexture(index, id, 0, 0, 0, readonly ? GL_READ_ONLY : GL_READ_WRITE, glInternalFormat);
|
glBindImageTexture(index, id, 0, 0, 0, readonly ? GL_READ_ONLY : GL_READ_WRITE, glInternalFormat);
|
||||||
|
@ -4336,7 +4381,8 @@ static void rlLoadShaderDefault(void)
|
||||||
"} \n";
|
"} \n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// NOTE: Compiled vertex/fragment shaders are kept for re-use
|
// 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.defaultVShaderId = rlCompileShader(defaultVShaderCode, GL_VERTEX_SHADER); // Compile default vertex shader
|
||||||
RLGL.State.defaultFShaderId = rlCompileShader(defaultFShaderCode, GL_FRAGMENT_SHADER); // Compile default fragment shader
|
RLGL.State.defaultFShaderId = rlCompileShader(defaultFShaderCode, GL_FRAGMENT_SHADER); // Compile default fragment shader
|
||||||
|
|
||||||
|
|
620
raylib/rmodels.c
620
raylib/rmodels.c
|
@ -4,12 +4,15 @@
|
||||||
*
|
*
|
||||||
* CONFIGURATION:
|
* CONFIGURATION:
|
||||||
*
|
*
|
||||||
|
* #define SUPPORT_MODULE_RMODELS
|
||||||
|
* rmodels module is included in the build
|
||||||
|
*
|
||||||
* #define SUPPORT_FILEFORMAT_OBJ
|
* #define SUPPORT_FILEFORMAT_OBJ
|
||||||
* #define SUPPORT_FILEFORMAT_MTL
|
* #define SUPPORT_FILEFORMAT_MTL
|
||||||
* #define SUPPORT_FILEFORMAT_IQM
|
* #define SUPPORT_FILEFORMAT_IQM
|
||||||
* #define SUPPORT_FILEFORMAT_GLTF
|
* #define SUPPORT_FILEFORMAT_GLTF
|
||||||
* #define SUPPORT_FILEFORMAT_VOX
|
* #define SUPPORT_FILEFORMAT_VOX
|
||||||
*
|
* #define SUPPORT_FILEFORMAT_M3D
|
||||||
* Selected desired fileformats to be supported for model data loading.
|
* Selected desired fileformats to be supported for model data loading.
|
||||||
*
|
*
|
||||||
* #define SUPPORT_MESH_GENERATION
|
* #define SUPPORT_MESH_GENERATION
|
||||||
|
@ -19,7 +22,7 @@
|
||||||
*
|
*
|
||||||
* LICENSE: zlib/libpng
|
* LICENSE: zlib/libpng
|
||||||
*
|
*
|
||||||
* Copyright (c) 2013-2021 Ramon Santamaria (@raysan5)
|
* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5)
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
* 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.
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -45,6 +48,8 @@
|
||||||
#include "config.h" // Defines module configuration flags
|
#include "config.h" // Defines module configuration flags
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(SUPPORT_MODULE_RMODELS)
|
||||||
|
|
||||||
#include "utils.h" // Required for: TRACELOG(), LoadFileData(), LoadFileText(), SaveFileText()
|
#include "utils.h" // Required for: TRACELOG(), LoadFileData(), LoadFileText(), SaveFileText()
|
||||||
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
|
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
|
||||||
#include "raymath.h" // Required for: Vector3, Quaternion and Matrix functionality
|
#include "raymath.h" // Required for: Vector3, Quaternion and Matrix functionality
|
||||||
|
@ -82,6 +87,15 @@
|
||||||
#include "external/vox_loader.h" // VOX file format loading (MagikaVoxel)
|
#include "external/vox_loader.h" // VOX file format loading (MagikaVoxel)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(SUPPORT_FILEFORMAT_M3D)
|
||||||
|
#define M3D_MALLOC RL_MALLOC
|
||||||
|
#define M3D_REALLOC RL_REALLOC
|
||||||
|
#define M3D_FREE RL_FREE
|
||||||
|
|
||||||
|
#define M3D_IMPLEMENTATION
|
||||||
|
#include "external/m3d.h" // Model3D file format loading
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(SUPPORT_MESH_GENERATION)
|
#if defined(SUPPORT_MESH_GENERATION)
|
||||||
#define PAR_MALLOC(T, N) ((T*)RL_MALLOC(N*sizeof(T)))
|
#define PAR_MALLOC(T, N) ((T*)RL_MALLOC(N*sizeof(T)))
|
||||||
#define PAR_CALLOC(T, N) ((T*)RL_CALLOC(N*sizeof(T), 1))
|
#define PAR_CALLOC(T, N) ((T*)RL_CALLOC(N*sizeof(T), 1))
|
||||||
|
@ -137,6 +151,10 @@ static Model LoadGLTF(const char *fileName); // Load GLTF mesh data
|
||||||
#if defined(SUPPORT_FILEFORMAT_VOX)
|
#if defined(SUPPORT_FILEFORMAT_VOX)
|
||||||
static Model LoadVOX(const char *filename); // Load VOX mesh data
|
static Model LoadVOX(const char *filename); // Load VOX mesh data
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(SUPPORT_FILEFORMAT_M3D)
|
||||||
|
static Model LoadM3D(const char *filename); // Load M3D mesh data
|
||||||
|
static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, unsigned int *animCount); // Load M3D animation data
|
||||||
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module Functions Definition
|
// Module Functions Definition
|
||||||
|
@ -196,7 +214,7 @@ void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rota
|
||||||
// Draw a color-filled triangle (vertex in counter-clockwise order!)
|
// Draw a color-filled triangle (vertex in counter-clockwise order!)
|
||||||
void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color)
|
void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color)
|
||||||
{
|
{
|
||||||
rlCheckRenderBatchLimit(3);
|
rlCheckRenderBatchLimit(8);
|
||||||
|
|
||||||
rlBegin(RL_TRIANGLES);
|
rlBegin(RL_TRIANGLES);
|
||||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||||
|
@ -918,11 +936,14 @@ Model LoadModel(const char *fileName)
|
||||||
if (IsFileExtension(fileName, ".iqm")) model = LoadIQM(fileName);
|
if (IsFileExtension(fileName, ".iqm")) model = LoadIQM(fileName);
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_GLTF)
|
#if defined(SUPPORT_FILEFORMAT_GLTF)
|
||||||
if (IsFileExtension(fileName, ".gltf;.glb")) model = LoadGLTF(fileName);
|
if (IsFileExtension(fileName, ".gltf") || IsFileExtension(fileName, ".glb")) model = LoadGLTF(fileName);
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_VOX)
|
#if defined(SUPPORT_FILEFORMAT_VOX)
|
||||||
if (IsFileExtension(fileName, ".vox")) model = LoadVOX(fileName);
|
if (IsFileExtension(fileName, ".vox")) model = LoadVOX(fileName);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(SUPPORT_FILEFORMAT_M3D)
|
||||||
|
if (IsFileExtension(fileName, ".m3d")) model = LoadM3D(fileName);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Make sure model transform is set to identity matrix!
|
// Make sure model transform is set to identity matrix!
|
||||||
model.transform = MatrixIdentity();
|
model.transform = MatrixIdentity();
|
||||||
|
@ -1083,7 +1104,7 @@ void UploadMesh(Mesh *mesh, bool dynamic)
|
||||||
mesh->vaoId = rlLoadVertexArray();
|
mesh->vaoId = rlLoadVertexArray();
|
||||||
rlEnableVertexArray(mesh->vaoId);
|
rlEnableVertexArray(mesh->vaoId);
|
||||||
|
|
||||||
// NOTE: Attributes must be uploaded considering default locations points
|
// NOTE: Vertex attributes must be uploaded considering default locations points and available vertex data
|
||||||
|
|
||||||
// Enable vertex attributes: position (shader-location = 0)
|
// Enable vertex attributes: position (shader-location = 0)
|
||||||
void *vertices = mesh->animVertices != NULL ? mesh->animVertices : mesh->vertices;
|
void *vertices = mesh->animVertices != NULL ? mesh->animVertices : mesh->vertices;
|
||||||
|
@ -1096,6 +1117,9 @@ void UploadMesh(Mesh *mesh, bool dynamic)
|
||||||
rlSetVertexAttribute(1, 2, RL_FLOAT, 0, 0, 0);
|
rlSetVertexAttribute(1, 2, RL_FLOAT, 0, 0, 0);
|
||||||
rlEnableVertexAttribute(1);
|
rlEnableVertexAttribute(1);
|
||||||
|
|
||||||
|
// WARNING: When setting default vertex attribute values, the values for each generic vertex attribute
|
||||||
|
// is part of current state and it is maintained even if a different program object is used
|
||||||
|
|
||||||
if (mesh->normals != NULL)
|
if (mesh->normals != NULL)
|
||||||
{
|
{
|
||||||
// Enable vertex attributes: normals (shader-location = 2)
|
// Enable vertex attributes: normals (shader-location = 2)
|
||||||
|
@ -1106,7 +1130,8 @@ void UploadMesh(Mesh *mesh, bool dynamic)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Default color vertex attribute set to WHITE
|
// Default vertex attribute: normal
|
||||||
|
// WARNING: Default value provided to shader if location available
|
||||||
float value[3] = { 1.0f, 1.0f, 1.0f };
|
float value[3] = { 1.0f, 1.0f, 1.0f };
|
||||||
rlSetVertexAttributeDefault(2, value, SHADER_ATTRIB_VEC3, 3);
|
rlSetVertexAttributeDefault(2, value, SHADER_ATTRIB_VEC3, 3);
|
||||||
rlDisableVertexAttribute(2);
|
rlDisableVertexAttribute(2);
|
||||||
|
@ -1121,8 +1146,9 @@ void UploadMesh(Mesh *mesh, bool dynamic)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Default color vertex attribute set to WHITE
|
// Default vertex attribute: color
|
||||||
float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
// WARNING: Default value provided to shader if location available
|
||||||
|
float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; // WHITE
|
||||||
rlSetVertexAttributeDefault(3, value, SHADER_ATTRIB_VEC4, 4);
|
rlSetVertexAttributeDefault(3, value, SHADER_ATTRIB_VEC4, 4);
|
||||||
rlDisableVertexAttribute(3);
|
rlDisableVertexAttribute(3);
|
||||||
}
|
}
|
||||||
|
@ -1136,7 +1162,8 @@ void UploadMesh(Mesh *mesh, bool dynamic)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Default tangents vertex attribute
|
// Default vertex attribute: tangent
|
||||||
|
// WARNING: Default value provided to shader if location available
|
||||||
float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
float value[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
rlSetVertexAttributeDefault(4, value, SHADER_ATTRIB_VEC4, 4);
|
rlSetVertexAttributeDefault(4, value, SHADER_ATTRIB_VEC4, 4);
|
||||||
rlDisableVertexAttribute(4);
|
rlDisableVertexAttribute(4);
|
||||||
|
@ -1151,7 +1178,8 @@ void UploadMesh(Mesh *mesh, bool dynamic)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Default texcoord2 vertex attribute
|
// Default vertex attribute: texcoord2
|
||||||
|
// WARNING: Default value provided to shader if location available
|
||||||
float value[2] = { 0.0f, 0.0f };
|
float value[2] = { 0.0f, 0.0f };
|
||||||
rlSetVertexAttributeDefault(5, value, SHADER_ATTRIB_VEC2, 2);
|
rlSetVertexAttributeDefault(5, value, SHADER_ATTRIB_VEC2, 2);
|
||||||
rlDisableVertexAttribute(5);
|
rlDisableVertexAttribute(5);
|
||||||
|
@ -1170,7 +1198,7 @@ void UploadMesh(Mesh *mesh, bool dynamic)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update mesh vertex data in GPU for a specific buffer index
|
// Update mesh vertex data in GPU for a specific buffer index
|
||||||
void UpdateMeshBuffer(Mesh mesh, int index, void *data, int dataSize, int offset)
|
void UpdateMeshBuffer(Mesh mesh, int index, const void *data, int dataSize, int offset)
|
||||||
{
|
{
|
||||||
rlUpdateVertexBuffer(mesh.vboId[index], data, dataSize, offset);
|
rlUpdateVertexBuffer(mesh.vboId[index], data, dataSize, offset);
|
||||||
}
|
}
|
||||||
|
@ -1289,8 +1317,10 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try binding vertex array objects (VAO)
|
// Try binding vertex array objects (VAO) or use VBOs if not possible
|
||||||
// or use VBOs if not possible
|
// WARNING: UploadMesh() enables all vertex attributes available in mesh and sets default attribute values
|
||||||
|
// for shader expected vertex attributes that are not provided by the mesh (i.e. colors)
|
||||||
|
// This could be a dangerous approach because different meshes with different shaders can enable/disable some attributes
|
||||||
if (!rlEnableVertexArray(mesh.vaoId))
|
if (!rlEnableVertexArray(mesh.vaoId))
|
||||||
{
|
{
|
||||||
// Bind mesh VBO data: vertex position (shader-location = 0)
|
// Bind mesh VBO data: vertex position (shader-location = 0)
|
||||||
|
@ -1322,10 +1352,10 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Set default value for unused attribute
|
// Set default value for defined vertex attribute in shader but not provided by mesh
|
||||||
// NOTE: Required when using default shader and no VAO support
|
// WARNING: It could result in GPU undefined behaviour
|
||||||
float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||||
rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC2, 4);
|
rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC4, 4);
|
||||||
rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
|
rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1349,6 +1379,9 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
|
||||||
if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]);
|
if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WARNING: Disable vertex attribute color input if mesh can not provide that data (despite location being enabled in shader)
|
||||||
|
if (mesh.vboId[3] == 0) rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
|
||||||
|
|
||||||
int eyeCount = 1;
|
int eyeCount = 1;
|
||||||
if (rlIsStereoRenderEnabled()) eyeCount = 2;
|
if (rlIsStereoRenderEnabled()) eyeCount = 2;
|
||||||
|
|
||||||
|
@ -1374,6 +1407,8 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
|
||||||
|
|
||||||
// Unbind all binded texture maps
|
// Unbind all binded texture maps
|
||||||
for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
|
for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
|
||||||
|
{
|
||||||
|
if (material.maps[i].texture.id > 0)
|
||||||
{
|
{
|
||||||
// Select current shader texture slot
|
// Select current shader texture slot
|
||||||
rlActiveTextureSlot(i);
|
rlActiveTextureSlot(i);
|
||||||
|
@ -1384,6 +1419,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
|
||||||
(i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap();
|
(i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap();
|
||||||
else rlDisableTexture();
|
else rlDisableTexture();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Disable all possible vertex array objects (or VBOs)
|
// Disable all possible vertex array objects (or VBOs)
|
||||||
rlDisableVertexArray();
|
rlDisableVertexArray();
|
||||||
|
@ -1400,7 +1436,7 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw multiple mesh instances with material and different transforms
|
// Draw multiple mesh instances with material and different transforms
|
||||||
void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int instances)
|
void DrawMeshInstanced(Mesh mesh, Material material, const Matrix *transforms, int instances)
|
||||||
{
|
{
|
||||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
// Instancing required variables
|
// Instancing required variables
|
||||||
|
@ -1540,7 +1576,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int ins
|
||||||
// Set default value for unused attribute
|
// Set default value for unused attribute
|
||||||
// NOTE: Required when using default shader and no VAO support
|
// NOTE: Required when using default shader and no VAO support
|
||||||
float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
float value[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||||
rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC2, 4);
|
rlSetVertexAttributeDefault(material.shader.locs[SHADER_LOC_VERTEX_COLOR], value, SHADER_ATTRIB_VEC4, 4);
|
||||||
rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
|
rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1564,6 +1600,9 @@ void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int ins
|
||||||
if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]);
|
if (mesh.indices != NULL) rlEnableVertexBufferElement(mesh.vboId[6]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WARNING: Disable vertex attribute color input if mesh can not provide that data (despite location being enabled in shader)
|
||||||
|
if (mesh.vboId[3] == 0) rlDisableVertexAttribute(material.shader.locs[SHADER_LOC_VERTEX_COLOR]);
|
||||||
|
|
||||||
int eyeCount = 1;
|
int eyeCount = 1;
|
||||||
if (rlIsStereoRenderEnabled()) eyeCount = 2;
|
if (rlIsStereoRenderEnabled()) eyeCount = 2;
|
||||||
|
|
||||||
|
@ -1589,6 +1628,8 @@ void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int ins
|
||||||
|
|
||||||
// Unbind all binded texture maps
|
// Unbind all binded texture maps
|
||||||
for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
|
for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
|
||||||
|
{
|
||||||
|
if (material.maps[i].texture.id > 0)
|
||||||
{
|
{
|
||||||
// Select current shader texture slot
|
// Select current shader texture slot
|
||||||
rlActiveTextureSlot(i);
|
rlActiveTextureSlot(i);
|
||||||
|
@ -1599,6 +1640,7 @@ void DrawMeshInstanced(Mesh mesh, Material material, Matrix *transforms, int ins
|
||||||
(i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap();
|
(i == MATERIAL_MAP_CUBEMAP)) rlDisableTextureCubemap();
|
||||||
else rlDisableTexture();
|
else rlDisableTexture();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Disable all possible vertex array objects (or VBOs)
|
// Disable all possible vertex array objects (or VBOs)
|
||||||
rlDisableVertexArray();
|
rlDisableVertexArray();
|
||||||
|
@ -1620,7 +1662,7 @@ void UnloadMesh(Mesh mesh)
|
||||||
// Unload rlgl mesh vboId data
|
// Unload rlgl mesh vboId data
|
||||||
rlUnloadVertexArray(mesh.vaoId);
|
rlUnloadVertexArray(mesh.vaoId);
|
||||||
|
|
||||||
for (int i = 0; i < MAX_MESH_VERTEX_BUFFERS; i++) rlUnloadVertexBuffer(mesh.vboId[i]);
|
if (mesh.vboId != NULL) for (int i = 0; i < MAX_MESH_VERTEX_BUFFERS; i++) rlUnloadVertexBuffer(mesh.vboId[i]);
|
||||||
RL_FREE(mesh.vboId);
|
RL_FREE(mesh.vboId);
|
||||||
|
|
||||||
RL_FREE(mesh.vertices);
|
RL_FREE(mesh.vertices);
|
||||||
|
@ -1645,13 +1687,13 @@ bool ExportMesh(Mesh mesh, const char *fileName)
|
||||||
if (IsFileExtension(fileName, ".obj"))
|
if (IsFileExtension(fileName, ".obj"))
|
||||||
{
|
{
|
||||||
// Estimated data size, it should be enough...
|
// Estimated data size, it should be enough...
|
||||||
int dataSize = mesh.vertexCount/3* (int)strlen("v 0000.00f 0000.00f 0000.00f") +
|
int dataSize = mesh.vertexCount*(int)strlen("v 0000.00f 0000.00f 0000.00f") +
|
||||||
mesh.vertexCount/2* (int)strlen("vt 0.000f 0.00f") +
|
mesh.vertexCount*(int)strlen("vt 0.000f 0.00f") +
|
||||||
mesh.vertexCount/3* (int)strlen("vn 0.000f 0.00f 0.00f") +
|
mesh.vertexCount*(int)strlen("vn 0.000f 0.00f 0.00f") +
|
||||||
mesh.triangleCount/3* (int)strlen("f 00000/00000/00000 00000/00000/00000 00000/00000/00000");
|
mesh.triangleCount*(int)strlen("f 00000/00000/00000 00000/00000/00000 00000/00000/00000");
|
||||||
|
|
||||||
// NOTE: Text data buffer size is estimated considering mesh data size
|
// NOTE: Text data buffer size is estimated considering mesh data size
|
||||||
char *txtData = (char *)RL_CALLOC(dataSize + 2000, sizeof(char));
|
char *txtData = (char *)RL_CALLOC(dataSize*2 + 2000, sizeof(char));
|
||||||
|
|
||||||
int byteCount = 0;
|
int byteCount = 0;
|
||||||
byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n");
|
byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n");
|
||||||
|
@ -1661,7 +1703,7 @@ bool ExportMesh(Mesh mesh, const char *fileName)
|
||||||
byteCount += sprintf(txtData + byteCount, "# // more info and bugs-report: github.com/raysan5/raylib //\n");
|
byteCount += sprintf(txtData + byteCount, "# // more info and bugs-report: github.com/raysan5/raylib //\n");
|
||||||
byteCount += sprintf(txtData + byteCount, "# // feedback and support: ray[at]raylib.com //\n");
|
byteCount += sprintf(txtData + byteCount, "# // feedback and support: ray[at]raylib.com //\n");
|
||||||
byteCount += sprintf(txtData + byteCount, "# // //\n");
|
byteCount += sprintf(txtData + byteCount, "# // //\n");
|
||||||
byteCount += sprintf(txtData + byteCount, "# // Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n");
|
byteCount += sprintf(txtData + byteCount, "# // Copyright (c) 2018-2022 Ramon Santamaria (@raysan5) //\n");
|
||||||
byteCount += sprintf(txtData + byteCount, "# // //\n");
|
byteCount += sprintf(txtData + byteCount, "# // //\n");
|
||||||
byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n\n");
|
byteCount += sprintf(txtData + byteCount, "# //////////////////////////////////////////////////////////////////////////////////\n\n");
|
||||||
byteCount += sprintf(txtData + byteCount, "# Vertex Count: %i\n", mesh.vertexCount);
|
byteCount += sprintf(txtData + byteCount, "# Vertex Count: %i\n", mesh.vertexCount);
|
||||||
|
@ -1684,9 +1726,22 @@ bool ExportMesh(Mesh mesh, const char *fileName)
|
||||||
byteCount += sprintf(txtData + byteCount, "vn %.3f %.3f %.3f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]);
|
byteCount += sprintf(txtData + byteCount, "vn %.3f %.3f %.3f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < mesh.triangleCount; i += 3)
|
if (mesh.indices != NULL)
|
||||||
{
|
{
|
||||||
byteCount += sprintf(txtData + byteCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", i, i, i, i + 1, i + 1, i + 1, i + 2, i + 2, i + 2);
|
for (int i = 0, v = 0; i < mesh.triangleCount; i++, v += 3)
|
||||||
|
{
|
||||||
|
byteCount += sprintf(txtData + byteCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n",
|
||||||
|
mesh.indices[v] + 1, mesh.indices[v] + 1, mesh.indices[v] + 1,
|
||||||
|
mesh.indices[v + 1] + 1, mesh.indices[v + 1] + 1, mesh.indices[v + 1] + 1,
|
||||||
|
mesh.indices[v + 2] + 1, mesh.indices[v + 2] + 1, mesh.indices[v + 2] + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0, v = 1; i < mesh.triangleCount; i++, v += 3)
|
||||||
|
{
|
||||||
|
byteCount += sprintf(txtData + byteCount, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", v, v, v, v + 1, v + 1, v + 1, v + 2, v + 2, v + 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
byteCount += sprintf(txtData + byteCount, "\n");
|
byteCount += sprintf(txtData + byteCount, "\n");
|
||||||
|
@ -1704,7 +1759,6 @@ bool ExportMesh(Mesh mesh, const char *fileName)
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Load materials from model file
|
// Load materials from model file
|
||||||
Material *LoadMaterials(const char *fileName, int *materialCount)
|
Material *LoadMaterials(const char *fileName, int *materialCount)
|
||||||
{
|
{
|
||||||
|
@ -1771,10 +1825,13 @@ void UnloadMaterial(Material material)
|
||||||
if (material.shader.id != rlGetShaderIdDefault()) UnloadShader(material.shader);
|
if (material.shader.id != rlGetShaderIdDefault()) UnloadShader(material.shader);
|
||||||
|
|
||||||
// Unload loaded texture maps (avoid unloading default texture, managed by raylib)
|
// Unload loaded texture maps (avoid unloading default texture, managed by raylib)
|
||||||
|
if (material.maps != NULL)
|
||||||
|
{
|
||||||
for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
|
for (int i = 0; i < MAX_MATERIAL_MAPS; i++)
|
||||||
{
|
{
|
||||||
if (material.maps[i].texture.id != rlGetTextureIdDefault()) rlUnloadTexture(material.maps[i].texture.id);
|
if (material.maps[i].texture.id != rlGetTextureIdDefault()) rlUnloadTexture(material.maps[i].texture.id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RL_FREE(material.maps);
|
RL_FREE(material.maps);
|
||||||
}
|
}
|
||||||
|
@ -1802,6 +1859,9 @@ ModelAnimation *LoadModelAnimations(const char *fileName, unsigned int *animCoun
|
||||||
#if defined(SUPPORT_FILEFORMAT_IQM)
|
#if defined(SUPPORT_FILEFORMAT_IQM)
|
||||||
if (IsFileExtension(fileName, ".iqm")) animations = LoadModelAnimationsIQM(fileName, animCount);
|
if (IsFileExtension(fileName, ".iqm")) animations = LoadModelAnimationsIQM(fileName, animCount);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(SUPPORT_FILEFORMAT_M3D)
|
||||||
|
if (IsFileExtension(fileName, ".m3d")) animations = LoadModelAnimationsM3D(fileName, animCount);
|
||||||
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_GLTF)
|
#if defined(SUPPORT_FILEFORMAT_GLTF)
|
||||||
//if (IsFileExtension(fileName, ".gltf;.glb")) animations = LoadModelAnimationGLTF(fileName, animCount);
|
//if (IsFileExtension(fileName, ".gltf;.glb")) animations = LoadModelAnimationGLTF(fileName, animCount);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1911,7 +1971,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, int frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unload animation array data
|
// Unload animation array data
|
||||||
void UnloadModelAnimations(ModelAnimation* animations, unsigned int count)
|
void UnloadModelAnimations(ModelAnimation *animations, unsigned int count)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < count; i++) UnloadModelAnimation(animations[i]);
|
for (unsigned int i = 0; i < count; i++) UnloadModelAnimation(animations[i]);
|
||||||
RL_FREE(animations);
|
RL_FREE(animations);
|
||||||
|
@ -2249,14 +2309,14 @@ Mesh GenMeshCube(float width, float height, float length)
|
||||||
int k = 0;
|
int k = 0;
|
||||||
|
|
||||||
// Indices can be initialized right now
|
// Indices can be initialized right now
|
||||||
for (int i = 0; i < 36; i+=6)
|
for (int i = 0; i < 36; i += 6)
|
||||||
{
|
{
|
||||||
mesh.indices[i] = 4*k;
|
mesh.indices[i] = 4*k;
|
||||||
mesh.indices[i+1] = 4*k+1;
|
mesh.indices[i + 1] = 4*k + 1;
|
||||||
mesh.indices[i+2] = 4*k+2;
|
mesh.indices[i + 2] = 4*k + 2;
|
||||||
mesh.indices[i+3] = 4*k;
|
mesh.indices[i + 3] = 4*k;
|
||||||
mesh.indices[i+4] = 4*k+2;
|
mesh.indices[i + 4] = 4*k + 2;
|
||||||
mesh.indices[i+5] = 4*k+3;
|
mesh.indices[i + 5] = 4*k + 3;
|
||||||
|
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
|
@ -2412,13 +2472,13 @@ Mesh GenMeshCylinder(float radius, float height, int slices)
|
||||||
par_shapes_mesh *cylinder = par_shapes_create_cylinder(slices, 8);
|
par_shapes_mesh *cylinder = par_shapes_create_cylinder(slices, 8);
|
||||||
par_shapes_scale(cylinder, radius, radius, height);
|
par_shapes_scale(cylinder, radius, radius, height);
|
||||||
par_shapes_rotate(cylinder, -PI/2.0f, (float[]){ 1, 0, 0 });
|
par_shapes_rotate(cylinder, -PI/2.0f, (float[]){ 1, 0, 0 });
|
||||||
par_shapes_rotate(cylinder, PI/2.0f, (float[]){ 0, 1, 0 });
|
|
||||||
|
|
||||||
// Generate an orientable disk shape (top cap)
|
// Generate an orientable disk shape (top cap)
|
||||||
par_shapes_mesh *capTop = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, 1 });
|
par_shapes_mesh *capTop = par_shapes_create_disk(radius, slices, (float[]){ 0, 0, 0 }, (float[]){ 0, 0, 1 });
|
||||||
capTop->tcoords = PAR_MALLOC(float, 2*capTop->npoints);
|
capTop->tcoords = PAR_MALLOC(float, 2*capTop->npoints);
|
||||||
for (int i = 0; i < 2*capTop->npoints; i++) capTop->tcoords[i] = 0.0f;
|
for (int i = 0; i < 2*capTop->npoints; i++) capTop->tcoords[i] = 0.0f;
|
||||||
par_shapes_rotate(capTop, -PI/2.0f, (float[]){ 1, 0, 0 });
|
par_shapes_rotate(capTop, -PI/2.0f, (float[]){ 1, 0, 0 });
|
||||||
|
par_shapes_rotate(capTop, 90*DEG2RAD, (float[]){ 0, 1, 0 });
|
||||||
par_shapes_translate(capTop, 0, height, 0);
|
par_shapes_translate(capTop, 0, height, 0);
|
||||||
|
|
||||||
// Generate an orientable disk shape (bottom cap)
|
// Generate an orientable disk shape (bottom cap)
|
||||||
|
@ -2426,6 +2486,7 @@ Mesh GenMeshCylinder(float radius, float height, int slices)
|
||||||
capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints);
|
capBottom->tcoords = PAR_MALLOC(float, 2*capBottom->npoints);
|
||||||
for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f;
|
for (int i = 0; i < 2*capBottom->npoints; i++) capBottom->tcoords[i] = 0.95f;
|
||||||
par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 });
|
par_shapes_rotate(capBottom, PI/2.0f, (float[]){ 1, 0, 0 });
|
||||||
|
par_shapes_rotate(capBottom, -90*DEG2RAD, (float[]){ 0, 1, 0 });
|
||||||
|
|
||||||
par_shapes_merge_and_free(cylinder, capTop);
|
par_shapes_merge_and_free(cylinder, capTop);
|
||||||
par_shapes_merge_and_free(cylinder, capBottom);
|
par_shapes_merge_and_free(cylinder, capBottom);
|
||||||
|
@ -2610,7 +2671,7 @@ Mesh GenMeshKnot(float radius, float size, int radSeg, int sides)
|
||||||
// NOTE: Vertex data is uploaded to GPU
|
// NOTE: Vertex data is uploaded to GPU
|
||||||
Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
|
Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
|
||||||
{
|
{
|
||||||
#define GRAY_VALUE(c) ((c.r+c.g+c.b)/3)
|
#define GRAY_VALUE(c) ((c.r+c.g+c.b)/3.0f)
|
||||||
|
|
||||||
Mesh mesh = { 0 };
|
Mesh mesh = { 0 };
|
||||||
|
|
||||||
|
@ -2633,8 +2694,6 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
|
||||||
int tcCounter = 0; // Used to count texcoords float by float
|
int tcCounter = 0; // Used to count texcoords float by float
|
||||||
int nCounter = 0; // Used to count normals float by float
|
int nCounter = 0; // Used to count normals float by float
|
||||||
|
|
||||||
int trisCounter = 0;
|
|
||||||
|
|
||||||
Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ };
|
Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ };
|
||||||
|
|
||||||
Vector3 vA = { 0 };
|
Vector3 vA = { 0 };
|
||||||
|
@ -2651,15 +2710,15 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
|
||||||
|
|
||||||
// one triangle - 3 vertex
|
// one triangle - 3 vertex
|
||||||
mesh.vertices[vCounter] = (float)x*scaleFactor.x;
|
mesh.vertices[vCounter] = (float)x*scaleFactor.x;
|
||||||
mesh.vertices[vCounter + 1] = (float)GRAY_VALUE(pixels[x + z*mapX])*scaleFactor.y;
|
mesh.vertices[vCounter + 1] = GRAY_VALUE(pixels[x + z*mapX])*scaleFactor.y;
|
||||||
mesh.vertices[vCounter + 2] = (float)z*scaleFactor.z;
|
mesh.vertices[vCounter + 2] = (float)z*scaleFactor.z;
|
||||||
|
|
||||||
mesh.vertices[vCounter + 3] = (float)x*scaleFactor.x;
|
mesh.vertices[vCounter + 3] = (float)x*scaleFactor.x;
|
||||||
mesh.vertices[vCounter + 4] = (float)GRAY_VALUE(pixels[x + (z + 1)*mapX])*scaleFactor.y;
|
mesh.vertices[vCounter + 4] = GRAY_VALUE(pixels[x + (z + 1)*mapX])*scaleFactor.y;
|
||||||
mesh.vertices[vCounter + 5] = (float)(z + 1)*scaleFactor.z;
|
mesh.vertices[vCounter + 5] = (float)(z + 1)*scaleFactor.z;
|
||||||
|
|
||||||
mesh.vertices[vCounter + 6] = (float)(x + 1)*scaleFactor.x;
|
mesh.vertices[vCounter + 6] = (float)(x + 1)*scaleFactor.x;
|
||||||
mesh.vertices[vCounter + 7] = (float)GRAY_VALUE(pixels[(x + 1) + z*mapX])*scaleFactor.y;
|
mesh.vertices[vCounter + 7] = GRAY_VALUE(pixels[(x + 1) + z*mapX])*scaleFactor.y;
|
||||||
mesh.vertices[vCounter + 8] = (float)z*scaleFactor.z;
|
mesh.vertices[vCounter + 8] = (float)z*scaleFactor.z;
|
||||||
|
|
||||||
// another triangle - 3 vertex
|
// another triangle - 3 vertex
|
||||||
|
@ -2672,7 +2731,7 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
|
||||||
mesh.vertices[vCounter + 14] = mesh.vertices[vCounter + 5];
|
mesh.vertices[vCounter + 14] = mesh.vertices[vCounter + 5];
|
||||||
|
|
||||||
mesh.vertices[vCounter + 15] = (float)(x + 1)*scaleFactor.x;
|
mesh.vertices[vCounter + 15] = (float)(x + 1)*scaleFactor.x;
|
||||||
mesh.vertices[vCounter + 16] = (float)GRAY_VALUE(pixels[(x + 1) + (z + 1)*mapX])*scaleFactor.y;
|
mesh.vertices[vCounter + 16] = GRAY_VALUE(pixels[(x + 1) + (z + 1)*mapX])*scaleFactor.y;
|
||||||
mesh.vertices[vCounter + 17] = (float)(z + 1)*scaleFactor.z;
|
mesh.vertices[vCounter + 17] = (float)(z + 1)*scaleFactor.z;
|
||||||
vCounter += 18; // 6 vertex, 18 floats
|
vCounter += 18; // 6 vertex, 18 floats
|
||||||
|
|
||||||
|
@ -2729,7 +2788,6 @@ Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
|
||||||
}
|
}
|
||||||
|
|
||||||
nCounter += 18; // 6 vertex, 18 floats
|
nCounter += 18; // 6 vertex, 18 floats
|
||||||
trisCounter += 2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3223,19 +3281,6 @@ void GenMeshTangents(Mesh *mesh)
|
||||||
TRACELOG(LOG_INFO, "MESH: Tangents data computed and uploaded for provided mesh");
|
TRACELOG(LOG_INFO, "MESH: Tangents data computed and uploaded for provided mesh");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute mesh binormals (aka bitangent)
|
|
||||||
void GenMeshBinormals(Mesh *mesh)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < mesh->vertexCount; i++)
|
|
||||||
{
|
|
||||||
//Vector3 normal = { mesh->normals[i*3 + 0], mesh->normals[i*3 + 1], mesh->normals[i*3 + 2] };
|
|
||||||
//Vector3 tangent = { mesh->tangents[i*4 + 0], mesh->tangents[i*4 + 1], mesh->tangents[i*4 + 2] };
|
|
||||||
//Vector3 binormal = Vector3Scale(Vector3CrossProduct(normal, tangent), mesh->tangents[i*4 + 3]);
|
|
||||||
|
|
||||||
// TODO: Register computed binormal in mesh->binormal?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw a model (with texture if set)
|
// Draw a model (with texture if set)
|
||||||
void DrawModel(Model model, Vector3 position, float scale, Color tint)
|
void DrawModel(Model model, Vector3 position, float scale, Color tint)
|
||||||
{
|
{
|
||||||
|
@ -3264,10 +3309,10 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
|
||||||
Color color = model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color;
|
Color color = model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color;
|
||||||
|
|
||||||
Color colorTint = WHITE;
|
Color colorTint = WHITE;
|
||||||
colorTint.r = (unsigned char)((((float)color.r/255.0)*((float)tint.r/255.0))*255.0f);
|
colorTint.r = (unsigned char)((((float)color.r/255.0f)*((float)tint.r/255.0f))*255.0f);
|
||||||
colorTint.g = (unsigned char)((((float)color.g/255.0)*((float)tint.g/255.0))*255.0f);
|
colorTint.g = (unsigned char)((((float)color.g/255.0f)*((float)tint.g/255.0f))*255.0f);
|
||||||
colorTint.b = (unsigned char)((((float)color.b/255.0)*((float)tint.b/255.0))*255.0f);
|
colorTint.b = (unsigned char)((((float)color.b/255.0f)*((float)tint.b/255.0f))*255.0f);
|
||||||
colorTint.a = (unsigned char)((((float)color.a/255.0)*((float)tint.a/255.0))*255.0f);
|
colorTint.a = (unsigned char)((((float)color.a/255.0f)*((float)tint.a/255.0f))*255.0f);
|
||||||
|
|
||||||
model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = colorTint;
|
model.materials[model.meshMaterial[i]].maps[MATERIAL_MAP_DIFFUSE].color = colorTint;
|
||||||
DrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform);
|
DrawMesh(model.meshes[i], model.materials[model.meshMaterial[i]], model.transform);
|
||||||
|
@ -3315,7 +3360,7 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle source, Vector
|
||||||
void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint)
|
void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector3 position, Vector3 up, Vector2 size, Vector2 origin, float rotation, Color tint)
|
||||||
{
|
{
|
||||||
// NOTE: Billboard size will maintain source rectangle aspect ratio, size will represent billboard width
|
// NOTE: Billboard size will maintain source rectangle aspect ratio, size will represent billboard width
|
||||||
Vector2 sizeRatio = { size.y, size.x*(float)source.height/source.width };
|
Vector2 sizeRatio = { size.x*(float)source.width/source.height, size.y };
|
||||||
|
|
||||||
Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
|
Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up);
|
||||||
|
|
||||||
|
@ -3376,7 +3421,7 @@ void DrawBillboardPro(Camera camera, Texture2D texture, Rectangle source, Vector
|
||||||
bottomRight = Vector3Add(bottomRight, position);
|
bottomRight = Vector3Add(bottomRight, position);
|
||||||
bottomLeft = Vector3Add(bottomLeft, position);
|
bottomLeft = Vector3Add(bottomLeft, position);
|
||||||
|
|
||||||
rlCheckRenderBatchLimit(4);
|
rlCheckRenderBatchLimit(8);
|
||||||
|
|
||||||
rlSetTexture(texture.id);
|
rlSetTexture(texture.id);
|
||||||
|
|
||||||
|
@ -3620,31 +3665,12 @@ RayCollision GetRayCollisionMesh(Ray ray, Mesh mesh, Matrix transform)
|
||||||
return collision;
|
return collision;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get collision info between ray and model
|
|
||||||
RayCollision GetRayCollisionModel(Ray ray, Model model)
|
|
||||||
{
|
|
||||||
RayCollision collision = { 0 };
|
|
||||||
|
|
||||||
for (int m = 0; m < model.meshCount; m++)
|
|
||||||
{
|
|
||||||
RayCollision meshHitInfo = GetRayCollisionMesh(ray, model.meshes[m], model.transform);
|
|
||||||
|
|
||||||
if (meshHitInfo.hit)
|
|
||||||
{
|
|
||||||
// Save the closest hit mesh
|
|
||||||
if ((!collision.hit) || (collision.distance > meshHitInfo.distance)) collision = meshHitInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return collision;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get collision info between ray and triangle
|
// Get collision info between ray and triangle
|
||||||
// NOTE: The points are expected to be in counter-clockwise winding
|
// NOTE: The points are expected to be in counter-clockwise winding
|
||||||
// NOTE: Based on https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
|
// NOTE: Based on https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
|
||||||
RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3)
|
RayCollision GetRayCollisionTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3)
|
||||||
{
|
{
|
||||||
#define EPSILON 0.000001 // A small number
|
#define EPSILON 0.000001f // A small number
|
||||||
|
|
||||||
RayCollision collision = { 0 };
|
RayCollision collision = { 0 };
|
||||||
Vector3 edge1 = { 0 };
|
Vector3 edge1 = { 0 };
|
||||||
|
@ -4281,7 +4307,7 @@ static Model LoadIQM(const char *fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load IQM animation data
|
// Load IQM animation data
|
||||||
static ModelAnimation* LoadModelAnimationsIQM(const char *fileName, unsigned int *animCount)
|
static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, unsigned int *animCount)
|
||||||
{
|
{
|
||||||
#define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number
|
#define IQM_MAGIC "INTERQUAKEMODEL" // IQM file magic number
|
||||||
#define IQM_VERSION 2 // only IQM version 2 supported
|
#define IQM_VERSION 2 // only IQM version 2 supported
|
||||||
|
@ -4642,7 +4668,6 @@ static Model LoadGLTF(const char *fileName)
|
||||||
// Load our model data: meshes and materials
|
// Load our model data: meshes and materials
|
||||||
model.meshCount = primitivesCount;
|
model.meshCount = primitivesCount;
|
||||||
model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
|
model.meshes = RL_CALLOC(model.meshCount, sizeof(Mesh));
|
||||||
for (int i = 0; i < model.meshCount; i++) model.meshes[i].vboId = (unsigned int*)RL_CALLOC(MAX_MESH_VERTEX_BUFFERS, sizeof(unsigned int));
|
|
||||||
|
|
||||||
// NOTE: We keep an extra slot for default material, in case some mesh requires it
|
// NOTE: We keep an extra slot for default material, in case some mesh requires it
|
||||||
model.materialCount = (int)data->materials_count + 1;
|
model.materialCount = (int)data->materials_count + 1;
|
||||||
|
@ -4672,13 +4697,12 @@ static Model LoadGLTF(const char *fileName)
|
||||||
model.materials[j].maps[MATERIAL_MAP_ALBEDO].texture = LoadTextureFromImage(imAlbedo);
|
model.materials[j].maps[MATERIAL_MAP_ALBEDO].texture = LoadTextureFromImage(imAlbedo);
|
||||||
UnloadImage(imAlbedo);
|
UnloadImage(imAlbedo);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Load base color factor (tint)
|
// Load base color factor (tint)
|
||||||
model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255);
|
model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.r = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[0]*255);
|
||||||
model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255);
|
model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.g = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[1]*255);
|
||||||
model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255);
|
model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.b = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[2]*255);
|
||||||
model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255);
|
model.materials[j].maps[MATERIAL_MAP_ALBEDO].color.a = (unsigned char)(data->materials[i].pbr_metallic_roughness.base_color_factor[3]*255);
|
||||||
}
|
|
||||||
|
|
||||||
// Load metallic/roughness texture
|
// Load metallic/roughness texture
|
||||||
if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture)
|
if (data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.texture)
|
||||||
|
@ -4845,7 +4869,7 @@ static Model LoadGLTF(const char *fileName)
|
||||||
LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
|
LOAD_ATTRIBUTE(attribute, 4, unsigned short, temp);
|
||||||
|
|
||||||
// Convert data to raylib color data type (4 bytes)
|
// Convert data to raylib color data type (4 bytes)
|
||||||
for (int c = 0; c < attribute->count*4; c++) model.meshes[meshIndex].colors[c] = (unsigned char)(((float)temp[c]/65535.0f)*255.0f);
|
for (unsigned int c = 0; c < attribute->count*4; c++) model.meshes[meshIndex].colors[c] = (unsigned char)(((float)temp[c]/65535.0f)*255.0f);
|
||||||
|
|
||||||
RL_FREE(temp);
|
RL_FREE(temp);
|
||||||
}
|
}
|
||||||
|
@ -4859,7 +4883,7 @@ static Model LoadGLTF(const char *fileName)
|
||||||
LOAD_ATTRIBUTE(attribute, 4, float, temp);
|
LOAD_ATTRIBUTE(attribute, 4, float, temp);
|
||||||
|
|
||||||
// Convert data to raylib color data type (4 bytes), we expect the color data normalized
|
// Convert data to raylib color data type (4 bytes), we expect the color data normalized
|
||||||
for (int c = 0; c < attribute->count*4; c++) model.meshes[meshIndex].colors[c] = (unsigned char)(temp[c]*255.0f);
|
for (unsigned int c = 0; c < attribute->count*4; c++) model.meshes[meshIndex].colors[c] = (unsigned char)(temp[c]*255.0f);
|
||||||
|
|
||||||
RL_FREE(temp);
|
RL_FREE(temp);
|
||||||
}
|
}
|
||||||
|
@ -4894,7 +4918,7 @@ static Model LoadGLTF(const char *fileName)
|
||||||
LOAD_ATTRIBUTE(attribute, 1, unsigned int, temp);
|
LOAD_ATTRIBUTE(attribute, 1, unsigned int, temp);
|
||||||
|
|
||||||
// Convert data to raylib indices data type (unsigned short)
|
// Convert data to raylib indices data type (unsigned short)
|
||||||
for (int d = 0; d < attribute->count; d++) model.meshes[meshIndex].indices[d] = (unsigned short)temp[d];
|
for (unsigned int d = 0; d < attribute->count; d++) model.meshes[meshIndex].indices[d] = (unsigned short)temp[d];
|
||||||
|
|
||||||
TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data converted from u32 to u16, possible loss of data", fileName);
|
TRACELOG(LOG_WARNING, "MODEL: [%s] Indices data converted from u32 to u16, possible loss of data", fileName);
|
||||||
|
|
||||||
|
@ -4906,7 +4930,7 @@ static Model LoadGLTF(const char *fileName)
|
||||||
|
|
||||||
// Assign to the primitive mesh the corresponding material index
|
// Assign to the primitive mesh the corresponding material index
|
||||||
// NOTE: If no material defined, mesh uses the already assigned default material (index: 0)
|
// NOTE: If no material defined, mesh uses the already assigned default material (index: 0)
|
||||||
for (int m = 0; m < data->materials_count; m++)
|
for (unsigned int m = 0; m < data->materials_count; m++)
|
||||||
{
|
{
|
||||||
// The primitive actually keeps the pointer to the corresponding material,
|
// The primitive actually keeps the pointer to the corresponding material,
|
||||||
// raylib instead assigns to the mesh the by its index, as loaded in model.materials array
|
// raylib instead assigns to the mesh the by its index, as loaded in model.materials array
|
||||||
|
@ -4923,6 +4947,63 @@ static Model LoadGLTF(const char *fileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TODO: Load glTF meshes animation data
|
||||||
|
// REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skins
|
||||||
|
// REF: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#skinned-mesh-attributes
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
for (unsigned int i = 0, meshIndex = 0; i < data->meshes_count; i++)
|
||||||
|
{
|
||||||
|
for (unsigned int p = 0; p < data->meshes[i].primitives_count; p++)
|
||||||
|
{
|
||||||
|
// NOTE: We only support primitives defined by triangles
|
||||||
|
if (data->meshes[i].primitives[p].type != cgltf_primitive_type_triangles) continue;
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < data->meshes[i].primitives[p].attributes_count; j++)
|
||||||
|
{
|
||||||
|
// NOTE: JOINTS_1 + WEIGHT_1 will be used for +4 joints influencing a vertex -> Not supported by raylib
|
||||||
|
|
||||||
|
if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_joints) // JOINTS_n (vec4: 4 bones max per vertex / u8, u16)
|
||||||
|
{
|
||||||
|
cgltf_accessor *attribute = data->meshes[i].primitives[p].attributes[j].data;
|
||||||
|
|
||||||
|
if ((attribute->component_type == cgltf_component_type_r_8u) && (attribute->type == cgltf_type_vec4))
|
||||||
|
{
|
||||||
|
// Init raylib mesh bone ids to copy glTF attribute data
|
||||||
|
model.meshes[meshIndex].boneIds = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(unsigned char));
|
||||||
|
|
||||||
|
// Load 4 components of unsigned char data type into mesh.boneIds
|
||||||
|
// TODO: It seems LOAD_ATTRIBUTE() macro does not work as expected in some cases,
|
||||||
|
// for cgltf_attribute_type_joints we have:
|
||||||
|
// - data.meshes[0] (256 vertices)
|
||||||
|
// - 256 values, provided as cgltf_type_vec4 of bytes (4 byte per joint, stride 4)
|
||||||
|
LOAD_ATTRIBUTE(attribute, 4, unsigned char, model.meshes[meshIndex].boneIds)
|
||||||
|
}
|
||||||
|
else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint attribute data format not supported, use vec4 u8", fileName);
|
||||||
|
}
|
||||||
|
else if (data->meshes[i].primitives[p].attributes[j].type == cgltf_attribute_type_weights) // WEIGHTS_n (vec4 / u8, u16, f32)
|
||||||
|
{
|
||||||
|
cgltf_accessor *attribute = data->meshes[i].primitives[p].attributes[j].data;
|
||||||
|
|
||||||
|
if ((attribute->component_type == cgltf_component_type_r_32f) && (attribute->type == cgltf_type_vec4))
|
||||||
|
{
|
||||||
|
// Init raylib mesh bone weight to copy glTF attribute data
|
||||||
|
model.meshes[meshIndex].boneWeights = RL_CALLOC(model.meshes[meshIndex].vertexCount*4, sizeof(float));
|
||||||
|
|
||||||
|
// Load 4 components of float data type into mesh.boneWeights
|
||||||
|
// for cgltf_attribute_type_weights we have:
|
||||||
|
// - data.meshes[0] (256 vertices)
|
||||||
|
// - 256 values, provided as cgltf_type_vec4 of float (4 byte per joint, stride 16)
|
||||||
|
LOAD_ATTRIBUTE(attribute, 4, float, model.meshes[meshIndex].boneWeights)
|
||||||
|
}
|
||||||
|
else TRACELOG(LOG_WARNING, "MODEL: [%s] Joint weight attribute data format not supported, use vec4 float", fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
meshIndex++; // Move to next mesh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
// Free all cgltf loaded data
|
// Free all cgltf loaded data
|
||||||
cgltf_free(data);
|
cgltf_free(data);
|
||||||
}
|
}
|
||||||
|
@ -5039,3 +5120,360 @@ static Model LoadVOX(const char *fileName)
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(SUPPORT_FILEFORMAT_M3D)
|
||||||
|
// Hook LoadFileData()/UnloadFileData() calls to M3D loaders
|
||||||
|
unsigned char *m3d_loaderhook(char *fn, unsigned int *len) { return LoadFileData((const char *)fn, len); }
|
||||||
|
void m3d_freehook(void *data) { UnloadFileData((unsigned char *)data); }
|
||||||
|
|
||||||
|
// Load M3D mesh data
|
||||||
|
static Model LoadM3D(const char *fileName)
|
||||||
|
{
|
||||||
|
Model model = { 0 };
|
||||||
|
|
||||||
|
m3d_t *m3d = NULL;
|
||||||
|
m3dp_t *prop = NULL;
|
||||||
|
unsigned int bytesRead = 0;
|
||||||
|
unsigned char *fileData = LoadFileData(fileName, &bytesRead);
|
||||||
|
int i, j, k, l, n, mi = -2;
|
||||||
|
|
||||||
|
if (fileData != NULL)
|
||||||
|
{
|
||||||
|
m3d = m3d_load(fileData, m3d_loaderhook, m3d_freehook, NULL);
|
||||||
|
|
||||||
|
if (!m3d || M3D_ERR_ISFATAL(m3d->errcode))
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load M3D data, error code %d", fileName, m3d ? m3d->errcode : -2);
|
||||||
|
if (m3d) m3d_free(m3d);
|
||||||
|
UnloadFileData(fileData);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
else TRACELOG(LOG_INFO, "MODEL: [%s] M3D data loaded successfully: %i faces/%i materials", fileName, m3d->numface, m3d->nummaterial);
|
||||||
|
|
||||||
|
// no face? this is probably just a material library
|
||||||
|
if (!m3d->numface)
|
||||||
|
{
|
||||||
|
m3d_free(m3d);
|
||||||
|
UnloadFileData(fileData);
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m3d->nummaterial > 0)
|
||||||
|
{
|
||||||
|
model.meshCount = model.materialCount = m3d->nummaterial;
|
||||||
|
TRACELOG(LOG_INFO, "MODEL: model has %i material meshes", model.materialCount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
model.meshCount = model.materialCount = 1;
|
||||||
|
TRACELOG(LOG_INFO, "MODEL: No materials, putting all meshes in a default material");
|
||||||
|
}
|
||||||
|
|
||||||
|
model.meshes = (Mesh *)RL_CALLOC(model.meshCount, sizeof(Mesh));
|
||||||
|
model.meshMaterial = (int *)RL_CALLOC(model.meshCount, sizeof(int));
|
||||||
|
model.materials = (Material *)RL_CALLOC(model.materialCount + 1, sizeof(Material));
|
||||||
|
|
||||||
|
// Map no material to index 0 with default shader, everything else materialid + 1
|
||||||
|
model.materials[0] = LoadMaterialDefault();
|
||||||
|
|
||||||
|
for (i = l = 0, k = -1; i < m3d->numface; i++, l++)
|
||||||
|
{
|
||||||
|
// Materials are grouped together
|
||||||
|
if (mi != m3d->face[i].materialid)
|
||||||
|
{
|
||||||
|
// there should be only one material switch per material kind, but be bulletproof for unoptimal model files
|
||||||
|
if (k + 1 >= model.meshCount)
|
||||||
|
{
|
||||||
|
model.meshCount++;
|
||||||
|
model.meshes = (Mesh *)RL_REALLOC(model.meshes, model.meshCount*sizeof(Mesh));
|
||||||
|
memset(&model.meshes[model.meshCount - 1], 0, sizeof(Mesh));
|
||||||
|
model.meshMaterial = (int *)RL_REALLOC(model.meshMaterial, model.meshCount*sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
k++;
|
||||||
|
mi = m3d->face[i].materialid;
|
||||||
|
|
||||||
|
for (j = i, l = 0; (j < m3d->numface) && (mi == m3d->face[j].materialid); j++, l++);
|
||||||
|
|
||||||
|
model.meshes[k].vertexCount = l*3;
|
||||||
|
model.meshes[k].triangleCount = l;
|
||||||
|
model.meshes[k].vertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
|
||||||
|
model.meshes[k].texcoords = (float *)RL_CALLOC(model.meshes[k].vertexCount*2, sizeof(float));
|
||||||
|
model.meshes[k].normals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
|
||||||
|
// without material, we rely on vertex colors
|
||||||
|
if (mi == M3D_UNDEF && model.meshes[k].colors == NULL)
|
||||||
|
{
|
||||||
|
model.meshes[k].colors = RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
|
||||||
|
for (j = 0; j < model.meshes[k].vertexCount*4; j += 4) memcpy(&model.meshes[k].colors[j], &WHITE, 4);
|
||||||
|
}
|
||||||
|
if (m3d->numbone && m3d->numskin)
|
||||||
|
{
|
||||||
|
model.meshes[k].boneIds = (unsigned char *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(unsigned char));
|
||||||
|
model.meshes[k].boneWeights = (float *)RL_CALLOC(model.meshes[k].vertexCount*4, sizeof(float));
|
||||||
|
model.meshes[k].animVertices = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
|
||||||
|
model.meshes[k].animNormals = (float *)RL_CALLOC(model.meshes[k].vertexCount*3, sizeof(float));
|
||||||
|
}
|
||||||
|
model.meshMaterial[k] = mi + 1;
|
||||||
|
l = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process meshes per material, add triangles
|
||||||
|
model.meshes[k].vertices[l * 9 + 0] = m3d->vertex[m3d->face[i].vertex[0]].x*m3d->scale;
|
||||||
|
model.meshes[k].vertices[l * 9 + 1] = m3d->vertex[m3d->face[i].vertex[0]].y*m3d->scale;
|
||||||
|
model.meshes[k].vertices[l * 9 + 2] = m3d->vertex[m3d->face[i].vertex[0]].z*m3d->scale;
|
||||||
|
model.meshes[k].vertices[l * 9 + 3] = m3d->vertex[m3d->face[i].vertex[1]].x*m3d->scale;
|
||||||
|
model.meshes[k].vertices[l * 9 + 4] = m3d->vertex[m3d->face[i].vertex[1]].y*m3d->scale;
|
||||||
|
model.meshes[k].vertices[l * 9 + 5] = m3d->vertex[m3d->face[i].vertex[1]].z*m3d->scale;
|
||||||
|
model.meshes[k].vertices[l * 9 + 6] = m3d->vertex[m3d->face[i].vertex[2]].x*m3d->scale;
|
||||||
|
model.meshes[k].vertices[l * 9 + 7] = m3d->vertex[m3d->face[i].vertex[2]].y*m3d->scale;
|
||||||
|
model.meshes[k].vertices[l * 9 + 8] = m3d->vertex[m3d->face[i].vertex[2]].z*m3d->scale;
|
||||||
|
|
||||||
|
if (mi == M3D_UNDEF)
|
||||||
|
{
|
||||||
|
// without vertex color (full transparency), we use the default color
|
||||||
|
if (m3d->vertex[m3d->face[i].vertex[0]].color & 0xFF000000)
|
||||||
|
memcpy(&model.meshes[k].colors[l * 12 + 0], &m3d->vertex[m3d->face[i].vertex[0]].color, 4);
|
||||||
|
if (m3d->vertex[m3d->face[i].vertex[1]].color & 0xFF000000)
|
||||||
|
memcpy(&model.meshes[k].colors[l * 12 + 4], &m3d->vertex[m3d->face[i].vertex[1]].color, 4);
|
||||||
|
if (m3d->vertex[m3d->face[i].vertex[2]].color & 0xFF000000)
|
||||||
|
memcpy(&model.meshes[k].colors[l * 12 + 8], &m3d->vertex[m3d->face[i].vertex[2]].color, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m3d->face[i].texcoord[0] != M3D_UNDEF)
|
||||||
|
{
|
||||||
|
model.meshes[k].texcoords[l * 6 + 0] = m3d->tmap[m3d->face[i].texcoord[0]].u;
|
||||||
|
model.meshes[k].texcoords[l * 6 + 1] = 1.0 - m3d->tmap[m3d->face[i].texcoord[0]].v;
|
||||||
|
model.meshes[k].texcoords[l * 6 + 2] = m3d->tmap[m3d->face[i].texcoord[1]].u;
|
||||||
|
model.meshes[k].texcoords[l * 6 + 3] = 1.0 - m3d->tmap[m3d->face[i].texcoord[1]].v;
|
||||||
|
model.meshes[k].texcoords[l * 6 + 4] = m3d->tmap[m3d->face[i].texcoord[2]].u;
|
||||||
|
model.meshes[k].texcoords[l * 6 + 5] = 1.0 - m3d->tmap[m3d->face[i].texcoord[2]].v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m3d->face[i].normal[0] != M3D_UNDEF)
|
||||||
|
{
|
||||||
|
model.meshes[k].normals[l * 9 + 0] = m3d->vertex[m3d->face[i].normal[0]].x;
|
||||||
|
model.meshes[k].normals[l * 9 + 1] = m3d->vertex[m3d->face[i].normal[0]].y;
|
||||||
|
model.meshes[k].normals[l * 9 + 2] = m3d->vertex[m3d->face[i].normal[0]].z;
|
||||||
|
model.meshes[k].normals[l * 9 + 3] = m3d->vertex[m3d->face[i].normal[1]].x;
|
||||||
|
model.meshes[k].normals[l * 9 + 4] = m3d->vertex[m3d->face[i].normal[1]].y;
|
||||||
|
model.meshes[k].normals[l * 9 + 5] = m3d->vertex[m3d->face[i].normal[1]].z;
|
||||||
|
model.meshes[k].normals[l * 9 + 6] = m3d->vertex[m3d->face[i].normal[2]].x;
|
||||||
|
model.meshes[k].normals[l * 9 + 7] = m3d->vertex[m3d->face[i].normal[2]].y;
|
||||||
|
model.meshes[k].normals[l * 9 + 8] = m3d->vertex[m3d->face[i].normal[2]].z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add skin (vertex / bone weight pairs)
|
||||||
|
if (m3d->numbone && m3d->numskin) {
|
||||||
|
for (n = 0; n < 3; n++) {
|
||||||
|
int skinid = m3d->vertex[m3d->face[i].vertex[n]].skinid;
|
||||||
|
// check if there's a skin for this mesh, should be, just failsafe
|
||||||
|
if (skinid != M3D_UNDEF && skinid < m3d->numskin)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
model.meshes[k].boneIds[l * 12 + n * 4 + j] = m3d->skin[skinid].boneid[j];
|
||||||
|
model.meshes[k].boneWeights[l * 12 + n * 4 + j] = m3d->skin[skinid].weight[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load materials
|
||||||
|
for (i = 0; i < m3d->nummaterial; i++)
|
||||||
|
{
|
||||||
|
model.materials[i + 1] = LoadMaterialDefault();
|
||||||
|
|
||||||
|
for (j = 0; j < m3d->material[i].numprop; j++)
|
||||||
|
{
|
||||||
|
prop = &m3d->material[i].prop[j];
|
||||||
|
|
||||||
|
switch (prop->type)
|
||||||
|
{
|
||||||
|
case m3dp_Kd:
|
||||||
|
{
|
||||||
|
memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].color, &prop->value.color, 4);
|
||||||
|
model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].value = 0.0f;
|
||||||
|
} break;
|
||||||
|
case m3dp_Ks:
|
||||||
|
{
|
||||||
|
memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].color, &prop->value.color, 4);
|
||||||
|
} break;
|
||||||
|
case m3dp_Ns:
|
||||||
|
{
|
||||||
|
model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].value = prop->value.fnum;
|
||||||
|
} break;
|
||||||
|
case m3dp_Ke:
|
||||||
|
{
|
||||||
|
memcpy(&model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].color, &prop->value.color, 4);
|
||||||
|
model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].value = 0.0f;
|
||||||
|
} break;
|
||||||
|
case m3dp_Pm:
|
||||||
|
{
|
||||||
|
model.materials[i + 1].maps[MATERIAL_MAP_METALNESS].value = prop->value.fnum;
|
||||||
|
} break;
|
||||||
|
case m3dp_Pr:
|
||||||
|
{
|
||||||
|
model.materials[i + 1].maps[MATERIAL_MAP_ROUGHNESS].value = prop->value.fnum;
|
||||||
|
} break;
|
||||||
|
case m3dp_Ps:
|
||||||
|
{
|
||||||
|
model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].color = WHITE;
|
||||||
|
model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].value = prop->value.fnum;
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
if (prop->type >= 128)
|
||||||
|
{
|
||||||
|
Image image = { 0 };
|
||||||
|
image.data = m3d->texture[prop->value.textureid].d;
|
||||||
|
image.width = m3d->texture[prop->value.textureid].w;
|
||||||
|
image.height = m3d->texture[prop->value.textureid].h;
|
||||||
|
image.mipmaps = 1;
|
||||||
|
image.format = (m3d->texture[prop->value.textureid].f == 4)? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 :
|
||||||
|
((m3d->texture[prop->value.textureid].f == 3)? PIXELFORMAT_UNCOMPRESSED_R8G8B8 :
|
||||||
|
((m3d->texture[prop->value.textureid].f == 2)? PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA : PIXELFORMAT_UNCOMPRESSED_GRAYSCALE));
|
||||||
|
|
||||||
|
switch (prop->type)
|
||||||
|
{
|
||||||
|
case m3dp_map_Kd: model.materials[i + 1].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTextureFromImage(image); break;
|
||||||
|
case m3dp_map_Ks: model.materials[i + 1].maps[MATERIAL_MAP_SPECULAR].texture = LoadTextureFromImage(image); break;
|
||||||
|
case m3dp_map_Ke: model.materials[i + 1].maps[MATERIAL_MAP_EMISSION].texture = LoadTextureFromImage(image); break;
|
||||||
|
case m3dp_map_Km: model.materials[i + 1].maps[MATERIAL_MAP_NORMAL].texture = LoadTextureFromImage(image); break;
|
||||||
|
case m3dp_map_Ka: model.materials[i + 1].maps[MATERIAL_MAP_OCCLUSION].texture = LoadTextureFromImage(image); break;
|
||||||
|
case m3dp_map_Pm: model.materials[i + 1].maps[MATERIAL_MAP_ROUGHNESS].texture = LoadTextureFromImage(image); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load bones
|
||||||
|
if(m3d->numbone)
|
||||||
|
{
|
||||||
|
model.boneCount = m3d->numbone;
|
||||||
|
model.bones = RL_MALLOC(m3d->numbone*sizeof(BoneInfo));
|
||||||
|
model.bindPose = RL_MALLOC(m3d->numbone*sizeof(Transform));
|
||||||
|
for (i = 0; i < m3d->numbone; i++)
|
||||||
|
{
|
||||||
|
model.bones[i].parent = m3d->bone[i].parent;
|
||||||
|
strncpy(model.bones[i].name, m3d->bone[i].name, sizeof(model.bones[i].name));
|
||||||
|
model.bindPose[i].translation.x = m3d->vertex[m3d->bone[i].pos].x;
|
||||||
|
model.bindPose[i].translation.y = m3d->vertex[m3d->bone[i].pos].y;
|
||||||
|
model.bindPose[i].translation.z = m3d->vertex[m3d->bone[i].pos].z;
|
||||||
|
model.bindPose[i].rotation.x = m3d->vertex[m3d->bone[i].ori].x;
|
||||||
|
model.bindPose[i].rotation.y = m3d->vertex[m3d->bone[i].ori].y;
|
||||||
|
model.bindPose[i].rotation.z = m3d->vertex[m3d->bone[i].ori].z;
|
||||||
|
model.bindPose[i].rotation.w = m3d->vertex[m3d->bone[i].ori].w;
|
||||||
|
// TODO: if the orientation quaternion not normalized, then that's encoding scaling
|
||||||
|
model.bindPose[i].rotation = QuaternionNormalize(model.bindPose[i].rotation);
|
||||||
|
model.bindPose[i].scale.x = model.bindPose[i].scale.y = model.bindPose[i].scale.z = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load bone-pose default mesh into animation vertices. These will be updated when UpdateModelAnimation gets
|
||||||
|
// called, but not before, however DrawMesh uses these if they exists (so not good if they are left empty).
|
||||||
|
if (m3d->numbone && m3d->numskin)
|
||||||
|
{
|
||||||
|
for(i = 0; i < model.meshCount; i++)
|
||||||
|
{
|
||||||
|
memcpy(model.meshes[i].animVertices, model.meshes[i].vertices, model.meshes[i].vertexCount*3*sizeof(float));
|
||||||
|
memcpy(model.meshes[i].animNormals, model.meshes[i].normals, model.meshes[i].vertexCount*3*sizeof(float));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m3d_free(m3d);
|
||||||
|
UnloadFileData(fileData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load M3D animation data
|
||||||
|
#define M3D_ANIMDELAY 17 // that's roughly ~1000 msec / 60 FPS (16.666666* msec)
|
||||||
|
static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, unsigned int *animCount)
|
||||||
|
{
|
||||||
|
m3d_t *m3d = NULL;
|
||||||
|
unsigned int bytesRead = 0;
|
||||||
|
unsigned char *fileData = LoadFileData(fileName, &bytesRead);
|
||||||
|
ModelAnimation *animations = NULL;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
*animCount = 0;
|
||||||
|
|
||||||
|
if (fileData != NULL)
|
||||||
|
{
|
||||||
|
m3d = m3d_load(fileData, m3d_loaderhook, m3d_freehook, NULL);
|
||||||
|
|
||||||
|
if (!m3d || M3D_ERR_ISFATAL(m3d->errcode))
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load M3D data, error code %d", fileName, m3d ? m3d->errcode : -2);
|
||||||
|
UnloadFileData(fileData);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else TRACELOG(LOG_INFO, "MODEL: [%s] M3D data loaded successfully: %i animations, %i bones, %i skins", fileName,
|
||||||
|
m3d->numaction, m3d->numbone, m3d->numskin);
|
||||||
|
|
||||||
|
// no animation or bone+skin?
|
||||||
|
if (!m3d->numaction || !m3d->numbone || !m3d->numskin)
|
||||||
|
{
|
||||||
|
m3d_free(m3d);
|
||||||
|
UnloadFileData(fileData);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
animations = RL_MALLOC(m3d->numaction*sizeof(ModelAnimation));
|
||||||
|
*animCount = m3d->numaction;
|
||||||
|
|
||||||
|
for (unsigned int a = 0; a < m3d->numaction; a++)
|
||||||
|
{
|
||||||
|
animations[a].frameCount = m3d->action[a].durationmsec / M3D_ANIMDELAY;
|
||||||
|
animations[a].boneCount = m3d->numbone;
|
||||||
|
animations[a].bones = RL_MALLOC(m3d->numbone*sizeof(BoneInfo));
|
||||||
|
animations[a].framePoses = RL_MALLOC(animations[a].frameCount*sizeof(Transform *));
|
||||||
|
// strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name));
|
||||||
|
TRACELOG(LOG_INFO, "MODEL: [%s] animation #%i: %i msec, %i frames", fileName, a, m3d->action[a].durationmsec, animations[a].frameCount);
|
||||||
|
|
||||||
|
for (i = 0; i < m3d->numbone; i++)
|
||||||
|
{
|
||||||
|
animations[a].bones[i].parent = m3d->bone[i].parent;
|
||||||
|
strncpy(animations[a].bones[i].name, m3d->bone[i].name, sizeof(animations[a].bones[i].name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// M3D stores frames at arbitrary intervals with sparse skeletons. We need full skeletons at
|
||||||
|
// regular intervals, so let the M3D SDK do the heavy lifting and calculate interpolated bones
|
||||||
|
for (i = 0; i < animations[a].frameCount; i++)
|
||||||
|
{
|
||||||
|
animations[a].framePoses[i] = RL_MALLOC(m3d->numbone*sizeof(Transform));
|
||||||
|
|
||||||
|
m3db_t *pose = m3d_pose(m3d, a, i * M3D_ANIMDELAY);
|
||||||
|
if (pose != NULL)
|
||||||
|
{
|
||||||
|
for (j = 0; j < m3d->numbone; j++)
|
||||||
|
{
|
||||||
|
animations[a].framePoses[i][j].translation.x = m3d->vertex[pose[j].pos].x;
|
||||||
|
animations[a].framePoses[i][j].translation.y = m3d->vertex[pose[j].pos].y;
|
||||||
|
animations[a].framePoses[i][j].translation.z = m3d->vertex[pose[j].pos].z;
|
||||||
|
animations[a].framePoses[i][j].rotation.x = m3d->vertex[pose[j].ori].x;
|
||||||
|
animations[a].framePoses[i][j].rotation.y = m3d->vertex[pose[j].ori].y;
|
||||||
|
animations[a].framePoses[i][j].rotation.z = m3d->vertex[pose[j].ori].z;
|
||||||
|
animations[a].framePoses[i][j].rotation.w = m3d->vertex[pose[j].ori].w;
|
||||||
|
animations[a].framePoses[i][j].rotation = QuaternionNormalize(animations[a].framePoses[i][j].rotation);
|
||||||
|
animations[a].framePoses[i][j].scale.x = animations[a].framePoses[i][j].scale.y = animations[a].framePoses[i][j].scale.z = 1.0f;
|
||||||
|
}
|
||||||
|
RL_FREE(pose);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m3d_free(m3d);
|
||||||
|
UnloadFileData(fileData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return animations;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // SUPPORT_MODULE_RMODELS
|
||||||
|
|
|
@ -17,13 +17,16 @@
|
||||||
*
|
*
|
||||||
* CONFIGURATION:
|
* CONFIGURATION:
|
||||||
*
|
*
|
||||||
|
* #define SUPPORT_MODULE_RSHAPES
|
||||||
|
* rshapes module is included in the build
|
||||||
|
*
|
||||||
* #define SUPPORT_QUADS_DRAW_MODE
|
* #define SUPPORT_QUADS_DRAW_MODE
|
||||||
* Use QUADS instead of TRIANGLES for drawing when possible. Lines-based shapes still use LINES
|
* Use QUADS instead of TRIANGLES for drawing when possible. Lines-based shapes still use LINES
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* LICENSE: zlib/libpng
|
* LICENSE: zlib/libpng
|
||||||
*
|
*
|
||||||
* Copyright (c) 2013-2021 Ramon Santamaria (@raysan5)
|
* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5)
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
* 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.
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -49,6 +52,8 @@
|
||||||
#include "config.h" // Defines module configuration flags
|
#include "config.h" // Defines module configuration flags
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(SUPPORT_MODULE_RSHAPES)
|
||||||
|
|
||||||
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
|
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
|
||||||
|
|
||||||
#include <math.h> // Required for: sinf(), asinf(), cosf(), acosf(), sqrtf(), fabsf()
|
#include <math.h> // Required for: sinf(), asinf(), cosf(), acosf(), sqrtf(), fabsf()
|
||||||
|
@ -76,7 +81,7 @@
|
||||||
// Global Variables Definition
|
// Global Variables Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
Texture2D texShapes = { 1, 1, 1, 1, 7 }; // Texture used on shapes drawing (usually a white pixel)
|
Texture2D texShapes = { 1, 1, 1, 1, 7 }; // Texture used on shapes drawing (usually a white pixel)
|
||||||
Rectangle texShapesRec = { 0, 0, 1, 1 }; // Texture source rectangle used on shapes drawing
|
Rectangle texShapesRec = { 0.0f, 0.0f, 1.0f, 1.0f }; // Texture source rectangle used on shapes drawing
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module specific Functions Declaration
|
// Module specific Functions Declaration
|
||||||
|
@ -780,7 +785,6 @@ void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3,
|
||||||
|
|
||||||
rlSetTexture(texShapes.id);
|
rlSetTexture(texShapes.id);
|
||||||
|
|
||||||
rlPushMatrix();
|
|
||||||
rlBegin(RL_QUADS);
|
rlBegin(RL_QUADS);
|
||||||
rlNormal3f(0.0f, 0.0f, 1.0f);
|
rlNormal3f(0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
@ -801,7 +805,6 @@ void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3,
|
||||||
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
|
rlTexCoord2f((texShapesRec.x + texShapesRec.width)/texShapes.width, texShapesRec.y/texShapes.height);
|
||||||
rlVertex2f(rec.x + rec.width, rec.y);
|
rlVertex2f(rec.x + rec.width, rec.y);
|
||||||
rlEnd();
|
rlEnd();
|
||||||
rlPopMatrix();
|
|
||||||
|
|
||||||
rlSetTexture(0);
|
rlSetTexture(0);
|
||||||
}
|
}
|
||||||
|
@ -1810,3 +1813,5 @@ static float EaseCubicInOut(float t, float b, float c, float d)
|
||||||
|
|
||||||
return 0.5f*c*(t*t*t + 2.0f) + b;
|
return 0.5f*c*(t*t*t + 2.0f) + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // SUPPORT_MODULE_RSHAPES
|
||||||
|
|
270
raylib/rtext.c
270
raylib/rtext.c
|
@ -4,6 +4,9 @@
|
||||||
*
|
*
|
||||||
* CONFIGURATION:
|
* CONFIGURATION:
|
||||||
*
|
*
|
||||||
|
* #define SUPPORT_MODULE_RTEXT
|
||||||
|
* rtext module is included in the build
|
||||||
|
*
|
||||||
* #define SUPPORT_FILEFORMAT_FNT
|
* #define SUPPORT_FILEFORMAT_FNT
|
||||||
* #define SUPPORT_FILEFORMAT_TTF
|
* #define SUPPORT_FILEFORMAT_TTF
|
||||||
* Selected desired fileformats to be supported for loading. Some of those formats are
|
* Selected desired fileformats to be supported for loading. Some of those formats are
|
||||||
|
@ -22,12 +25,12 @@
|
||||||
*
|
*
|
||||||
* DEPENDENCIES:
|
* DEPENDENCIES:
|
||||||
* stb_truetype - Load TTF file and rasterize characters data
|
* stb_truetype - Load TTF file and rasterize characters data
|
||||||
* stb_rect_pack - Rectangles packing algorythms, required for font atlas generation
|
* stb_rect_pack - Rectangles packing algorithms, required for font atlas generation
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* LICENSE: zlib/libpng
|
* LICENSE: zlib/libpng
|
||||||
*
|
*
|
||||||
* Copyright (c) 2013-2021 Ramon Santamaria (@raysan5)
|
* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5)
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
* 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.
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -53,6 +56,8 @@
|
||||||
#include "config.h" // Defines module configuration flags
|
#include "config.h" // Defines module configuration flags
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(SUPPORT_MODULE_RTEXT)
|
||||||
|
|
||||||
#include "utils.h" // Required for: LoadFileText()
|
#include "utils.h" // Required for: LoadFileText()
|
||||||
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 -> Only DrawTextPro()
|
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 -> Only DrawTextPro()
|
||||||
|
|
||||||
|
@ -224,7 +229,7 @@ extern void LoadFontDefault(void)
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Allocate space for our characters info data
|
// Allocate space for our characters info data
|
||||||
// NOTE: This memory should be freed at end! --> CloseWindow()
|
// NOTE: This memory must be freed at end! --> Done by CloseWindow()
|
||||||
defaultFont.glyphs = (GlyphInfo *)RL_MALLOC(defaultFont.glyphCount*sizeof(GlyphInfo));
|
defaultFont.glyphs = (GlyphInfo *)RL_MALLOC(defaultFont.glyphCount*sizeof(GlyphInfo));
|
||||||
defaultFont.recs = (Rectangle *)RL_MALLOC(defaultFont.glyphCount*sizeof(Rectangle));
|
defaultFont.recs = (Rectangle *)RL_MALLOC(defaultFont.glyphCount*sizeof(Rectangle));
|
||||||
|
|
||||||
|
@ -311,7 +316,7 @@ Font LoadFont(const char *fileName)
|
||||||
Font font = { 0 };
|
Font font = { 0 };
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_TTF)
|
#if defined(SUPPORT_FILEFORMAT_TTF)
|
||||||
if (IsFileExtension(fileName, ".ttf;.otf")) font = LoadFontEx(fileName, FONT_TTF_DEFAULT_SIZE, NULL, FONT_TTF_DEFAULT_NUMCHARS);
|
if (IsFileExtension(fileName, ".ttf") || IsFileExtension(fileName, ".otf")) font = LoadFontEx(fileName, FONT_TTF_DEFAULT_SIZE, NULL, FONT_TTF_DEFAULT_NUMCHARS);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_FNT)
|
#if defined(SUPPORT_FILEFORMAT_FNT)
|
||||||
|
@ -329,7 +334,11 @@ Font LoadFont(const char *fileName)
|
||||||
TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
|
TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
|
||||||
font = GetFontDefault();
|
font = GetFontDefault();
|
||||||
}
|
}
|
||||||
else SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default we set point filter (best performance)
|
else
|
||||||
|
{
|
||||||
|
SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default we set point filter (best performance)
|
||||||
|
TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", FONT_TTF_DEFAULT_SIZE, FONT_TTF_DEFAULT_NUMCHARS);
|
||||||
|
}
|
||||||
|
|
||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
@ -515,7 +524,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
|
||||||
|
|
||||||
UnloadImage(atlas);
|
UnloadImage(atlas);
|
||||||
|
|
||||||
// TRACELOG(LOG_INFO, "FONT: Font loaded successfully (%i glyphs)", font.glyphCount);
|
TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount);
|
||||||
}
|
}
|
||||||
else font = GetFontDefault();
|
else font = GetFontDefault();
|
||||||
}
|
}
|
||||||
|
@ -677,8 +686,8 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int glyphC
|
||||||
// NOTE 2: SDF font characters already contain an internal padding,
|
// NOTE 2: SDF font characters already contain an internal padding,
|
||||||
// so image size would result bigger than default font type
|
// so image size would result bigger than default font type
|
||||||
float requiredArea = 0;
|
float requiredArea = 0;
|
||||||
for (int i = 0; i < glyphCount; i++) requiredArea += ((chars[i].image.width + 2*padding)*(chars[i].image.height + 2*padding));
|
for (int i = 0; i < glyphCount; i++) requiredArea += ((chars[i].image.width + 2*padding)*(fontSize + 2*padding));
|
||||||
float guessSize = sqrtf(requiredArea)*1.3f;
|
float guessSize = sqrtf(requiredArea)*1.4f;
|
||||||
int imageSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT
|
int imageSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT
|
||||||
|
|
||||||
atlas.width = imageSize; // Atlas bitmap width
|
atlas.width = imageSize; // Atlas bitmap width
|
||||||
|
@ -690,7 +699,7 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int glyphC
|
||||||
// DEBUG: We can see padding in the generated image setting a gray background...
|
// DEBUG: We can see padding in the generated image setting a gray background...
|
||||||
//for (int i = 0; i < atlas.width*atlas.height; i++) ((unsigned char *)atlas.data)[i] = 100;
|
//for (int i = 0; i < atlas.width*atlas.height; i++) ((unsigned char *)atlas.data)[i] = 100;
|
||||||
|
|
||||||
if (packMethod == 0) // Use basic packing algorythm
|
if (packMethod == 0) // Use basic packing algorithm
|
||||||
{
|
{
|
||||||
int offsetX = padding;
|
int offsetX = padding;
|
||||||
int offsetY = padding;
|
int offsetY = padding;
|
||||||
|
@ -725,11 +734,23 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int glyphC
|
||||||
// height is bigger than fontSize, it could be up to (fontSize + 8)
|
// height is bigger than fontSize, it could be up to (fontSize + 8)
|
||||||
offsetY += (fontSize + 2*padding);
|
offsetY += (fontSize + 2*padding);
|
||||||
|
|
||||||
if (offsetY > (atlas.height - fontSize - padding)) break;
|
if (offsetY > (atlas.height - fontSize - padding))
|
||||||
|
{
|
||||||
|
for(int j = i + 1; j < glyphCount; j++)
|
||||||
|
{
|
||||||
|
TRACELOG(LOG_WARNING, "FONT: Failed to package character (%i)", j);
|
||||||
|
// make sure remaining recs contain valid data
|
||||||
|
recs[j].x = 0;
|
||||||
|
recs[j].y = 0;
|
||||||
|
recs[j].width = 0;
|
||||||
|
recs[j].height = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (packMethod == 1) // Use Skyline rect packing algorythm (stb_pack_rect)
|
}
|
||||||
|
else if (packMethod == 1) // Use Skyline rect packing algorithm (stb_pack_rect)
|
||||||
{
|
{
|
||||||
stbrp_context *context = (stbrp_context *)RL_MALLOC(sizeof(*context));
|
stbrp_context *context = (stbrp_context *)RL_MALLOC(sizeof(*context));
|
||||||
stbrp_node *nodes = (stbrp_node *)RL_MALLOC(glyphCount*sizeof(*nodes));
|
stbrp_node *nodes = (stbrp_node *)RL_MALLOC(glyphCount*sizeof(*nodes));
|
||||||
|
@ -797,9 +818,12 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int glyphC
|
||||||
// Unload font glyphs info data (RAM)
|
// Unload font glyphs info data (RAM)
|
||||||
void UnloadFontData(GlyphInfo *glyphs, int glyphCount)
|
void UnloadFontData(GlyphInfo *glyphs, int glyphCount)
|
||||||
{
|
{
|
||||||
|
if (glyphs != NULL)
|
||||||
|
{
|
||||||
for (int i = 0; i < glyphCount; i++) UnloadImage(glyphs[i].image);
|
for (int i = 0; i < glyphCount; i++) UnloadImage(glyphs[i].image);
|
||||||
|
|
||||||
RL_FREE(glyphs);
|
RL_FREE(glyphs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unload Font from GPU memory (VRAM)
|
// Unload Font from GPU memory (VRAM)
|
||||||
|
@ -816,15 +840,170 @@ void UnloadFont(Font font)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Export font as code file, returns true on success
|
||||||
|
bool ExportFontAsCode(Font font, const char *fileName)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
#ifndef TEXT_BYTES_PER_LINE
|
||||||
|
#define TEXT_BYTES_PER_LINE 20
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAX_FONT_DATA_SIZE 1024*1024 // 1 MB
|
||||||
|
|
||||||
|
// Get file name from path
|
||||||
|
char fileNamePascal[256] = { 0 };
|
||||||
|
strcpy(fileNamePascal, TextToPascal(GetFileNameWithoutExt(fileName)));
|
||||||
|
|
||||||
|
// NOTE: Text data buffer size is estimated considering image data size in bytes
|
||||||
|
// and requiring 6 char bytes for every byte: "0x00, "
|
||||||
|
char *txtData = (char *)RL_CALLOC(MAX_FONT_DATA_SIZE, sizeof(char));
|
||||||
|
|
||||||
|
int byteCount = 0;
|
||||||
|
byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// FontAsCode exporter v1.0 - Font data exported as an array of bytes //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2022 Ramon Santamaria (@raysan5) //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// ---------------------------------------------------------------------------------- //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// TODO: Fill the information and license of the exported font here: //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// Font name: .... //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// Font creator: .... //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// Font LICENSE: .... //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
|
||||||
|
|
||||||
|
// Support font export and initialization
|
||||||
|
// NOTE: This mechanism is highly coupled to raylib
|
||||||
|
Image image = LoadImageFromTexture(font.texture);
|
||||||
|
if (image.format != PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) TRACELOG(LOG_WARNING, "Font export as code: Font image format is not GRAY+ALPHA!");
|
||||||
|
int imageDataSize = GetPixelDataSize(image.width, image.height, image.format);
|
||||||
|
|
||||||
|
// Image data is usually GRAYSCALE + ALPHA and can be reduced to GRAYSCALE
|
||||||
|
//ImageFormat(&image, PIXELFORMAT_UNCOMPRESSED_GRAYSCALE);
|
||||||
|
|
||||||
|
#define SUPPORT_COMPRESSED_FONT_ATLAS
|
||||||
|
#if defined(SUPPORT_COMPRESSED_FONT_ATLAS)
|
||||||
|
// WARNING: Data is compressed using raylib CompressData() DEFLATE,
|
||||||
|
// it requires to be decompressed with raylib DecompressData(), that requires
|
||||||
|
// compiling raylib with SUPPORT_COMPRESSION_API config flag enabled
|
||||||
|
|
||||||
|
// Compress font image data
|
||||||
|
int compDataSize = 0;
|
||||||
|
unsigned char *compData = CompressData(image.data, imageDataSize, &compDataSize);
|
||||||
|
|
||||||
|
// Save font image data (compressed)
|
||||||
|
byteCount += sprintf(txtData + byteCount, "#define COMPRESSED_DATA_SIZE_FONT_%s %i\n\n", TextToUpper(fileNamePascal), compDataSize);
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// Font image pixels data compressed (DEFLATE)\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// NOTE: Original pixel data simplified to GRAYSCALE\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "static unsigned char fontData_%s[COMPRESSED_DATA_SIZE_FONT_%s] = { ", fileNamePascal, TextToUpper(fileNamePascal));
|
||||||
|
for (int i = 0; i < compDataSize - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%02x,\n " : "0x%02x, "), compData[i]);
|
||||||
|
byteCount += sprintf(txtData + byteCount, "0x%02x };\n\n", compData[compDataSize - 1]);
|
||||||
|
MemFree(compData);
|
||||||
|
#else
|
||||||
|
// Save font image data (uncompressed)
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// Font image pixels data\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// NOTE: 2 bytes per pixel, GRAY + ALPHA channels\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "static unsigned char fontImageData_%s[%i] = { ", fileNamePascal, imageDataSize);
|
||||||
|
for (int i = 0; i < imageDataSize - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%02x,\n " : "0x%02x, "), ((unsigned char *)imFont.data)[i]);
|
||||||
|
byteCount += sprintf(txtData + byteCount, "0x%02x };\n\n", ((unsigned char *)imFont.data)[imageDataSize - 1]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Save font recs data
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// Font characters rectangles data\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "static const Rectangle fontRecs_%s[%i] = {\n", fileNamePascal, font.glyphCount);
|
||||||
|
for (int i = 0; i < font.glyphCount; i++)
|
||||||
|
{
|
||||||
|
byteCount += sprintf(txtData + byteCount, " { %1.0f, %1.0f, %1.0f , %1.0f },\n", font.recs[i].x, font.recs[i].y, font.recs[i].width, font.recs[i].height);
|
||||||
|
}
|
||||||
|
byteCount += sprintf(txtData + byteCount, "};\n\n");
|
||||||
|
|
||||||
|
// Save font glyphs data
|
||||||
|
// NOTE: Glyphs image data not saved (grayscale pixels),
|
||||||
|
// it could be generated from image and recs
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// Font glyphs info data\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// NOTE: No glyphs.image data provided\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "static const GlyphInfo fontGlyphs_%s[%i] = {\n", fileNamePascal, font.glyphCount);
|
||||||
|
for (int i = 0; i < font.glyphCount; i++)
|
||||||
|
{
|
||||||
|
byteCount += sprintf(txtData + byteCount, " { %i, %i, %i, %i, { 0 }},\n", font.glyphs[i].value, font.glyphs[i].offsetX, font.glyphs[i].offsetY, font.glyphs[i].advanceX);
|
||||||
|
}
|
||||||
|
byteCount += sprintf(txtData + byteCount, "};\n\n");
|
||||||
|
|
||||||
|
// Custom font loading function
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// Font loading function: %s\n", fileNamePascal);
|
||||||
|
byteCount += sprintf(txtData + byteCount, "static Font LoadFont_%s(void)\n{\n", fileNamePascal);
|
||||||
|
byteCount += sprintf(txtData + byteCount, " Font font = { 0 };\n\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, " font.baseSize = %i;\n", font.baseSize);
|
||||||
|
byteCount += sprintf(txtData + byteCount, " font.glyphCount = %i;\n", font.glyphCount);
|
||||||
|
byteCount += sprintf(txtData + byteCount, " font.glyphPadding = %i;\n\n", font.glyphPadding);
|
||||||
|
byteCount += sprintf(txtData + byteCount, " // Custom font loading\n");
|
||||||
|
#if defined(SUPPORT_COMPRESSED_FONT_ATLAS)
|
||||||
|
byteCount += sprintf(txtData + byteCount, " // NOTE: Compressed font image data (DEFLATE), it requires DecompressData() function\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, " int fontDataSize_%s = 0;\n", fileNamePascal);
|
||||||
|
byteCount += sprintf(txtData + byteCount, " unsigned char *data = DecompressData(fontData_%s, COMPRESSED_DATA_SIZE_FONT_%s, &fontDataSize_%s);\n", fileNamePascal, TextToUpper(fileNamePascal), fileNamePascal);
|
||||||
|
byteCount += sprintf(txtData + byteCount, " Image imFont = { data, %i, %i, 1, %i };\n\n", image.width, image.height, image.format);
|
||||||
|
#else
|
||||||
|
byteCount += sprintf(txtData + byteCount, " Image imFont = { fontImageData_%s, %i, %i, 1, %i };\n\n", styleName, image.width, image.height, image.format);
|
||||||
|
#endif
|
||||||
|
byteCount += sprintf(txtData + byteCount, " // Load texture from image\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, " font.texture = LoadTextureFromImage(imFont);\n");
|
||||||
|
#if defined(SUPPORT_COMPRESSED_FONT_ATLAS)
|
||||||
|
byteCount += sprintf(txtData + byteCount, " UnloadImage(imFont); // Uncompressed data can be unloaded from memory\n\n");
|
||||||
|
#endif
|
||||||
|
// We have two possible mechanisms to assign font.recs and font.glyphs data,
|
||||||
|
// that data is already available as global arrays, we two options to assign that data:
|
||||||
|
// - 1. Data copy. This option consumes more memory and Font MUST be unloaded by user, requiring additional code.
|
||||||
|
// - 2. Data assignment. This option consumes less memory and Font MUST NOT be unloaded by user because data is on protected DATA segment
|
||||||
|
//#define SUPPORT_FONT_DATA_COPY
|
||||||
|
#if defined(SUPPORT_FONT_DATA_COPY)
|
||||||
|
byteCount += sprintf(txtData + byteCount, " // Copy glyph recs data from global fontRecs\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, " // NOTE: Required to avoid issues if trying to free font\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, " font.recs = (Rectangle *)malloc(font.glyphCount*sizeof(Rectangle));\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, " memcpy(font.recs, fontRecs_%s, font.glyphCount*sizeof(Rectangle));\n\n", fileNamePascal);
|
||||||
|
|
||||||
|
byteCount += sprintf(txtData + byteCount, " // Copy font glyph info data from global fontChars\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, " // NOTE: Required to avoid issues if trying to free font\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, " font.glyphs = (GlyphInfo *)malloc(font.glyphCount*sizeof(GlyphInfo));\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, " memcpy(font.glyphs, fontGlyphs_%s, font.glyphCount*sizeof(GlyphInfo));\n\n", fileNamePascal);
|
||||||
|
#else
|
||||||
|
byteCount += sprintf(txtData + byteCount, " // Assign glyph recs and info data directly\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, " // WARNING: This font data must not be unloaded\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, " font.recs = fontRecs_%s;\n", fileNamePascal);
|
||||||
|
byteCount += sprintf(txtData + byteCount, " font.glyphs = fontGlyphs_%s;\n\n", fileNamePascal);
|
||||||
|
#endif
|
||||||
|
byteCount += sprintf(txtData + byteCount, " return font;\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "}\n");
|
||||||
|
|
||||||
|
UnloadImage(image);
|
||||||
|
|
||||||
|
// NOTE: Text data size exported is determined by '\0' (NULL) character
|
||||||
|
success = SaveFileText(fileName, txtData);
|
||||||
|
|
||||||
|
RL_FREE(txtData);
|
||||||
|
|
||||||
|
if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Font as code exported successfully", fileName);
|
||||||
|
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export font as code", fileName);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Draw current FPS
|
// Draw current FPS
|
||||||
// NOTE: Uses default font
|
// NOTE: Uses default font
|
||||||
void DrawFPS(int posX, int posY)
|
void DrawFPS(int posX, int posY)
|
||||||
{
|
{
|
||||||
Color color = LIME; // good fps
|
Color color = LIME; // Good FPS
|
||||||
int fps = GetFPS();
|
int fps = GetFPS();
|
||||||
|
|
||||||
if (fps < 30 && fps >= 15) color = ORANGE; // warning FPS
|
if ((fps < 30) && (fps >= 15)) color = ORANGE; // Warning FPS
|
||||||
else if (fps < 15) color = RED; // bad FPS
|
else if (fps < 15) color = RED; // Low FPS
|
||||||
|
|
||||||
DrawText(TextFormat("%2i FPS", GetFPS()), posX, posY, 20, color);
|
DrawText(TextFormat("%2i FPS", GetFPS()), posX, posY, 20, color);
|
||||||
}
|
}
|
||||||
|
@ -875,7 +1054,7 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
|
||||||
{
|
{
|
||||||
// NOTE: Fixed line spacing of 1.5 line-height
|
// NOTE: Fixed line spacing of 1.5 line-height
|
||||||
// TODO: Support custom line spacing defined by user
|
// TODO: Support custom line spacing defined by user
|
||||||
textOffsetY += (int)((font.baseSize + font.baseSize/2)*scaleFactor);
|
textOffsetY += (int)((font.baseSize + font.baseSize/2.0f)*scaleFactor);
|
||||||
textOffsetX = 0.0f;
|
textOffsetX = 0.0f;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -931,10 +1110,42 @@ void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSiz
|
||||||
DrawTexturePro(font.texture, srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, tint);
|
DrawTexturePro(font.texture, srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, tint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw multiple character (codepoints)
|
||||||
|
void DrawTextCodepoints(Font font, const int *codepoints, int count, Vector2 position, float fontSize, float spacing, Color tint)
|
||||||
|
{
|
||||||
|
int textOffsetY = 0; // Offset between lines (on line break '\n')
|
||||||
|
float textOffsetX = 0.0f; // Offset X to next character to draw
|
||||||
|
|
||||||
|
float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
int index = GetGlyphIndex(font, codepoints[i]);
|
||||||
|
|
||||||
|
if (codepoints[i] == '\n')
|
||||||
|
{
|
||||||
|
// NOTE: Fixed line spacing of 1.5 line-height
|
||||||
|
// TODO: Support custom line spacing defined by user
|
||||||
|
textOffsetY += (int)((font.baseSize + font.baseSize/2.0f)*scaleFactor);
|
||||||
|
textOffsetX = 0.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((codepoints[i] != ' ') && (codepoints[i] != '\t'))
|
||||||
|
{
|
||||||
|
DrawTextCodepoint(font, codepoints[i], (Vector2){ position.x + textOffsetX, position.y + textOffsetY }, fontSize, tint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (font.glyphs[index].advanceX == 0) textOffsetX += ((float)font.recs[index].width*scaleFactor + spacing);
|
||||||
|
else textOffsetX += ((float)font.glyphs[index].advanceX*scaleFactor + spacing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Measure string width for default font
|
// Measure string width for default font
|
||||||
int MeasureText(const char *text, int fontSize)
|
int MeasureText(const char *text, int fontSize)
|
||||||
{
|
{
|
||||||
Vector2 vec = { 0.0f, 0.0f };
|
Vector2 textSize = { 0.0f, 0.0f };
|
||||||
|
|
||||||
// Check if default font has been loaded
|
// Check if default font has been loaded
|
||||||
if (GetFontDefault().texture.id != 0)
|
if (GetFontDefault().texture.id != 0)
|
||||||
|
@ -943,15 +1154,19 @@ int MeasureText(const char *text, int fontSize)
|
||||||
if (fontSize < defaultFontSize) fontSize = defaultFontSize;
|
if (fontSize < defaultFontSize) fontSize = defaultFontSize;
|
||||||
int spacing = fontSize/defaultFontSize;
|
int spacing = fontSize/defaultFontSize;
|
||||||
|
|
||||||
vec = MeasureTextEx(GetFontDefault(), text, (float)fontSize, (float)spacing);
|
textSize = MeasureTextEx(GetFontDefault(), text, (float)fontSize, (float)spacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int)vec.x;
|
return (int)textSize.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Measure string size for Font
|
// Measure string size for Font
|
||||||
Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing)
|
Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing)
|
||||||
{
|
{
|
||||||
|
Vector2 textSize = { 0 };
|
||||||
|
|
||||||
|
if ((font.texture.id == 0) || (text == NULL)) return textSize;
|
||||||
|
|
||||||
int size = TextLength(text); // Get size in bytes of text
|
int size = TextLength(text); // Get size in bytes of text
|
||||||
int tempByteCounter = 0; // Used to count longer text line num chars
|
int tempByteCounter = 0; // Used to count longer text line num chars
|
||||||
int byteCounter = 0;
|
int byteCounter = 0;
|
||||||
|
@ -996,11 +1211,10 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
|
||||||
|
|
||||||
if (tempTextWidth < textWidth) tempTextWidth = textWidth;
|
if (tempTextWidth < textWidth) tempTextWidth = textWidth;
|
||||||
|
|
||||||
Vector2 vec = { 0 };
|
textSize.x = tempTextWidth*scaleFactor + (float)((tempByteCounter - 1)*spacing); // Adds chars spacing to measure
|
||||||
vec.x = tempTextWidth*scaleFactor + (float)((tempByteCounter - 1)*spacing); // Adds chars spacing to measure
|
textSize.y = textHeight*scaleFactor;
|
||||||
vec.y = textHeight*scaleFactor;
|
|
||||||
|
|
||||||
return vec;
|
return textSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get index position for a unicode character on font
|
// Get index position for a unicode character on font
|
||||||
|
@ -1179,7 +1393,7 @@ const char *TextSubtext(const char *text, int position, int length)
|
||||||
|
|
||||||
// Replace text string
|
// Replace text string
|
||||||
// REQUIRES: strlen(), strstr(), strncpy(), strcpy()
|
// REQUIRES: strlen(), strstr(), strncpy(), strcpy()
|
||||||
// WARNING: Returned buffer must be freed by the user (if return != NULL)
|
// WARNING: Allocated memory must be manually freed
|
||||||
char *TextReplace(char *text, const char *replace, const char *by)
|
char *TextReplace(char *text, const char *replace, const char *by)
|
||||||
{
|
{
|
||||||
// Sanity checks and initialization
|
// Sanity checks and initialization
|
||||||
|
@ -1228,7 +1442,7 @@ char *TextReplace(char *text, const char *replace, const char *by)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert text in a specific position, moves all text forward
|
// Insert text in a specific position, moves all text forward
|
||||||
// WARNING: Allocated memory should be manually freed
|
// WARNING: Allocated memory must be manually freed
|
||||||
char *TextInsert(const char *text, const char *insert, int position)
|
char *TextInsert(const char *text, const char *insert, int position)
|
||||||
{
|
{
|
||||||
int textLen = TextLength(text);
|
int textLen = TextLength(text);
|
||||||
|
@ -1412,8 +1626,8 @@ const char *TextToPascal(const char *text)
|
||||||
|
|
||||||
// Encode text codepoint into UTF-8 text
|
// Encode text codepoint into UTF-8 text
|
||||||
// REQUIRES: memcpy()
|
// REQUIRES: memcpy()
|
||||||
// WARNING: Allocated memory should be manually freed
|
// WARNING: Allocated memory must be manually freed
|
||||||
char *TextCodepointsToUTF8(int *codepoints, int length)
|
char *TextCodepointsToUTF8(const int *codepoints, int length)
|
||||||
{
|
{
|
||||||
// We allocate enough memory fo fit all possible codepoints
|
// We allocate enough memory fo fit all possible codepoints
|
||||||
// NOTE: 5 bytes for every codepoint should be enough
|
// NOTE: 5 bytes for every codepoint should be enough
|
||||||
|
@ -1593,7 +1807,7 @@ int GetCodepoint(const char *text, int *bytesProcessed)
|
||||||
if (((octet == 0xe0) && !((octet1 >= 0xa0) && (octet1 <= 0xbf))) ||
|
if (((octet == 0xe0) && !((octet1 >= 0xa0) && (octet1 <= 0xbf))) ||
|
||||||
((octet == 0xed) && !((octet1 >= 0x80) && (octet1 <= 0x9f)))) { *bytesProcessed = 2; return code; }
|
((octet == 0xed) && !((octet1 >= 0x80) && (octet1 <= 0x9f)))) { *bytesProcessed = 2; return code; }
|
||||||
|
|
||||||
if ((octet >= 0xe0) && (0 <= 0xef))
|
if ((octet >= 0xe0) && (octet <= 0xef))
|
||||||
{
|
{
|
||||||
code = ((octet & 0xf) << 12) | ((octet1 & 0x3f) << 6) | (octet2 & 0x3f);
|
code = ((octet & 0xf) << 12) | ((octet1 & 0x3f) << 6) | (octet2 & 0x3f);
|
||||||
*bytesProcessed = 3;
|
*bytesProcessed = 3;
|
||||||
|
@ -1795,3 +2009,5 @@ static Font LoadBMFont(const char *fileName)
|
||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif // SUPPORT_MODULE_RTEXT
|
||||||
|
|
|
@ -4,11 +4,15 @@
|
||||||
*
|
*
|
||||||
* CONFIGURATION:
|
* CONFIGURATION:
|
||||||
*
|
*
|
||||||
|
* #define SUPPORT_MODULE_RTEXTURES
|
||||||
|
* rtextures module is included in the build
|
||||||
|
*
|
||||||
* #define SUPPORT_FILEFORMAT_BMP
|
* #define SUPPORT_FILEFORMAT_BMP
|
||||||
* #define SUPPORT_FILEFORMAT_PNG
|
* #define SUPPORT_FILEFORMAT_PNG
|
||||||
* #define SUPPORT_FILEFORMAT_TGA
|
* #define SUPPORT_FILEFORMAT_TGA
|
||||||
* #define SUPPORT_FILEFORMAT_JPG
|
* #define SUPPORT_FILEFORMAT_JPG
|
||||||
* #define SUPPORT_FILEFORMAT_GIF
|
* #define SUPPORT_FILEFORMAT_GIF
|
||||||
|
* #define SUPPORT_FILEFORMAT_QOI
|
||||||
* #define SUPPORT_FILEFORMAT_PSD
|
* #define SUPPORT_FILEFORMAT_PSD
|
||||||
* #define SUPPORT_FILEFORMAT_PIC
|
* #define SUPPORT_FILEFORMAT_PIC
|
||||||
* #define SUPPORT_FILEFORMAT_HDR
|
* #define SUPPORT_FILEFORMAT_HDR
|
||||||
|
@ -33,12 +37,12 @@
|
||||||
* DEPENDENCIES:
|
* DEPENDENCIES:
|
||||||
* stb_image - Multiple image formats loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC)
|
* stb_image - Multiple image formats loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC)
|
||||||
* NOTE: stb_image has been slightly modified to support Android platform.
|
* NOTE: stb_image has been slightly modified to support Android platform.
|
||||||
* stb_image_resize - Multiple image resize algorythms
|
* stb_image_resize - Multiple image resize algorithms
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* LICENSE: zlib/libpng
|
* LICENSE: zlib/libpng
|
||||||
*
|
*
|
||||||
* Copyright (c) 2013-2021 Ramon Santamaria (@raysan5)
|
* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5)
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
* 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.
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -64,11 +68,13 @@
|
||||||
#include "config.h" // Defines module configuration flags
|
#include "config.h" // Defines module configuration flags
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(SUPPORT_MODULE_RTEXTURES)
|
||||||
|
|
||||||
#include "utils.h" // Required for: TRACELOG() and fopen() Android mapping
|
#include "utils.h" // Required for: TRACELOG() and fopen() Android mapping
|
||||||
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2
|
#include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2
|
||||||
|
|
||||||
#include <stdlib.h> // Required for: malloc(), free()
|
#include <stdlib.h> // Required for: malloc(), free()
|
||||||
#include <string.h> // Required for: strlen() [Used in ImageTextEx()]
|
#include <string.h> // Required for: strlen() [Used in ImageTextEx()], strcmp() [Used in LoadImageFromMemory()]
|
||||||
#include <math.h> // Required for: fabsf()
|
#include <math.h> // Required for: fabsf()
|
||||||
#include <stdio.h> // Required for: sprintf() [Used in ExportImageAsCode()]
|
#include <stdio.h> // Required for: sprintf() [Used in ExportImageAsCode()]
|
||||||
|
|
||||||
|
@ -124,6 +130,14 @@
|
||||||
// NOTE: Used to read image data (multiple formats support)
|
// NOTE: Used to read image data (multiple formats support)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(SUPPORT_FILEFORMAT_QOI)
|
||||||
|
#define QOI_MALLOC RL_MALLOC
|
||||||
|
#define QOI_FREE RL_FREE
|
||||||
|
|
||||||
|
#define QOI_IMPLEMENTATION
|
||||||
|
#include "external/qoi.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(SUPPORT_IMAGE_EXPORT)
|
#if defined(SUPPORT_IMAGE_EXPORT)
|
||||||
#define STBIW_MALLOC RL_MALLOC
|
#define STBIW_MALLOC RL_MALLOC
|
||||||
#define STBIW_FREE RL_FREE
|
#define STBIW_FREE RL_FREE
|
||||||
|
@ -202,7 +216,8 @@ Image LoadImage(const char *fileName)
|
||||||
defined(SUPPORT_FILEFORMAT_PIC) || \
|
defined(SUPPORT_FILEFORMAT_PIC) || \
|
||||||
defined(SUPPORT_FILEFORMAT_HDR) || \
|
defined(SUPPORT_FILEFORMAT_HDR) || \
|
||||||
defined(SUPPORT_FILEFORMAT_PSD)
|
defined(SUPPORT_FILEFORMAT_PSD)
|
||||||
#define STBI_REQUIRED
|
|
||||||
|
#define STBI_REQUIRED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Loading file to memory
|
// Loading file to memory
|
||||||
|
@ -286,36 +301,32 @@ Image LoadImageAnim(const char *fileName, int *frames)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load image from memory buffer, fileType refers to extension: i.e. ".png"
|
// Load image from memory buffer, fileType refers to extension: i.e. ".png"
|
||||||
|
// WARNING: File extension must be provided in lower-case
|
||||||
Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize)
|
Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize)
|
||||||
{
|
{
|
||||||
Image image = { 0 };
|
Image image = { 0 };
|
||||||
|
|
||||||
char fileExtLower[16] = { 0 };
|
|
||||||
strcpy(fileExtLower, TextToLower(fileType));
|
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_PNG)
|
|
||||||
if ((TextIsEqual(fileExtLower, ".png"))
|
|
||||||
#else
|
|
||||||
if ((false)
|
if ((false)
|
||||||
|
#if defined(SUPPORT_FILEFORMAT_PNG)
|
||||||
|
|| (strcmp(fileType, ".png") == 0)
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_BMP)
|
#if defined(SUPPORT_FILEFORMAT_BMP)
|
||||||
|| (TextIsEqual(fileExtLower, ".bmp"))
|
|| (strcmp(fileType, ".bmp") == 0)
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_TGA)
|
#if defined(SUPPORT_FILEFORMAT_TGA)
|
||||||
|| (TextIsEqual(fileExtLower, ".tga"))
|
|| (strcmp(fileType, ".tga") == 0)
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_JPG)
|
#if defined(SUPPORT_FILEFORMAT_JPG)
|
||||||
|| (TextIsEqual(fileExtLower, ".jpg") ||
|
|| ((strcmp(fileType, ".jpg") == 0) || (strcmp(fileType, ".jpeg") == 0))
|
||||||
TextIsEqual(fileExtLower, ".jpeg"))
|
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_GIF)
|
#if defined(SUPPORT_FILEFORMAT_GIF)
|
||||||
|| (TextIsEqual(fileExtLower, ".gif"))
|
|| (strcmp(fileType, ".gif") == 0)
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_PIC)
|
#if defined(SUPPORT_FILEFORMAT_PIC)
|
||||||
|| (TextIsEqual(fileExtLower, ".pic"))
|
|| (strcmp(fileType, ".pic") == 0)
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_PSD)
|
#if defined(SUPPORT_FILEFORMAT_PSD)
|
||||||
|| (TextIsEqual(fileExtLower, ".psd"))
|
|| (strcmp(fileType, ".psd") == 0)
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -340,7 +351,7 @@ Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, i
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#if defined(SUPPORT_FILEFORMAT_HDR)
|
#if defined(SUPPORT_FILEFORMAT_HDR)
|
||||||
else if (TextIsEqual(fileExtLower, ".hdr"))
|
else if (strcmp(fileType, ".hdr") == 0)
|
||||||
{
|
{
|
||||||
#if defined(STBI_REQUIRED)
|
#if defined(STBI_REQUIRED)
|
||||||
if (fileData != NULL)
|
if (fileData != NULL)
|
||||||
|
@ -362,20 +373,31 @@ Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, i
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(SUPPORT_FILEFORMAT_QOI)
|
||||||
|
else if (strcmp(fileType, ".qoi") == 0)
|
||||||
|
{
|
||||||
|
qoi_desc desc = { 0 };
|
||||||
|
image.data = qoi_decode(fileData, dataSize, &desc, 4);
|
||||||
|
image.width = desc.width;
|
||||||
|
image.height = desc.height;
|
||||||
|
image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
|
||||||
|
image.mipmaps = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_DDS)
|
#if defined(SUPPORT_FILEFORMAT_DDS)
|
||||||
else if (TextIsEqual(fileExtLower, ".dds")) image = LoadDDS(fileData, dataSize);
|
else if (strcmp(fileType, ".dds") == 0) image = LoadDDS(fileData, dataSize);
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_PKM)
|
#if defined(SUPPORT_FILEFORMAT_PKM)
|
||||||
else if (TextIsEqual(fileExtLower, ".pkm")) image = LoadPKM(fileData, dataSize);
|
else if (strcmp(fileType, ".pkm") == 0) image = LoadPKM(fileData, dataSize);
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_KTX)
|
#if defined(SUPPORT_FILEFORMAT_KTX)
|
||||||
else if (TextIsEqual(fileExtLower, ".ktx")) image = LoadKTX(fileData, dataSize);
|
else if (strcmp(fileType, ".ktx") == 0) image = LoadKTX(fileData, dataSize);
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_PVR)
|
#if defined(SUPPORT_FILEFORMAT_PVR)
|
||||||
else if (TextIsEqual(fileExtLower, ".pvr")) image = LoadPVR(fileData, dataSize);
|
else if (strcmp(fileType, ".pvr") == 0) image = LoadPVR(fileData, dataSize);
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_ASTC)
|
#if defined(SUPPORT_FILEFORMAT_ASTC)
|
||||||
else if (TextIsEqual(fileExtLower, ".astc")) image = LoadASTC(fileData, dataSize);
|
else if (strcmp(fileType, ".astc") == 0) image = LoadASTC(fileData, dataSize);
|
||||||
#endif
|
#endif
|
||||||
else TRACELOG(LOG_WARNING, "IMAGE: Data format not supported");
|
else TRACELOG(LOG_WARNING, "IMAGE: Data format not supported");
|
||||||
|
|
||||||
|
@ -477,7 +499,28 @@ bool ExportImage(Image image, const char *fileName)
|
||||||
else if (IsFileExtension(fileName, ".tga")) success = stbi_write_tga(fileName, image.width, image.height, channels, imgData);
|
else if (IsFileExtension(fileName, ".tga")) success = stbi_write_tga(fileName, image.width, image.height, channels, imgData);
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_JPG)
|
#if defined(SUPPORT_FILEFORMAT_JPG)
|
||||||
else if (IsFileExtension(fileName, ".jpg")) success = stbi_write_jpg(fileName, image.width, image.height, channels, imgData, 90); // JPG quality: between 1 and 100
|
else if (IsFileExtension(fileName, ".jpg") ||
|
||||||
|
IsFileExtension(fileName, ".jpeg")) success = stbi_write_jpg(fileName, image.width, image.height, channels, imgData, 90); // JPG quality: between 1 and 100
|
||||||
|
#endif
|
||||||
|
#if defined(SUPPORT_FILEFORMAT_QOI)
|
||||||
|
else if (IsFileExtension(fileName, ".qoi"))
|
||||||
|
{
|
||||||
|
channels = 0;
|
||||||
|
if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) channels = 3;
|
||||||
|
else if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) channels = 4;
|
||||||
|
else TRACELOG(LOG_WARNING, "IMAGE: Image pixel format must be R8G8B8 or R8G8B8A8");
|
||||||
|
|
||||||
|
if ((channels == 3) || (channels == 4))
|
||||||
|
{
|
||||||
|
qoi_desc desc = { 0 };
|
||||||
|
desc.width = image.width;
|
||||||
|
desc.height = image.height;
|
||||||
|
desc.channels = channels;
|
||||||
|
desc.colorspace = QOI_SRGB;
|
||||||
|
|
||||||
|
success = qoi_write(fileName, imgData, &desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_KTX)
|
#if defined(SUPPORT_FILEFORMAT_KTX)
|
||||||
else if (IsFileExtension(fileName, ".ktx")) success = SaveKTX(image, fileName);
|
else if (IsFileExtension(fileName, ".ktx")) success = SaveKTX(image, fileName);
|
||||||
|
@ -523,7 +566,7 @@ bool ExportImageAsCode(Image image, const char *fileName)
|
||||||
byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n");
|
byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n");
|
||||||
byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n");
|
byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n");
|
||||||
byteCount += sprintf(txtData + byteCount, "// //\n");
|
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||||
byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2021 Ramon Santamaria (@raysan5) //\n");
|
byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2018-2022 Ramon Santamaria (@raysan5) //\n");
|
||||||
byteCount += sprintf(txtData + byteCount, "// //\n");
|
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||||
byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
|
byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
|
||||||
|
|
||||||
|
@ -549,8 +592,8 @@ bool ExportImageAsCode(Image image, const char *fileName)
|
||||||
|
|
||||||
#endif // SUPPORT_IMAGE_EXPORT
|
#endif // SUPPORT_IMAGE_EXPORT
|
||||||
|
|
||||||
if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image exported successfully", fileName);
|
if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Image as code exported successfully", fileName);
|
||||||
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image", fileName);
|
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export image as code", fileName);
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
@ -732,7 +775,7 @@ Image GenImageCellular(int width, int height, int tileSize)
|
||||||
{
|
{
|
||||||
int y = (i/seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1);
|
int y = (i/seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1);
|
||||||
int x = (i%seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1);
|
int x = (i%seedsPerRow)*tileSize + GetRandomValue(0, tileSize - 1);
|
||||||
seeds[i] = (Vector2){ (float)x, (float)y};
|
seeds[i] = (Vector2){ (float)x, (float)y };
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int y = 0; y < height; y++)
|
for (int y = 0; y < height; y++)
|
||||||
|
@ -743,7 +786,7 @@ Image GenImageCellular(int width, int height, int tileSize)
|
||||||
{
|
{
|
||||||
int tileX = x/tileSize;
|
int tileX = x/tileSize;
|
||||||
|
|
||||||
float minDistance = (float)strtod("Inf", NULL);
|
float minDistance = 65536.0f; //(float)strtod("Inf", NULL);
|
||||||
|
|
||||||
// Check all adjacent tiles
|
// Check all adjacent tiles
|
||||||
for (int i = -1; i < 2; i++)
|
for (int i = -1; i < 2; i++)
|
||||||
|
@ -832,11 +875,11 @@ Image ImageFromImage(Image image, Rectangle rec)
|
||||||
|
|
||||||
result.width = (int)rec.width;
|
result.width = (int)rec.width;
|
||||||
result.height = (int)rec.height;
|
result.height = (int)rec.height;
|
||||||
result.data = RL_CALLOC((int)(rec.width*rec.height)*bytesPerPixel, 1);
|
result.data = RL_CALLOC((int)rec.width*(int)rec.height*bytesPerPixel, 1);
|
||||||
result.format = image.format;
|
result.format = image.format;
|
||||||
result.mipmaps = 1;
|
result.mipmaps = 1;
|
||||||
|
|
||||||
for (int y = 0; y < rec.height; y++)
|
for (int y = 0; y < (int)rec.height; y++)
|
||||||
{
|
{
|
||||||
memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel, ((unsigned char *)image.data) + ((y + (int)rec.y)*image.width + (int)rec.x)*bytesPerPixel, (int)rec.width*bytesPerPixel);
|
memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel, ((unsigned char *)image.data) + ((y + (int)rec.y)*image.width + (int)rec.x)*bytesPerPixel, (int)rec.width*bytesPerPixel);
|
||||||
}
|
}
|
||||||
|
@ -1092,35 +1135,41 @@ void ImageToPOT(Image *image, Color fill)
|
||||||
// Create an image from text (default font)
|
// Create an image from text (default font)
|
||||||
Image ImageText(const char *text, int fontSize, Color color)
|
Image ImageText(const char *text, int fontSize, Color color)
|
||||||
{
|
{
|
||||||
|
Image imText = { 0 };
|
||||||
|
#if defined(SUPPORT_MODULE_RTEXT)
|
||||||
int defaultFontSize = 10; // Default Font chars height in pixel
|
int defaultFontSize = 10; // Default Font chars height in pixel
|
||||||
if (fontSize < defaultFontSize) fontSize = defaultFontSize;
|
if (fontSize < defaultFontSize) fontSize = defaultFontSize;
|
||||||
int spacing = fontSize/defaultFontSize;
|
int spacing = fontSize/defaultFontSize;
|
||||||
|
imText = ImageTextEx(GetFontDefault(), text, (float)fontSize, (float)spacing, color); // WARNING: Module required: rtext
|
||||||
Image imText = ImageTextEx(GetFontDefault(), text, (float)fontSize, (float)spacing, color);
|
#else
|
||||||
|
imText = GenImageColor(200, 60, BLACK); // Generating placeholder black image rectangle
|
||||||
|
TRACELOG(LOG_WARNING, "IMAGE: ImageTextEx() requires module: rtext");
|
||||||
|
#endif
|
||||||
return imText;
|
return imText;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an image from text (custom sprite font)
|
// Create an image from text (custom sprite font)
|
||||||
Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint)
|
Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint)
|
||||||
{
|
{
|
||||||
|
Image imText = { 0 };
|
||||||
|
#if defined(SUPPORT_MODULE_RTEXT)
|
||||||
int size = (int)strlen(text); // Get size in bytes of text
|
int size = (int)strlen(text); // Get size in bytes of text
|
||||||
|
|
||||||
int textOffsetX = 0; // Image drawing position X
|
int textOffsetX = 0; // Image drawing position X
|
||||||
int textOffsetY = 0; // Offset between lines (on line break '\n')
|
int textOffsetY = 0; // Offset between lines (on line break '\n')
|
||||||
|
|
||||||
// NOTE: Text image is generated at font base size, later scaled to desired font size
|
// NOTE: Text image is generated at font base size, later scaled to desired font size
|
||||||
Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing);
|
Vector2 imSize = MeasureTextEx(font, text, (float)font.baseSize, spacing); // WARNING: Module required: rtext
|
||||||
|
|
||||||
// Create image to store text
|
// Create image to store text
|
||||||
Image imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK);
|
imText = GenImageColor((int)imSize.x, (int)imSize.y, BLANK);
|
||||||
|
|
||||||
for (int i = 0; i < size; i++)
|
for (int i = 0; i < size; i++)
|
||||||
{
|
{
|
||||||
// Get next codepoint from byte string and glyph index in font
|
// Get next codepoint from byte string and glyph index in font
|
||||||
int codepointByteCount = 0;
|
int codepointByteCount = 0;
|
||||||
int codepoint = GetCodepoint(&text[i], &codepointByteCount);
|
int codepoint = GetCodepoint(&text[i], &codepointByteCount); // WARNING: Module required: rtext
|
||||||
int index = GetGlyphIndex(font, codepoint);
|
int index = GetGlyphIndex(font, codepoint); // WARNING: Module required: rtext
|
||||||
|
|
||||||
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
|
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
|
||||||
// but we need to draw all of the bad bytes using the '?' symbol moving one byte
|
// but we need to draw all of the bad bytes using the '?' symbol moving one byte
|
||||||
|
@ -1155,10 +1204,14 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co
|
||||||
TRACELOG(LOG_INFO, "IMAGE: Text scaled by factor: %f", scaleFactor);
|
TRACELOG(LOG_INFO, "IMAGE: Text scaled by factor: %f", scaleFactor);
|
||||||
|
|
||||||
// Using nearest-neighbor scaling algorithm for default font
|
// Using nearest-neighbor scaling algorithm for default font
|
||||||
|
// WARNING: Module required: rtext
|
||||||
if (font.texture.id == GetFontDefault().texture.id) ImageResizeNN(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor));
|
if (font.texture.id == GetFontDefault().texture.id) ImageResizeNN(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor));
|
||||||
else ImageResize(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor));
|
else ImageResize(&imText, (int)(imSize.x*scaleFactor), (int)(imSize.y*scaleFactor));
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
imText = GenImageColor(200, 60, BLACK); // Generating placeholder black image rectangle
|
||||||
|
TRACELOG(LOG_WARNING, "IMAGE: ImageTextEx() requires module: rtext");
|
||||||
|
#endif
|
||||||
return imText;
|
return imText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1361,10 +1414,12 @@ void ImageResize(Image *image, int newWidth, int newHeight)
|
||||||
// Security check to avoid program crash
|
// Security check to avoid program crash
|
||||||
if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
|
if ((image->data == NULL) || (image->width == 0) || (image->height == 0)) return;
|
||||||
|
|
||||||
bool fastPath = true;
|
// Check if we can use a fast path on image scaling
|
||||||
if ((image->format != PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) && (image->format != PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) && (image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8) && (image->format != PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)) fastPath = true;
|
// It can be for 8 bit per channel images with 1 to 4 channels per pixel
|
||||||
|
if ((image->format == PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) ||
|
||||||
if (fastPath)
|
(image->format == PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA) ||
|
||||||
|
(image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8) ||
|
||||||
|
(image->format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8))
|
||||||
{
|
{
|
||||||
int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
|
int bytesPerPixel = GetPixelDataSize(1, 1, image->format);
|
||||||
unsigned char *output = (unsigned char *)RL_MALLOC(newWidth*newHeight*bytesPerPixel);
|
unsigned char *output = (unsigned char *)RL_MALLOC(newWidth*newHeight*bytesPerPixel);
|
||||||
|
@ -1836,10 +1891,10 @@ void ImageColorTint(Image *image, Color color)
|
||||||
unsigned char b = (unsigned char)(((float)pixels[index].b/255*cB)*255.0f);
|
unsigned char b = (unsigned char)(((float)pixels[index].b/255*cB)*255.0f);
|
||||||
unsigned char a = (unsigned char)(((float)pixels[index].a/255*cA)*255.0f);
|
unsigned char a = (unsigned char)(((float)pixels[index].a/255*cA)*255.0f);
|
||||||
|
|
||||||
pixels[y*image->width + x].r = r;
|
pixels[index].r = r;
|
||||||
pixels[y*image->width + x].g = g;
|
pixels[index].g = g;
|
||||||
pixels[y*image->width + x].b = b;
|
pixels[index].b = b;
|
||||||
pixels[y*image->width + x].a = a;
|
pixels[index].a = a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1905,25 +1960,25 @@ void ImageColorContrast(Image *image, float contrast)
|
||||||
for (int x = 0; x < image->width; x++)
|
for (int x = 0; x < image->width; x++)
|
||||||
{
|
{
|
||||||
float pR = (float)pixels[y*image->width + x].r/255.0f;
|
float pR = (float)pixels[y*image->width + x].r/255.0f;
|
||||||
pR -= 0.5;
|
pR -= 0.5f;
|
||||||
pR *= contrast;
|
pR *= contrast;
|
||||||
pR += 0.5;
|
pR += 0.5f;
|
||||||
pR *= 255;
|
pR *= 255;
|
||||||
if (pR < 0) pR = 0;
|
if (pR < 0) pR = 0;
|
||||||
if (pR > 255) pR = 255;
|
if (pR > 255) pR = 255;
|
||||||
|
|
||||||
float pG = (float)pixels[y*image->width + x].g/255.0f;
|
float pG = (float)pixels[y*image->width + x].g/255.0f;
|
||||||
pG -= 0.5;
|
pG -= 0.5f;
|
||||||
pG *= contrast;
|
pG *= contrast;
|
||||||
pG += 0.5;
|
pG += 0.5f;
|
||||||
pG *= 255;
|
pG *= 255;
|
||||||
if (pG < 0) pG = 0;
|
if (pG < 0) pG = 0;
|
||||||
if (pG > 255) pG = 255;
|
if (pG > 255) pG = 255;
|
||||||
|
|
||||||
float pB = (float)pixels[y*image->width + x].b/255.0f;
|
float pB = (float)pixels[y*image->width + x].b/255.0f;
|
||||||
pB -= 0.5;
|
pB -= 0.5f;
|
||||||
pB *= contrast;
|
pB *= contrast;
|
||||||
pB += 0.5;
|
pB += 0.5f;
|
||||||
pB *= 255;
|
pB *= 255;
|
||||||
if (pB < 0) pB = 0;
|
if (pB < 0) pB = 0;
|
||||||
if (pB > 255) pB = 255;
|
if (pB > 255) pB = 255;
|
||||||
|
@ -2358,7 +2413,20 @@ Color GetImageColor(Image image, int x, int y)
|
||||||
// Clear image background with given color
|
// Clear image background with given color
|
||||||
void ImageClearBackground(Image *dst, Color color)
|
void ImageClearBackground(Image *dst, Color color)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < dst->width*dst->height; ++i) ImageDrawPixel(dst, i%dst->width, i/dst->width, color);
|
// Security check to avoid program crash
|
||||||
|
if ((dst->data == NULL) || (dst->width == 0) || (dst->height == 0)) return;
|
||||||
|
|
||||||
|
// Fill in first pixel based on image format
|
||||||
|
ImageDrawPixel(dst, 0, 0, color);
|
||||||
|
|
||||||
|
unsigned char *pSrcPixel = (unsigned char *)dst->data;
|
||||||
|
int bytesPerPixel = GetPixelDataSize(1, 1, dst->format);
|
||||||
|
|
||||||
|
// Repeat the first pixel data throughout the image
|
||||||
|
for (int i = 1; i < dst->width * dst->height; i++)
|
||||||
|
{
|
||||||
|
memcpy(pSrcPixel + i * bytesPerPixel, pSrcPixel, bytesPerPixel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw pixel within an image
|
// Draw pixel within an image
|
||||||
|
@ -2632,13 +2700,21 @@ void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color)
|
||||||
int ey = sy + (int)rec.height;
|
int ey = sy + (int)rec.height;
|
||||||
|
|
||||||
int sx = (int)rec.x;
|
int sx = (int)rec.x;
|
||||||
int ex = sx + (int)rec.width;
|
|
||||||
|
int bytesPerPixel = GetPixelDataSize(1, 1, dst->format);
|
||||||
|
|
||||||
for (int y = sy; y < ey; y++)
|
for (int y = sy; y < ey; y++)
|
||||||
{
|
{
|
||||||
for (int x = sx; x < ex; x++)
|
// Fill in the first pixel of the row based on image format
|
||||||
|
ImageDrawPixel(dst, sx, y, color);
|
||||||
|
|
||||||
|
int bytesOffset = ((y * dst->width) + sx) * bytesPerPixel;
|
||||||
|
unsigned char *pSrcPixel = (unsigned char *)dst->data + bytesOffset;
|
||||||
|
|
||||||
|
// Repeat the first pixel data throughout the row
|
||||||
|
for (int x = 1; x < (int)rec.width; x++)
|
||||||
{
|
{
|
||||||
ImageDrawPixel(dst, x, y, color);
|
memcpy(pSrcPixel + x * bytesPerPixel, pSrcPixel, bytesPerPixel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2716,6 +2792,9 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color
|
||||||
// [x] Consider fast path: no alpha blending required cases (src has no alpha)
|
// [x] Consider fast path: no alpha blending required cases (src has no alpha)
|
||||||
// [x] Consider fast path: same src/dst format with no alpha -> direct line copy
|
// [x] Consider fast path: same src/dst format with no alpha -> direct line copy
|
||||||
// [-] GetPixelColor(): Get Vector4 instead of Color, easier for ColorAlphaBlend()
|
// [-] GetPixelColor(): Get Vector4 instead of Color, easier for ColorAlphaBlend()
|
||||||
|
// [ ] Support f32bit channels drawing
|
||||||
|
|
||||||
|
// TODO: Support PIXELFORMAT_UNCOMPRESSED_R32, PIXELFORMAT_UNCOMPRESSED_R32G32B32, PIXELFORMAT_UNCOMPRESSED_R32G32B32A32
|
||||||
|
|
||||||
Color colSrc, colDst, blend;
|
Color colSrc, colDst, blend;
|
||||||
bool blendRequired = true;
|
bool blendRequired = true;
|
||||||
|
@ -2768,10 +2847,13 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color
|
||||||
// Draw text (default font) within an image (destination)
|
// Draw text (default font) within an image (destination)
|
||||||
void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color)
|
void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color)
|
||||||
{
|
{
|
||||||
|
#if defined(SUPPORT_MODULE_RTEXT)
|
||||||
Vector2 position = { (float)posX, (float)posY };
|
Vector2 position = { (float)posX, (float)posY };
|
||||||
|
// NOTE: For default font, spacing is set to desired font size / default font size (10)
|
||||||
// NOTE: For default font, sapcing is set to desired font size / default font size (10)
|
ImageDrawTextEx(dst, GetFontDefault(), text, position, (float)fontSize, (float)fontSize/10, color); // WARNING: Module required: rtext
|
||||||
ImageDrawTextEx(dst, GetFontDefault(), text, position, (float)fontSize, (float)fontSize/10, color);
|
#else
|
||||||
|
TRACELOG(LOG_WARNING, "IMAGE: ImageDrawText() requires module: rtext");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw text (custom sprite font) within an image (destination)
|
// Draw text (custom sprite font) within an image (destination)
|
||||||
|
@ -2812,7 +2894,7 @@ Texture2D LoadTextureFromImage(Image image)
|
||||||
{
|
{
|
||||||
Texture2D texture = { 0 };
|
Texture2D texture = { 0 };
|
||||||
|
|
||||||
if ((image.data != NULL) && (image.width != 0) && (image.height != 0))
|
if ((image.width != 0) && (image.height != 0))
|
||||||
{
|
{
|
||||||
texture.id = rlLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps);
|
texture.id = rlLoadTexture(image.data, image.width, image.height, image.format, image.mipmaps);
|
||||||
}
|
}
|
||||||
|
@ -2849,6 +2931,7 @@ TextureCubemap LoadTextureCubemap(Image image, int layout)
|
||||||
cubemap.height = cubemap.width;
|
cubemap.height = cubemap.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Layout provided or already auto-detected
|
||||||
if (layout != CUBEMAP_LAYOUT_AUTO_DETECT)
|
if (layout != CUBEMAP_LAYOUT_AUTO_DETECT)
|
||||||
{
|
{
|
||||||
int size = cubemap.width;
|
int size = cubemap.width;
|
||||||
|
@ -2859,8 +2942,7 @@ TextureCubemap LoadTextureCubemap(Image image, int layout)
|
||||||
|
|
||||||
if (layout == CUBEMAP_LAYOUT_LINE_VERTICAL)
|
if (layout == CUBEMAP_LAYOUT_LINE_VERTICAL)
|
||||||
{
|
{
|
||||||
faces = image;
|
faces = ImageCopy(image); // Image data already follows expected convention
|
||||||
for (int i = 0; i < 6; i++) faceRecs[i].y = (float)size*i;
|
|
||||||
}
|
}
|
||||||
else if (layout == CUBEMAP_LAYOUT_PANORAMA)
|
else if (layout == CUBEMAP_LAYOUT_PANORAMA)
|
||||||
{
|
{
|
||||||
|
@ -2894,10 +2976,12 @@ TextureCubemap LoadTextureCubemap(Image image, int layout)
|
||||||
ImageFormat(&faces, image.format);
|
ImageFormat(&faces, image.format);
|
||||||
|
|
||||||
// NOTE: Image formating does not work with compressed textures
|
// NOTE: Image formating does not work with compressed textures
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 6; i++) ImageDraw(&faces, image, faceRecs[i], (Rectangle){ 0, (float)size*i, (float)size, (float)size }, WHITE);
|
for (int i = 0; i < 6; i++) ImageDraw(&faces, image, faceRecs[i], (Rectangle){ 0, (float)size*i, (float)size, (float)size }, WHITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Cubemap data is expected to be provided as 6 images in a single data array,
|
||||||
|
// one after the other (that's a vertical image), following convention: +X, -X, +Y, -Y, +Z, -Z
|
||||||
cubemap.id = rlLoadTextureCubemap(faces.data, size, faces.format);
|
cubemap.id = rlLoadTextureCubemap(faces.data, size, faces.format);
|
||||||
if (cubemap.id == 0) TRACELOG(LOG_WARNING, "IMAGE: Failed to load cubemap image");
|
if (cubemap.id == 0) TRACELOG(LOG_WARNING, "IMAGE: Failed to load cubemap image");
|
||||||
|
|
||||||
|
@ -3071,6 +3155,7 @@ void SetTextureWrap(Texture2D texture, int wrap)
|
||||||
{
|
{
|
||||||
case TEXTURE_WRAP_REPEAT:
|
case TEXTURE_WRAP_REPEAT:
|
||||||
{
|
{
|
||||||
|
// NOTE: It only works if NPOT textures are supported, i.e. OpenGL ES 2.0 could not support it
|
||||||
rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_REPEAT);
|
rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_TEXTURE_WRAP_REPEAT);
|
||||||
rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_REPEAT);
|
rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_TEXTURE_WRAP_REPEAT);
|
||||||
} break;
|
} break;
|
||||||
|
@ -3132,6 +3217,8 @@ void DrawTextureRec(Texture2D texture, Rectangle source, Vector2 position, Color
|
||||||
// i.e tiling = { 1.0f, 1.0f } refers to all texture, offset = { 0.5f, 0.5f } moves texture origin to center
|
// i.e tiling = { 1.0f, 1.0f } refers to all texture, offset = { 0.5f, 0.5f } moves texture origin to center
|
||||||
void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint)
|
void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint)
|
||||||
{
|
{
|
||||||
|
// WARNING: This solution only works if TEXTURE_WRAP_REPEAT is supported,
|
||||||
|
// NPOT textures supported is required and OpenGL ES 2.0 could not support it
|
||||||
Rectangle source = { offset.x*texture.width, offset.y*texture.height, tiling.x*texture.width, tiling.y*texture.height };
|
Rectangle source = { offset.x*texture.width, offset.y*texture.height, tiling.x*texture.width, tiling.y*texture.height };
|
||||||
Vector2 origin = { 0.0f, 0.0f };
|
Vector2 origin = { 0.0f, 0.0f };
|
||||||
|
|
||||||
|
@ -3143,6 +3230,7 @@ void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangl
|
||||||
void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, float scale, Color tint)
|
void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, float scale, Color tint)
|
||||||
{
|
{
|
||||||
if ((texture.id <= 0) || (scale <= 0.0f)) return; // Wanna see a infinite loop?!...just delete this line!
|
if ((texture.id <= 0) || (scale <= 0.0f)) return; // Wanna see a infinite loop?!...just delete this line!
|
||||||
|
if ((source.width == 0) || (source.height == 0)) return;
|
||||||
|
|
||||||
int tileWidth = (int)(source.width*scale), tileHeight = (int)(source.height*scale);
|
int tileWidth = (int)(source.width*scale), tileHeight = (int)(source.height*scale);
|
||||||
if ((dest.width < tileWidth) && (dest.height < tileHeight))
|
if ((dest.width < tileWidth) && (dest.height < tileHeight))
|
||||||
|
@ -3406,6 +3494,8 @@ void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest,
|
||||||
coordD.x = (nPatchInfo.source.x + nPatchInfo.source.width)/width;
|
coordD.x = (nPatchInfo.source.x + nPatchInfo.source.width)/width;
|
||||||
coordD.y = (nPatchInfo.source.y + nPatchInfo.source.height)/height;
|
coordD.y = (nPatchInfo.source.y + nPatchInfo.source.height)/height;
|
||||||
|
|
||||||
|
rlCheckRenderBatchLimit(9 * 3 * 2); // Maxium number of verts that could happen
|
||||||
|
|
||||||
rlSetTexture(texture.id);
|
rlSetTexture(texture.id);
|
||||||
|
|
||||||
rlPushMatrix();
|
rlPushMatrix();
|
||||||
|
@ -3553,7 +3643,7 @@ void DrawTexturePoly(Texture2D texture, Vector2 center, Vector2 *points, Vector2
|
||||||
|
|
||||||
rlSetTexture(texture.id);
|
rlSetTexture(texture.id);
|
||||||
|
|
||||||
// Texturing is only supported on QUADs
|
// Texturing is only supported on RL_QUADS
|
||||||
rlBegin(RL_QUADS);
|
rlBegin(RL_QUADS);
|
||||||
|
|
||||||
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
|
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
|
||||||
|
@ -3721,10 +3811,10 @@ Color ColorAlphaBlend(Color dst, Color src, Color tint)
|
||||||
Color out = WHITE;
|
Color out = WHITE;
|
||||||
|
|
||||||
// Apply color tint to source color
|
// Apply color tint to source color
|
||||||
src.r = (unsigned char)(((unsigned int)src.r*(unsigned int)tint.r) >> 8);
|
src.r = (unsigned char)(((unsigned int)src.r*((unsigned int)tint.r+1)) >> 8);
|
||||||
src.g = (unsigned char)(((unsigned int)src.g*(unsigned int)tint.g) >> 8);
|
src.g = (unsigned char)(((unsigned int)src.g*((unsigned int)tint.g+1)) >> 8);
|
||||||
src.b = (unsigned char)(((unsigned int)src.b*(unsigned int)tint.b) >> 8);
|
src.b = (unsigned char)(((unsigned int)src.b*((unsigned int)tint.b+1)) >> 8);
|
||||||
src.a = (unsigned char)(((unsigned int)src.a*(unsigned int)tint.a) >> 8);
|
src.a = (unsigned char)(((unsigned int)src.a*((unsigned int)tint.a+1)) >> 8);
|
||||||
|
|
||||||
//#define COLORALPHABLEND_FLOAT
|
//#define COLORALPHABLEND_FLOAT
|
||||||
#define COLORALPHABLEND_INTEGERS
|
#define COLORALPHABLEND_INTEGERS
|
||||||
|
@ -4259,6 +4349,7 @@ static Image LoadPKM(const unsigned char *fileData, unsigned int fileSize)
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_KTX)
|
#if defined(SUPPORT_FILEFORMAT_KTX)
|
||||||
// Load KTX compressed image data (ETC1/ETC2 compression)
|
// Load KTX compressed image data (ETC1/ETC2 compression)
|
||||||
|
// TODO: Review KTX loading, many things changed!
|
||||||
static Image LoadKTX(const unsigned char *fileData, unsigned int fileSize)
|
static Image LoadKTX(const unsigned char *fileData, unsigned int fileSize)
|
||||||
{
|
{
|
||||||
unsigned char *fileDataPtr = (unsigned char *)fileData;
|
unsigned char *fileDataPtr = (unsigned char *)fileData;
|
||||||
|
@ -4333,6 +4424,8 @@ static Image LoadKTX(const unsigned char *fileData, unsigned int fileSize)
|
||||||
if (ktxHeader->glInternalFormat == 0x8D64) image.format = PIXELFORMAT_COMPRESSED_ETC1_RGB;
|
if (ktxHeader->glInternalFormat == 0x8D64) image.format = PIXELFORMAT_COMPRESSED_ETC1_RGB;
|
||||||
else if (ktxHeader->glInternalFormat == 0x9274) image.format = PIXELFORMAT_COMPRESSED_ETC2_RGB;
|
else if (ktxHeader->glInternalFormat == 0x9274) image.format = PIXELFORMAT_COMPRESSED_ETC2_RGB;
|
||||||
else if (ktxHeader->glInternalFormat == 0x9278) image.format = PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA;
|
else if (ktxHeader->glInternalFormat == 0x9278) image.format = PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA;
|
||||||
|
|
||||||
|
// TODO: Support uncompressed data formats? Right now it returns format = 0!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4341,11 +4434,12 @@ static Image LoadKTX(const unsigned char *fileData, unsigned int fileSize)
|
||||||
|
|
||||||
// Save image data as KTX file
|
// Save image data as KTX file
|
||||||
// NOTE: By default KTX 1.1 spec is used, 2.0 is still on draft (01Oct2018)
|
// NOTE: By default KTX 1.1 spec is used, 2.0 is still on draft (01Oct2018)
|
||||||
|
// TODO: Review KTX saving, many things changed!
|
||||||
static int SaveKTX(Image image, const char *fileName)
|
static int SaveKTX(Image image, const char *fileName)
|
||||||
{
|
{
|
||||||
// KTX file Header (64 bytes)
|
// KTX file Header (64 bytes)
|
||||||
// v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
|
// v1.1 - https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
|
||||||
// v2.0 - http://github.khronos.org/KTX-Specification/ - still on draft, not ready for implementation
|
// v2.0 - http://github.khronos.org/KTX-Specification/ - Final specs by 2021-04-18
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n" // KTX 2.0: "«KTX 22»\r\n\x1A\n"
|
char id[12]; // Identifier: "«KTX 11»\r\n\x1A\n" // KTX 2.0: "«KTX 22»\r\n\x1A\n"
|
||||||
unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04
|
unsigned int endianness; // Little endian: 0x01 0x02 0x03 0x04
|
||||||
|
@ -4480,7 +4574,7 @@ static Image LoadPVR(const unsigned char *fileData, unsigned int fileSize)
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
unsigned char channels[4]; // pixelFormat high part
|
unsigned char channels[4]; // pixelFormat high part
|
||||||
unsigned char channelDepth[4]; // pixelFormat low part
|
unsigned char channelDepth[4]; // pixelFormat low part
|
||||||
unsigned int colourSpace;
|
unsigned int colorSpace;
|
||||||
unsigned int channelType;
|
unsigned int channelType;
|
||||||
unsigned int height;
|
unsigned int height;
|
||||||
unsigned int width;
|
unsigned int width;
|
||||||
|
@ -4759,3 +4853,5 @@ static Vector4 *LoadImageDataNormalized(Image image)
|
||||||
|
|
||||||
return pixels;
|
return pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // SUPPORT_MODULE_RTEXTURES
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
*
|
*
|
||||||
* LICENSE: zlib/libpng
|
* LICENSE: zlib/libpng
|
||||||
*
|
*
|
||||||
* Copyright (c) 2014-2021 Ramon Santamaria (@raysan5)
|
* Copyright (c) 2014-2022 Ramon Santamaria (@raysan5)
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
* 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.
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -148,6 +148,7 @@ void TraceLog(int logType, const char *text, ...)
|
||||||
strcat(buffer, text);
|
strcat(buffer, text);
|
||||||
strcat(buffer, "\n");
|
strcat(buffer, "\n");
|
||||||
vprintf(buffer, args);
|
vprintf(buffer, args);
|
||||||
|
fflush(stdout);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
@ -268,6 +269,51 @@ bool SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite)
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Export data to code (.h), returns true on success
|
||||||
|
bool ExportDataAsCode(const char *data, unsigned int size, const char *fileName)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
#ifndef TEXT_BYTES_PER_LINE
|
||||||
|
#define TEXT_BYTES_PER_LINE 20
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// NOTE: Text data buffer size is estimated considering raw data size in bytes
|
||||||
|
// and requiring 6 char bytes for every byte: "0x00, "
|
||||||
|
char *txtData = (char *)RL_CALLOC(size*6 + 2000, sizeof(char));
|
||||||
|
|
||||||
|
int byteCount = 0;
|
||||||
|
byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// DataAsCode exporter v1.0 - Raw data exported as an array of bytes //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2022 Ramon Santamaria (@raysan5) //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||||
|
byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
|
||||||
|
|
||||||
|
// Get file name from path and convert variable name to uppercase
|
||||||
|
char varFileName[256] = { 0 };
|
||||||
|
strcpy(varFileName, GetFileNameWithoutExt(fileName));
|
||||||
|
for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; }
|
||||||
|
|
||||||
|
byteCount += sprintf(txtData + byteCount, "static unsigned char %s_DATA[%i] = { ", varFileName, size);
|
||||||
|
for (unsigned int i = 0; i < size - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), data[i]);
|
||||||
|
byteCount += sprintf(txtData + byteCount, "0x%x };\n", data[size - 1]);
|
||||||
|
|
||||||
|
// NOTE: Text data size exported is determined by '\0' (NULL) character
|
||||||
|
success = SaveFileText(fileName, txtData);
|
||||||
|
|
||||||
|
RL_FREE(txtData);
|
||||||
|
|
||||||
|
if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Data as code exported successfully", fileName);
|
||||||
|
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export data as code", fileName);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
// Load text data from file, returns a '\0' terminated string
|
// Load text data from file, returns a '\0' terminated string
|
||||||
// NOTE: text chars array should be freed manually
|
// NOTE: text chars array should be freed manually
|
||||||
char *LoadFileText(const char *fileName)
|
char *LoadFileText(const char *fileName)
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*
|
*
|
||||||
* LICENSE: zlib/libpng
|
* LICENSE: zlib/libpng
|
||||||
*
|
*
|
||||||
* Copyright (c) 2014-2021 Ramon Santamaria (@raysan5)
|
* Copyright (c) 2014-2022 Ramon Santamaria (@raysan5)
|
||||||
*
|
*
|
||||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
* 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.
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module Functions Declaration
|
// Module Functions Declaration
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
#ifdef __cplusplus
|
#if defined(__cplusplus)
|
||||||
extern "C" { // Prevents name mangling of functions
|
extern "C" { // Prevents name mangling of functions
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ void InitAssetManager(AAssetManager *manager, const char *dataPath); // Initia
|
||||||
FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen() -> Read-only!
|
FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen() -> Read-only!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue