commit
0677b256f1
38 changed files with 14000 additions and 4750 deletions
|
@ -59,6 +59,7 @@ You can also build binary in [MSYS2](https://msys2.github.io/) shell.
|
|||
* `opengl43` - uses OpenGL 4.3 backend
|
||||
* `opengl21` - uses OpenGL 2.1 backend (default is 3.3 on desktop)
|
||||
* `opengl11` - uses OpenGL 1.1 backend (pseudo OpenGL 1.1 style)
|
||||
* `angle` - uses OpenGL ES 2.0 backend (can be used to link against [Google's ANGLE](https://github.com/google/angle))
|
||||
|
||||
### Documentation
|
||||
|
||||
|
@ -69,10 +70,11 @@ Documentation on [GoDoc](https://godoc.org/github.com/gen2brain/raylib-go/raylib
|
|||
```go
|
||||
package main
|
||||
|
||||
import "github.com/gen2brain/raylib-go/raylib"
|
||||
import rl "github.com/gen2brain/raylib-go/raylib"
|
||||
|
||||
func main() {
|
||||
rl.InitWindow(800, 450, "raylib [core] example - basic window")
|
||||
defer rl.CloseWindow()
|
||||
rl.SetTargetFPS(60)
|
||||
|
||||
for !rl.WindowShouldClose() {
|
||||
|
@ -83,8 +85,6 @@ func main() {
|
|||
|
||||
rl.EndDrawing()
|
||||
}
|
||||
|
||||
rl.CloseWindow()
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -26,9 +26,10 @@ package rl
|
|||
#cgo darwin LDFLAGS: -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -framework CoreFoundation
|
||||
#cgo darwin CFLAGS: -x objective-c -Iexternal/glfw/include -D_GLFW_COCOA -D_GLFW_USE_CHDIR -D_GLFW_USE_MENUBAR -D_GLFW_USE_RETINA -Wno-deprecated-declarations -Wno-implicit-const-int-float-conversion -DPLATFORM_DESKTOP
|
||||
|
||||
#cgo darwin,opengl11 CFLAGS: -DGRAPHICS_API_OPENGL_11
|
||||
#cgo darwin,opengl21 CFLAGS: -DGRAPHICS_API_OPENGL_21
|
||||
#cgo darwin,opengl43 CFLAGS: -DGRAPHICS_API_OPENGL_43
|
||||
#cgo darwin,!opengl11,!opengl21,!opengl43 CFLAGS: -DGRAPHICS_API_OPENGL_33
|
||||
#cgo darwin,opengl11,!angle CFLAGS: -DGRAPHICS_API_OPENGL_11
|
||||
#cgo darwin,opengl21,!angle CFLAGS: -DGRAPHICS_API_OPENGL_21
|
||||
#cgo darwin,opengl43,!angle CFLAGS: -DGRAPHICS_API_OPENGL_43
|
||||
#cgo darwin,!opengl11,!opengl21,!opengl43,!angle CFLAGS: -DGRAPHICS_API_OPENGL_33
|
||||
#cgo darwin,angle CFLAGS: -DGRAPHICS_API_OPENGL_ES2
|
||||
*/
|
||||
import "C"
|
||||
|
|
|
@ -42,9 +42,10 @@ package rl
|
|||
#cgo freebsd,!wayland CFLAGS: -D_GLFW_X11
|
||||
#cgo freebsd,wayland CFLAGS: -D_GLFW_WAYLAND
|
||||
|
||||
#cgo freebsd,opengl11 CFLAGS: -DGRAPHICS_API_OPENGL_11
|
||||
#cgo freebsd,opengl21 CFLAGS: -DGRAPHICS_API_OPENGL_21
|
||||
#cgo freebsd,opengl43 CFLAGS: -DGRAPHICS_API_OPENGL_43
|
||||
#cgo freebsd,!opengl11,!opengl21,!opengl43 CFLAGS: -DGRAPHICS_API_OPENGL_33
|
||||
#cgo freebsd,opengl11,!angle CFLAGS: -DGRAPHICS_API_OPENGL_11
|
||||
#cgo freebsd,opengl21,!angle CFLAGS: -DGRAPHICS_API_OPENGL_21
|
||||
#cgo freebsd,opengl43,!angle CFLAGS: -DGRAPHICS_API_OPENGL_43
|
||||
#cgo freebsd,!opengl11,!opengl21,!opengl43,!angle CFLAGS: -DGRAPHICS_API_OPENGL_33
|
||||
#cgo freebsd,angle CFLAGS: -DGRAPHICS_API_OPENGL_ES2
|
||||
*/
|
||||
import "C"
|
||||
|
|
|
@ -41,9 +41,10 @@ package rl
|
|||
#cgo linux,!wayland CFLAGS: -D_GLFW_X11
|
||||
#cgo linux,wayland CFLAGS: -D_GLFW_WAYLAND
|
||||
|
||||
#cgo linux,opengl11 CFLAGS: -DGRAPHICS_API_OPENGL_11
|
||||
#cgo linux,opengl21 CFLAGS: -DGRAPHICS_API_OPENGL_21
|
||||
#cgo linux,opengl43 CFLAGS: -DGRAPHICS_API_OPENGL_43
|
||||
#cgo linux,!opengl11,!opengl21,!opengl43 CFLAGS: -DGRAPHICS_API_OPENGL_33
|
||||
#cgo linux,opengl11,!angle CFLAGS: -DGRAPHICS_API_OPENGL_11
|
||||
#cgo linux,opengl21,!angle CFLAGS: -DGRAPHICS_API_OPENGL_21
|
||||
#cgo linux,opengl43,!angle CFLAGS: -DGRAPHICS_API_OPENGL_43
|
||||
#cgo linux,!opengl11,!opengl21,!opengl43,!angle CFLAGS: -DGRAPHICS_API_OPENGL_33
|
||||
#cgo linux,angle CFLAGS: -DGRAPHICS_API_OPENGL_ES2
|
||||
*/
|
||||
import "C"
|
||||
|
|
|
@ -42,9 +42,10 @@ package rl
|
|||
#cgo openbsd,!wayland CFLAGS: -D_GLFW_X11
|
||||
#cgo openbsd,wayland CFLAGS: -D_GLFW_WAYLAND
|
||||
|
||||
#cgo openbsd,opengl11 CFLAGS: -DGRAPHICS_API_OPENGL_11
|
||||
#cgo openbsd,opengl21 CFLAGS: -DGRAPHICS_API_OPENGL_21
|
||||
#cgo openbsd,opengl43 CFLAGS: -DGRAPHICS_API_OPENGL_43
|
||||
#cgo openbsd,!opengl11,!opengl21,!opengl43 CFLAGS: -DGRAPHICS_API_OPENGL_33
|
||||
#cgo openbsd,opengl11,!angle CFLAGS: -DGRAPHICS_API_OPENGL_11
|
||||
#cgo openbsd,opengl21,!angle CFLAGS: -DGRAPHICS_API_OPENGL_21
|
||||
#cgo openbsd,opengl43,!angle CFLAGS: -DGRAPHICS_API_OPENGL_43
|
||||
#cgo openbsd,!opengl11,!opengl21,!opengl43,!angle CFLAGS: -DGRAPHICS_API_OPENGL_33
|
||||
#cgo openbsd,angle CFLAGS: -DGRAPHICS_API_OPENGL_ES2
|
||||
*/
|
||||
import "C"
|
||||
|
|
|
@ -26,9 +26,10 @@ package rl
|
|||
#cgo windows LDFLAGS: -lopengl32 -lgdi32 -lwinmm -lole32
|
||||
#cgo windows CFLAGS: -D_GLFW_WIN32 -Iexternal -Iexternal/glfw/include -Iexternal/glfw/deps/mingw -DPLATFORM_DESKTOP
|
||||
|
||||
#cgo windows,opengl11 CFLAGS: -DGRAPHICS_API_OPENGL_11
|
||||
#cgo windows,opengl21 CFLAGS: -DGRAPHICS_API_OPENGL_21
|
||||
#cgo windows,opengl43 CFLAGS: -DGRAPHICS_API_OPENGL_43
|
||||
#cgo windows,!opengl11,!opengl21,!opengl43 CFLAGS: -DGRAPHICS_API_OPENGL_33
|
||||
#cgo windows,opengl11,!angle CFLAGS: -DGRAPHICS_API_OPENGL_11
|
||||
#cgo windows,opengl21,!angle CFLAGS: -DGRAPHICS_API_OPENGL_21
|
||||
#cgo windows,opengl43,!angle CFLAGS: -DGRAPHICS_API_OPENGL_43
|
||||
#cgo windows,!opengl11,!opengl21,!opengl43,!angle CFLAGS: -DGRAPHICS_API_OPENGL_33
|
||||
#cgo windows,angle CFLAGS: -DGRAPHICS_API_OPENGL_ES2
|
||||
*/
|
||||
import "C"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
* LICENSE: zlib/libpng
|
||||
*
|
||||
* Copyright (c) 2018-2022 Ahmad Fatoum & Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2018-2023 Ahmad Fatoum & Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||
* will the authors be held liable for any damages arising from the use of this software.
|
||||
|
@ -25,6 +25,9 @@
|
|||
*
|
||||
**********************************************************************************************/
|
||||
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Module selection - Some modules could be avoided
|
||||
// Mandatory modules: rcore, rlgl, utils
|
||||
|
@ -49,7 +52,7 @@
|
|||
// Setting a higher resolution can improve the accuracy of time-out intervals in wait functions.
|
||||
// However, it can also reduce overall system performance, because the thread scheduler switches tasks more often.
|
||||
#define SUPPORT_WINMM_HIGHRES_TIMER 1
|
||||
// Use busy wait loop for timing sync, if not defined, a high-resolution timer is setup and used
|
||||
// Use busy wait loop for timing sync, if not defined, a high-resolution timer is set up and used
|
||||
//#define SUPPORT_BUSY_WAIT_LOOP 1
|
||||
// Use a partial-busy wait loop, in this case frame sleeps for most of the time, but then runs a busy loop at the end for accuracy
|
||||
#define SUPPORT_PARTIALBUSY_WAIT_LOOP
|
||||
|
@ -64,7 +67,7 @@
|
|||
// Support automatic generated events, loading and recording of those events when required
|
||||
//#define SUPPORT_EVENTS_AUTOMATION 1
|
||||
// Support custom frame control, only for advance users
|
||||
// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timming + PollInputEvents()
|
||||
// By default EndDrawing() does this job: draws everything + SwapScreenBuffer() + manage frame timing + PollInputEvents()
|
||||
// Enabling this flag allows manual control of the frame processes, use at your own risk
|
||||
//#define SUPPORT_CUSTOM_FRAME_CONTROL 1
|
||||
|
||||
|
@ -109,12 +112,12 @@
|
|||
|
||||
// Default shader vertex attribute names to set location points
|
||||
// NOTE: When a new shader is loaded, the following locations are tried to be set for convenience
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Binded by default to shader location: 0
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: 0
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: 1
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: 2
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: 3
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: 4
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: 5
|
||||
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
|
||||
#define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix
|
||||
|
@ -138,7 +141,7 @@
|
|||
//------------------------------------------------------------------------------------
|
||||
// Module: rtextures - Configuration Flags
|
||||
//------------------------------------------------------------------------------------
|
||||
// Selecte desired fileformats to be supported for image data loading
|
||||
// Select the desired fileformats to be supported for image data loading
|
||||
#define SUPPORT_FILEFORMAT_PNG 1
|
||||
#define SUPPORT_FILEFORMAT_BMP 1
|
||||
//#define SUPPORT_FILEFORMAT_TGA 1
|
||||
|
@ -148,6 +151,8 @@
|
|||
//#define SUPPORT_FILEFORMAT_PSD 1
|
||||
#define SUPPORT_FILEFORMAT_DDS 1
|
||||
#define SUPPORT_FILEFORMAT_HDR 1
|
||||
//#define SUPPORT_FILEFORMAT_PIC 1
|
||||
//#define SUPPORT_FILEFORMAT_PNM 1
|
||||
//#define SUPPORT_FILEFORMAT_KTX 1
|
||||
//#define SUPPORT_FILEFORMAT_ASTC 1
|
||||
//#define SUPPORT_FILEFORMAT_PKM 1
|
||||
|
@ -208,10 +213,11 @@
|
|||
// Desired audio fileformats to be supported for loading
|
||||
#define SUPPORT_FILEFORMAT_WAV 1
|
||||
#define SUPPORT_FILEFORMAT_OGG 1
|
||||
#define SUPPORT_FILEFORMAT_MP3 1
|
||||
#define SUPPORT_FILEFORMAT_QOA 1
|
||||
//#define SUPPORT_FILEFORMAT_FLAC 1
|
||||
#define SUPPORT_FILEFORMAT_XM 1
|
||||
#define SUPPORT_FILEFORMAT_MOD 1
|
||||
#define SUPPORT_FILEFORMAT_MP3 1
|
||||
//#define SUPPORT_FILEFORMAT_FLAC 1
|
||||
|
||||
// raudio: Configuration values
|
||||
//------------------------------------------------------------------------------------
|
||||
|
@ -225,7 +231,7 @@
|
|||
// Module: utils - Configuration Flags
|
||||
//------------------------------------------------------------------------------------
|
||||
// Standard file io library (stdio.h) included
|
||||
#define SUPPORT_STANDARD_FILEIO
|
||||
#define SUPPORT_STANDARD_FILEIO 1
|
||||
// Show TRACELOG() output messages
|
||||
// NOTE: By default LOG_DEBUG traces not shown
|
||||
#define SUPPORT_TRACELOG 1
|
||||
|
@ -233,4 +239,6 @@
|
|||
|
||||
// utils: Configuration values
|
||||
//------------------------------------------------------------------------------------
|
||||
#define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message
|
||||
#define MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message
|
||||
|
||||
#endif // CONFIG_H
|
||||
|
|
265
raylib/external/cgltf.h
vendored
265
raylib/external/cgltf.h
vendored
|
@ -1,7 +1,7 @@
|
|||
/**
|
||||
* cgltf - a single-file glTF 2.0 parser written in C99.
|
||||
*
|
||||
* Version: 1.12
|
||||
* Version: 1.13
|
||||
*
|
||||
* Website: https://github.com/jkuhlmann/cgltf
|
||||
*
|
||||
|
@ -80,19 +80,16 @@
|
|||
* `cgltf_accessor_read_index` is similar to its floating-point counterpart, but it returns size_t
|
||||
* and only works with single-component data types.
|
||||
*
|
||||
* `cgltf_result cgltf_copy_extras_json(const cgltf_data*, const cgltf_extras*,
|
||||
* char* dest, cgltf_size* dest_size)` allows users to retrieve the "extras" data that
|
||||
* can be attached to many glTF objects (which can be arbitrary JSON data). The
|
||||
* `cgltf_extras` struct stores the offsets of the start and end of the extras JSON data
|
||||
* as it appears in the complete glTF JSON data. This function copies the extras data
|
||||
* into the provided buffer. If `dest` is NULL, the length of the data is written into
|
||||
* `dest_size`. You can then parse this data using your own JSON parser
|
||||
* `cgltf_copy_extras_json` allows users to retrieve the "extras" data that can be attached to many
|
||||
* glTF objects (which can be arbitrary JSON data). This is a legacy function, consider using
|
||||
* cgltf_extras::data directly instead. You can parse this data using your own JSON parser
|
||||
* or, if you've included the cgltf implementation using the integrated JSMN JSON parser.
|
||||
*/
|
||||
#ifndef CGLTF_H_INCLUDED__
|
||||
#define CGLTF_H_INCLUDED__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h> /* For uint8_t, uint32_t */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -256,8 +253,10 @@ typedef enum cgltf_data_free_method {
|
|||
} cgltf_data_free_method;
|
||||
|
||||
typedef struct cgltf_extras {
|
||||
cgltf_size start_offset;
|
||||
cgltf_size end_offset;
|
||||
cgltf_size start_offset; /* this field is deprecated and will be removed in the future; use data instead */
|
||||
cgltf_size end_offset; /* this field is deprecated and will be removed in the future; use data instead */
|
||||
|
||||
char* data;
|
||||
} cgltf_extras;
|
||||
|
||||
typedef struct cgltf_extension {
|
||||
|
@ -432,8 +431,6 @@ typedef struct cgltf_pbr_metallic_roughness
|
|||
cgltf_float base_color_factor[4];
|
||||
cgltf_float metallic_factor;
|
||||
cgltf_float roughness_factor;
|
||||
|
||||
cgltf_extras extras;
|
||||
} cgltf_pbr_metallic_roughness;
|
||||
|
||||
typedef struct cgltf_pbr_specular_glossiness
|
||||
|
@ -833,6 +830,8 @@ void cgltf_free(cgltf_data* data);
|
|||
void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix);
|
||||
void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix);
|
||||
|
||||
const uint8_t* cgltf_buffer_view_data(const cgltf_buffer_view* view);
|
||||
|
||||
cgltf_bool cgltf_accessor_read_float(const cgltf_accessor* accessor, cgltf_size index, cgltf_float* out, cgltf_size element_size);
|
||||
cgltf_bool cgltf_accessor_read_uint(const cgltf_accessor* accessor, cgltf_size index, cgltf_uint* out, cgltf_size element_size);
|
||||
cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size index);
|
||||
|
@ -841,6 +840,7 @@ cgltf_size cgltf_num_components(cgltf_type type);
|
|||
|
||||
cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_float* out, cgltf_size float_count);
|
||||
|
||||
/* this function is deprecated and will be removed in the future; use cgltf_extras::data instead */
|
||||
cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras* extras, char* dest, cgltf_size* dest_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -863,7 +863,6 @@ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras*
|
|||
|
||||
#ifdef CGLTF_IMPLEMENTATION
|
||||
|
||||
#include <stdint.h> /* For uint8_t, uint32_t */
|
||||
#include <string.h> /* For strncpy */
|
||||
#include <stdio.h> /* For fopen */
|
||||
#include <limits.h> /* For UINT_MAX etc */
|
||||
|
@ -905,15 +904,15 @@ enum jsmnerr {
|
|||
};
|
||||
typedef struct {
|
||||
jsmntype_t type;
|
||||
int start;
|
||||
int end;
|
||||
ptrdiff_t start;
|
||||
ptrdiff_t end;
|
||||
int size;
|
||||
#ifdef JSMN_PARENT_LINKS
|
||||
int parent;
|
||||
#endif
|
||||
} jsmntok_t;
|
||||
typedef struct {
|
||||
unsigned int pos; /* offset in the JSON string */
|
||||
size_t pos; /* offset in the JSON string */
|
||||
unsigned int toknext; /* next token to allocate */
|
||||
int toksuper; /* superior token node, e.g parent object or array */
|
||||
} jsmn_parser;
|
||||
|
@ -924,12 +923,15 @@ static int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t
|
|||
*/
|
||||
|
||||
|
||||
#ifndef CGLTF_CONSTS
|
||||
static const cgltf_size GlbHeaderSize = 12;
|
||||
static const cgltf_size GlbChunkHeaderSize = 8;
|
||||
static const uint32_t GlbVersion = 2;
|
||||
static const uint32_t GlbMagic = 0x46546C67;
|
||||
static const uint32_t GlbMagicJsonChunk = 0x4E4F534A;
|
||||
static const uint32_t GlbMagicBinChunk = 0x004E4942;
|
||||
#define CGLTF_CONSTS
|
||||
#endif
|
||||
|
||||
#ifndef CGLTF_MALLOC
|
||||
#define CGLTF_MALLOC(size) malloc(size)
|
||||
|
@ -1745,7 +1747,12 @@ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras*
|
|||
return cgltf_result_success;
|
||||
}
|
||||
|
||||
void cgltf_free_extensions(cgltf_data* data, cgltf_extension* extensions, cgltf_size extensions_count)
|
||||
static void cgltf_free_extras(cgltf_data* data, cgltf_extras* extras)
|
||||
{
|
||||
data->memory.free_func(data->memory.user_data, extras->data);
|
||||
}
|
||||
|
||||
static void cgltf_free_extensions(cgltf_data* data, cgltf_extension* extensions, cgltf_size extensions_count)
|
||||
{
|
||||
for (cgltf_size i = 0; i < extensions_count; ++i)
|
||||
{
|
||||
|
@ -1755,6 +1762,12 @@ void cgltf_free_extensions(cgltf_data* data, cgltf_extension* extensions, cgltf_
|
|||
data->memory.free_func(data->memory.user_data, extensions);
|
||||
}
|
||||
|
||||
static void cgltf_free_texture_view(cgltf_data* data, cgltf_texture_view* view)
|
||||
{
|
||||
cgltf_free_extensions(data, view->extensions, view->extensions_count);
|
||||
cgltf_free_extras(data, &view->extras);
|
||||
}
|
||||
|
||||
void cgltf_free(cgltf_data* data)
|
||||
{
|
||||
if (!data)
|
||||
|
@ -1770,6 +1783,7 @@ void cgltf_free(cgltf_data* data)
|
|||
data->memory.free_func(data->memory.user_data, data->asset.min_version);
|
||||
|
||||
cgltf_free_extensions(data, data->asset.extensions, data->asset.extensions_count);
|
||||
cgltf_free_extras(data, &data->asset.extras);
|
||||
|
||||
for (cgltf_size i = 0; i < data->accessors_count; ++i)
|
||||
{
|
||||
|
@ -1780,8 +1794,12 @@ void cgltf_free(cgltf_data* data)
|
|||
cgltf_free_extensions(data, data->accessors[i].sparse.extensions, data->accessors[i].sparse.extensions_count);
|
||||
cgltf_free_extensions(data, data->accessors[i].sparse.indices_extensions, data->accessors[i].sparse.indices_extensions_count);
|
||||
cgltf_free_extensions(data, data->accessors[i].sparse.values_extensions, data->accessors[i].sparse.values_extensions_count);
|
||||
cgltf_free_extras(data, &data->accessors[i].sparse.extras);
|
||||
cgltf_free_extras(data, &data->accessors[i].sparse.indices_extras);
|
||||
cgltf_free_extras(data, &data->accessors[i].sparse.values_extras);
|
||||
}
|
||||
cgltf_free_extensions(data, data->accessors[i].extensions, data->accessors[i].extensions_count);
|
||||
cgltf_free_extras(data, &data->accessors[i].extras);
|
||||
}
|
||||
data->memory.free_func(data->memory.user_data, data->accessors);
|
||||
|
||||
|
@ -1791,6 +1809,7 @@ void cgltf_free(cgltf_data* data)
|
|||
data->memory.free_func(data->memory.user_data, data->buffer_views[i].data);
|
||||
|
||||
cgltf_free_extensions(data, data->buffer_views[i].extensions, data->buffer_views[i].extensions_count);
|
||||
cgltf_free_extras(data, &data->buffer_views[i].extras);
|
||||
}
|
||||
data->memory.free_func(data->memory.user_data, data->buffer_views);
|
||||
|
||||
|
@ -1810,8 +1829,8 @@ void cgltf_free(cgltf_data* data)
|
|||
data->memory.free_func(data->memory.user_data, data->buffers[i].uri);
|
||||
|
||||
cgltf_free_extensions(data, data->buffers[i].extensions, data->buffers[i].extensions_count);
|
||||
cgltf_free_extras(data, &data->buffers[i].extras);
|
||||
}
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->buffers);
|
||||
|
||||
for (cgltf_size i = 0; i < data->meshes_count; ++i)
|
||||
|
@ -1849,9 +1868,15 @@ void cgltf_free(cgltf_data* data)
|
|||
data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].draco_mesh_compression.attributes);
|
||||
}
|
||||
|
||||
for (cgltf_size k = 0; k < data->meshes[i].primitives[j].mappings_count; ++k)
|
||||
{
|
||||
cgltf_free_extras(data, &data->meshes[i].primitives[j].mappings[k].extras);
|
||||
}
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->meshes[i].primitives[j].mappings);
|
||||
|
||||
cgltf_free_extensions(data, data->meshes[i].primitives[j].extensions, data->meshes[i].primitives[j].extensions_count);
|
||||
cgltf_free_extras(data, &data->meshes[i].primitives[j].extras);
|
||||
}
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->meshes[i].primitives);
|
||||
|
@ -1863,6 +1888,7 @@ void cgltf_free(cgltf_data* data)
|
|||
}
|
||||
|
||||
cgltf_free_extensions(data, data->meshes[i].extensions, data->meshes[i].extensions_count);
|
||||
cgltf_free_extras(data, &data->meshes[i].extras);
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->meshes[i].target_names);
|
||||
}
|
||||
|
@ -1875,49 +1901,50 @@ void cgltf_free(cgltf_data* data)
|
|||
|
||||
if(data->materials[i].has_pbr_metallic_roughness)
|
||||
{
|
||||
cgltf_free_extensions(data, data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.extensions, data->materials[i].pbr_metallic_roughness.metallic_roughness_texture.extensions_count);
|
||||
cgltf_free_extensions(data, data->materials[i].pbr_metallic_roughness.base_color_texture.extensions, data->materials[i].pbr_metallic_roughness.base_color_texture.extensions_count);
|
||||
cgltf_free_texture_view(data, &data->materials[i].pbr_metallic_roughness.metallic_roughness_texture);
|
||||
cgltf_free_texture_view(data, &data->materials[i].pbr_metallic_roughness.base_color_texture);
|
||||
}
|
||||
if(data->materials[i].has_pbr_specular_glossiness)
|
||||
{
|
||||
cgltf_free_extensions(data, data->materials[i].pbr_specular_glossiness.diffuse_texture.extensions, data->materials[i].pbr_specular_glossiness.diffuse_texture.extensions_count);
|
||||
cgltf_free_extensions(data, data->materials[i].pbr_specular_glossiness.specular_glossiness_texture.extensions, data->materials[i].pbr_specular_glossiness.specular_glossiness_texture.extensions_count);
|
||||
cgltf_free_texture_view(data, &data->materials[i].pbr_specular_glossiness.diffuse_texture);
|
||||
cgltf_free_texture_view(data, &data->materials[i].pbr_specular_glossiness.specular_glossiness_texture);
|
||||
}
|
||||
if(data->materials[i].has_clearcoat)
|
||||
{
|
||||
cgltf_free_extensions(data, data->materials[i].clearcoat.clearcoat_texture.extensions, data->materials[i].clearcoat.clearcoat_texture.extensions_count);
|
||||
cgltf_free_extensions(data, data->materials[i].clearcoat.clearcoat_roughness_texture.extensions, data->materials[i].clearcoat.clearcoat_roughness_texture.extensions_count);
|
||||
cgltf_free_extensions(data, data->materials[i].clearcoat.clearcoat_normal_texture.extensions, data->materials[i].clearcoat.clearcoat_normal_texture.extensions_count);
|
||||
cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_texture);
|
||||
cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_roughness_texture);
|
||||
cgltf_free_texture_view(data, &data->materials[i].clearcoat.clearcoat_normal_texture);
|
||||
}
|
||||
if(data->materials[i].has_specular)
|
||||
{
|
||||
cgltf_free_extensions(data, data->materials[i].specular.specular_texture.extensions, data->materials[i].specular.specular_texture.extensions_count);
|
||||
cgltf_free_extensions(data, data->materials[i].specular.specular_color_texture.extensions, data->materials[i].specular.specular_color_texture.extensions_count);
|
||||
cgltf_free_texture_view(data, &data->materials[i].specular.specular_texture);
|
||||
cgltf_free_texture_view(data, &data->materials[i].specular.specular_color_texture);
|
||||
}
|
||||
if(data->materials[i].has_transmission)
|
||||
{
|
||||
cgltf_free_extensions(data, data->materials[i].transmission.transmission_texture.extensions, data->materials[i].transmission.transmission_texture.extensions_count);
|
||||
cgltf_free_texture_view(data, &data->materials[i].transmission.transmission_texture);
|
||||
}
|
||||
if (data->materials[i].has_volume)
|
||||
{
|
||||
cgltf_free_extensions(data, data->materials[i].volume.thickness_texture.extensions, data->materials[i].volume.thickness_texture.extensions_count);
|
||||
cgltf_free_texture_view(data, &data->materials[i].volume.thickness_texture);
|
||||
}
|
||||
if(data->materials[i].has_sheen)
|
||||
{
|
||||
cgltf_free_extensions(data, data->materials[i].sheen.sheen_color_texture.extensions, data->materials[i].sheen.sheen_color_texture.extensions_count);
|
||||
cgltf_free_extensions(data, data->materials[i].sheen.sheen_roughness_texture.extensions, data->materials[i].sheen.sheen_roughness_texture.extensions_count);
|
||||
cgltf_free_texture_view(data, &data->materials[i].sheen.sheen_color_texture);
|
||||
cgltf_free_texture_view(data, &data->materials[i].sheen.sheen_roughness_texture);
|
||||
}
|
||||
if(data->materials[i].has_iridescence)
|
||||
{
|
||||
cgltf_free_extensions(data, data->materials[i].iridescence.iridescence_texture.extensions, data->materials[i].iridescence.iridescence_texture.extensions_count);
|
||||
cgltf_free_extensions(data, data->materials[i].iridescence.iridescence_thickness_texture.extensions, data->materials[i].iridescence.iridescence_thickness_texture.extensions_count);
|
||||
cgltf_free_texture_view(data, &data->materials[i].iridescence.iridescence_texture);
|
||||
cgltf_free_texture_view(data, &data->materials[i].iridescence.iridescence_thickness_texture);
|
||||
}
|
||||
|
||||
cgltf_free_extensions(data, data->materials[i].normal_texture.extensions, data->materials[i].normal_texture.extensions_count);
|
||||
cgltf_free_extensions(data, data->materials[i].occlusion_texture.extensions, data->materials[i].occlusion_texture.extensions_count);
|
||||
cgltf_free_extensions(data, data->materials[i].emissive_texture.extensions, data->materials[i].emissive_texture.extensions_count);
|
||||
cgltf_free_texture_view(data, &data->materials[i].normal_texture);
|
||||
cgltf_free_texture_view(data, &data->materials[i].occlusion_texture);
|
||||
cgltf_free_texture_view(data, &data->materials[i].emissive_texture);
|
||||
|
||||
cgltf_free_extensions(data, data->materials[i].extensions, data->materials[i].extensions_count);
|
||||
cgltf_free_extras(data, &data->materials[i].extras);
|
||||
}
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->materials);
|
||||
|
@ -1929,6 +1956,7 @@ void cgltf_free(cgltf_data* data)
|
|||
data->memory.free_func(data->memory.user_data, data->images[i].mime_type);
|
||||
|
||||
cgltf_free_extensions(data, data->images[i].extensions, data->images[i].extensions_count);
|
||||
cgltf_free_extras(data, &data->images[i].extras);
|
||||
}
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->images);
|
||||
|
@ -1936,7 +1964,9 @@ void cgltf_free(cgltf_data* data)
|
|||
for (cgltf_size i = 0; i < data->textures_count; ++i)
|
||||
{
|
||||
data->memory.free_func(data->memory.user_data, data->textures[i].name);
|
||||
|
||||
cgltf_free_extensions(data, data->textures[i].extensions, data->textures[i].extensions_count);
|
||||
cgltf_free_extras(data, &data->textures[i].extras);
|
||||
}
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->textures);
|
||||
|
@ -1944,7 +1974,9 @@ void cgltf_free(cgltf_data* data)
|
|||
for (cgltf_size i = 0; i < data->samplers_count; ++i)
|
||||
{
|
||||
data->memory.free_func(data->memory.user_data, data->samplers[i].name);
|
||||
|
||||
cgltf_free_extensions(data, data->samplers[i].extensions, data->samplers[i].extensions_count);
|
||||
cgltf_free_extras(data, &data->samplers[i].extras);
|
||||
}
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->samplers);
|
||||
|
@ -1955,6 +1987,7 @@ void cgltf_free(cgltf_data* data)
|
|||
data->memory.free_func(data->memory.user_data, data->skins[i].joints);
|
||||
|
||||
cgltf_free_extensions(data, data->skins[i].extensions, data->skins[i].extensions_count);
|
||||
cgltf_free_extras(data, &data->skins[i].extras);
|
||||
}
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->skins);
|
||||
|
@ -1962,7 +1995,18 @@ void cgltf_free(cgltf_data* data)
|
|||
for (cgltf_size i = 0; i < data->cameras_count; ++i)
|
||||
{
|
||||
data->memory.free_func(data->memory.user_data, data->cameras[i].name);
|
||||
|
||||
if (data->cameras[i].type == cgltf_camera_type_perspective)
|
||||
{
|
||||
cgltf_free_extras(data, &data->cameras[i].data.perspective.extras);
|
||||
}
|
||||
else if (data->cameras[i].type == cgltf_camera_type_orthographic)
|
||||
{
|
||||
cgltf_free_extras(data, &data->cameras[i].data.orthographic.extras);
|
||||
}
|
||||
|
||||
cgltf_free_extensions(data, data->cameras[i].extensions, data->cameras[i].extensions_count);
|
||||
cgltf_free_extras(data, &data->cameras[i].extras);
|
||||
}
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->cameras);
|
||||
|
@ -1970,6 +2014,8 @@ void cgltf_free(cgltf_data* data)
|
|||
for (cgltf_size i = 0; i < data->lights_count; ++i)
|
||||
{
|
||||
data->memory.free_func(data->memory.user_data, data->lights[i].name);
|
||||
|
||||
cgltf_free_extras(data, &data->lights[i].extras);
|
||||
}
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->lights);
|
||||
|
@ -1979,7 +2025,19 @@ void cgltf_free(cgltf_data* data)
|
|||
data->memory.free_func(data->memory.user_data, data->nodes[i].name);
|
||||
data->memory.free_func(data->memory.user_data, data->nodes[i].children);
|
||||
data->memory.free_func(data->memory.user_data, data->nodes[i].weights);
|
||||
|
||||
if (data->nodes[i].has_mesh_gpu_instancing)
|
||||
{
|
||||
for (cgltf_size j = 0; j < data->nodes[i].mesh_gpu_instancing.attributes_count; ++j)
|
||||
{
|
||||
data->memory.free_func(data->memory.user_data, data->nodes[i].mesh_gpu_instancing.attributes[j].name);
|
||||
}
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->nodes[i].mesh_gpu_instancing.attributes);
|
||||
}
|
||||
|
||||
cgltf_free_extensions(data, data->nodes[i].extensions, data->nodes[i].extensions_count);
|
||||
cgltf_free_extras(data, &data->nodes[i].extras);
|
||||
}
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->nodes);
|
||||
|
@ -1990,6 +2048,7 @@ void cgltf_free(cgltf_data* data)
|
|||
data->memory.free_func(data->memory.user_data, data->scenes[i].nodes);
|
||||
|
||||
cgltf_free_extensions(data, data->scenes[i].extensions, data->scenes[i].extensions_count);
|
||||
cgltf_free_extras(data, &data->scenes[i].extras);
|
||||
}
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->scenes);
|
||||
|
@ -2000,16 +2059,19 @@ void cgltf_free(cgltf_data* data)
|
|||
for (cgltf_size j = 0; j < data->animations[i].samplers_count; ++j)
|
||||
{
|
||||
cgltf_free_extensions(data, data->animations[i].samplers[j].extensions, data->animations[i].samplers[j].extensions_count);
|
||||
cgltf_free_extras(data, &data->animations[i].samplers[j].extras);
|
||||
}
|
||||
data->memory.free_func(data->memory.user_data, data->animations[i].samplers);
|
||||
|
||||
for (cgltf_size j = 0; j < data->animations[i].channels_count; ++j)
|
||||
{
|
||||
cgltf_free_extensions(data, data->animations[i].channels[j].extensions, data->animations[i].channels[j].extensions_count);
|
||||
cgltf_free_extras(data, &data->animations[i].channels[j].extras);
|
||||
}
|
||||
data->memory.free_func(data->memory.user_data, data->animations[i].channels);
|
||||
|
||||
cgltf_free_extensions(data, data->animations[i].extensions, data->animations[i].extensions_count);
|
||||
cgltf_free_extras(data, &data->animations[i].extras);
|
||||
}
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->animations);
|
||||
|
@ -2017,11 +2079,14 @@ void cgltf_free(cgltf_data* data)
|
|||
for (cgltf_size i = 0; i < data->variants_count; ++i)
|
||||
{
|
||||
data->memory.free_func(data->memory.user_data, data->variants[i].name);
|
||||
|
||||
cgltf_free_extras(data, &data->variants[i].extras);
|
||||
}
|
||||
|
||||
data->memory.free_func(data->memory.user_data, data->variants);
|
||||
|
||||
cgltf_free_extensions(data, data->data_extensions, data->data_extensions_count);
|
||||
cgltf_free_extras(data, &data->extras);
|
||||
|
||||
for (cgltf_size i = 0; i < data->extensions_used_count; ++i)
|
||||
{
|
||||
|
@ -2440,7 +2505,7 @@ static int cgltf_json_strcmp(jsmntok_t const* tok, const uint8_t* json_chunk, co
|
|||
{
|
||||
CGLTF_CHECK_TOKTYPE(*tok, JSMN_STRING);
|
||||
size_t const str_len = strlen(str);
|
||||
size_t const name_length = tok->end - tok->start;
|
||||
size_t const name_length = (size_t)(tok->end - tok->start);
|
||||
return (str_len == name_length) ? strncmp((const char*)json_chunk + tok->start, str, str_len) : 128;
|
||||
}
|
||||
|
||||
|
@ -2448,7 +2513,7 @@ static int cgltf_json_to_int(jsmntok_t const* tok, const uint8_t* json_chunk)
|
|||
{
|
||||
CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE);
|
||||
char tmp[128];
|
||||
int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1);
|
||||
int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1);
|
||||
strncpy(tmp, (const char*)json_chunk + tok->start, size);
|
||||
tmp[size] = 0;
|
||||
return CGLTF_ATOI(tmp);
|
||||
|
@ -2458,7 +2523,7 @@ static cgltf_size cgltf_json_to_size(jsmntok_t const* tok, const uint8_t* json_c
|
|||
{
|
||||
CGLTF_CHECK_TOKTYPE_RETTYPE(*tok, JSMN_PRIMITIVE, cgltf_size);
|
||||
char tmp[128];
|
||||
int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1);
|
||||
int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1);
|
||||
strncpy(tmp, (const char*)json_chunk + tok->start, size);
|
||||
tmp[size] = 0;
|
||||
return (cgltf_size)CGLTF_ATOLL(tmp);
|
||||
|
@ -2468,7 +2533,7 @@ static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json
|
|||
{
|
||||
CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE);
|
||||
char tmp[128];
|
||||
int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1);
|
||||
int size = (size_t)(tok->end - tok->start) < sizeof(tmp) ? (int)(tok->end - tok->start) : (int)(sizeof(tmp) - 1);
|
||||
strncpy(tmp, (const char*)json_chunk + tok->start, size);
|
||||
tmp[size] = 0;
|
||||
return (cgltf_float)CGLTF_ATOF(tmp);
|
||||
|
@ -2476,7 +2541,7 @@ static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json
|
|||
|
||||
static cgltf_bool cgltf_json_to_bool(jsmntok_t const* tok, const uint8_t* json_chunk)
|
||||
{
|
||||
int size = tok->end - tok->start;
|
||||
int size = (int)(tok->end - tok->start);
|
||||
return size == 4 && memcmp(json_chunk + tok->start, "true", 4) == 0;
|
||||
}
|
||||
|
||||
|
@ -2542,7 +2607,7 @@ static int cgltf_parse_json_string(cgltf_options* options, jsmntok_t const* toke
|
|||
{
|
||||
return CGLTF_ERROR_JSON;
|
||||
}
|
||||
int size = tokens[i].end - tokens[i].start;
|
||||
int size = (int)(tokens[i].end - tokens[i].start);
|
||||
char* result = (char*)options->memory.alloc_func(options->memory.user_data, size + 1);
|
||||
if (!result)
|
||||
{
|
||||
|
@ -2683,11 +2748,27 @@ static int cgltf_parse_json_attribute_list(cgltf_options* options, jsmntok_t con
|
|||
return i;
|
||||
}
|
||||
|
||||
static int cgltf_parse_json_extras(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_extras* out_extras)
|
||||
static int cgltf_parse_json_extras(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_extras* out_extras)
|
||||
{
|
||||
(void)json_chunk;
|
||||
if (out_extras->data)
|
||||
{
|
||||
return CGLTF_ERROR_JSON;
|
||||
}
|
||||
|
||||
/* fill deprecated fields for now, this will be removed in the future */
|
||||
out_extras->start_offset = tokens[i].start;
|
||||
out_extras->end_offset = tokens[i].end;
|
||||
|
||||
size_t start = tokens[i].start;
|
||||
size_t size = tokens[i].end - start;
|
||||
out_extras->data = (char*)options->memory.alloc_func(options->memory.user_data, size + 1);
|
||||
if (!out_extras->data)
|
||||
{
|
||||
return CGLTF_ERROR_NOMEM;
|
||||
}
|
||||
strncpy(out_extras->data, (const char*)json_chunk + start, size);
|
||||
out_extras->data[size] = '\0';
|
||||
|
||||
i = cgltf_skip_json(tokens, i);
|
||||
return i;
|
||||
}
|
||||
|
@ -2842,7 +2923,7 @@ static int cgltf_parse_json_material_mapping_data(cgltf_options* options, jsmnto
|
|||
|
||||
int material = -1;
|
||||
int variants_tok = -1;
|
||||
cgltf_extras extras = {0, 0};
|
||||
int extras_tok = -1;
|
||||
|
||||
for (int k = 0; k < obj_size; ++k)
|
||||
{
|
||||
|
@ -2863,7 +2944,8 @@ static int cgltf_parse_json_material_mapping_data(cgltf_options* options, jsmnto
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &extras);
|
||||
extras_tok = i + 1;
|
||||
i = cgltf_skip_json(tokens, extras_tok);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2891,7 +2973,13 @@ static int cgltf_parse_json_material_mapping_data(cgltf_options* options, jsmnto
|
|||
|
||||
out_mappings[*offset].material = CGLTF_PTRINDEX(cgltf_material, material);
|
||||
out_mappings[*offset].variant = variant;
|
||||
out_mappings[*offset].extras = extras;
|
||||
|
||||
if (extras_tok >= 0)
|
||||
{
|
||||
int e = cgltf_parse_json_extras(options, tokens, extras_tok, json_chunk, &out_mappings[*offset].extras);
|
||||
if (e < 0)
|
||||
return e;
|
||||
}
|
||||
|
||||
(*offset)++;
|
||||
}
|
||||
|
@ -3006,7 +3094,7 @@ static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* t
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_prim->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_prim->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -3253,7 +3341,7 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sparse->indices_extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->indices_extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -3296,7 +3384,7 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sparse->values_extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->values_extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -3315,7 +3403,7 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sparse->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sparse->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -3438,7 +3526,7 @@ static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* to
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_accessor->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_accessor->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -3544,7 +3632,7 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_texture_view->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_texture_view->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -3640,10 +3728,6 @@ static int cgltf_parse_json_pbr_metallic_roughness(cgltf_options* options, jsmnt
|
|||
i = cgltf_parse_json_texture_view(options, tokens, i + 1, json_chunk,
|
||||
&out_pbr->metallic_roughness_texture);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_pbr->extras);
|
||||
}
|
||||
else
|
||||
{
|
||||
i = cgltf_skip_json(tokens, i+1);
|
||||
|
@ -4076,7 +4160,7 @@ static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* token
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_image->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_image->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -4145,7 +4229,7 @@ static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tok
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sampler->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sampler->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -4194,7 +4278,7 @@ static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tok
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_texture->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_texture->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -4357,7 +4441,7 @@ static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* to
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_material->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_material->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -4710,7 +4794,7 @@ static int cgltf_parse_json_buffer_view(cgltf_options* options, jsmntok_t const*
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_buffer_view->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_buffer_view->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -4813,7 +4897,7 @@ static int cgltf_parse_json_buffer(cgltf_options* options, jsmntok_t const* toke
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_buffer->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_buffer->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -4897,7 +4981,7 @@ static int cgltf_parse_json_skin(cgltf_options* options, jsmntok_t const* tokens
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_skin->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_skin->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -4951,19 +5035,6 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke
|
|||
{
|
||||
i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_camera->name);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "type") == 0)
|
||||
{
|
||||
++i;
|
||||
if (cgltf_json_strcmp(tokens + i, json_chunk, "perspective") == 0)
|
||||
{
|
||||
out_camera->type = cgltf_camera_type_perspective;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "orthographic") == 0)
|
||||
{
|
||||
out_camera->type = cgltf_camera_type_orthographic;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "perspective") == 0)
|
||||
{
|
||||
++i;
|
||||
|
@ -4973,6 +5044,11 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke
|
|||
int data_size = tokens[i].size;
|
||||
++i;
|
||||
|
||||
if (out_camera->type != cgltf_camera_type_invalid)
|
||||
{
|
||||
return CGLTF_ERROR_JSON;
|
||||
}
|
||||
|
||||
out_camera->type = cgltf_camera_type_perspective;
|
||||
|
||||
for (int k = 0; k < data_size; ++k)
|
||||
|
@ -5007,7 +5083,7 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->data.perspective.extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_camera->data.perspective.extras);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5029,6 +5105,11 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke
|
|||
int data_size = tokens[i].size;
|
||||
++i;
|
||||
|
||||
if (out_camera->type != cgltf_camera_type_invalid)
|
||||
{
|
||||
return CGLTF_ERROR_JSON;
|
||||
}
|
||||
|
||||
out_camera->type = cgltf_camera_type_orthographic;
|
||||
|
||||
for (int k = 0; k < data_size; ++k)
|
||||
|
@ -5061,7 +5142,7 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->data.orthographic.extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_camera->data.orthographic.extras);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5076,7 +5157,7 @@ static int cgltf_parse_json_camera(cgltf_options* options, jsmntok_t const* toke
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_camera->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_camera->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -5209,7 +5290,7 @@ static int cgltf_parse_json_light(cgltf_options* options, jsmntok_t const* token
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_light->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_light->extras);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5335,7 +5416,7 @@ static int cgltf_parse_json_node(cgltf_options* options, jsmntok_t const* tokens
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_node->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_node->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -5473,7 +5554,7 @@ static int cgltf_parse_json_scene(cgltf_options* options, jsmntok_t const* token
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_scene->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_scene->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -5555,7 +5636,7 @@ static int cgltf_parse_json_animation_sampler(cgltf_options* options, jsmntok_t
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_sampler->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_sampler->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -5635,7 +5716,7 @@ static int cgltf_parse_json_animation_channel(cgltf_options* options, jsmntok_t
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_channel->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_channel->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -5717,7 +5798,7 @@ static int cgltf_parse_json_animation(cgltf_options* options, jsmntok_t const* t
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_animation->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_animation->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -5773,7 +5854,7 @@ static int cgltf_parse_json_variant(cgltf_options* options, jsmntok_t const* tok
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_variant->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_variant->extras);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5837,7 +5918,7 @@ static int cgltf_parse_json_asset(cgltf_options* options, jsmntok_t const* token
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_asset->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_asset->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -5993,7 +6074,7 @@ static int cgltf_parse_json_root(cgltf_options* options, jsmntok_t const* tokens
|
|||
}
|
||||
else if (cgltf_json_strcmp(tokens+i, json_chunk, "extras") == 0)
|
||||
{
|
||||
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_data->extras);
|
||||
i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_data->extras);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
|
||||
{
|
||||
|
@ -6420,7 +6501,7 @@ static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
|
|||
* Fills token type and boundaries.
|
||||
*/
|
||||
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
|
||||
int start, int end) {
|
||||
ptrdiff_t start, ptrdiff_t end) {
|
||||
token->type = type;
|
||||
token->start = start;
|
||||
token->end = end;
|
||||
|
@ -6433,7 +6514,7 @@ static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
|
|||
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
|
||||
size_t len, jsmntok_t *tokens, size_t num_tokens) {
|
||||
jsmntok_t *token;
|
||||
int start;
|
||||
ptrdiff_t start;
|
||||
|
||||
start = parser->pos;
|
||||
|
||||
|
@ -6483,7 +6564,7 @@ static int jsmn_parse_string(jsmn_parser *parser, const char *js,
|
|||
size_t len, jsmntok_t *tokens, size_t num_tokens) {
|
||||
jsmntok_t *token;
|
||||
|
||||
int start = parser->pos;
|
||||
ptrdiff_t start = parser->pos;
|
||||
|
||||
parser->pos++;
|
||||
|
||||
|
|
524
raylib/external/dr_flac.h
vendored
524
raylib/external/dr_flac.h
vendored
File diff suppressed because it is too large
Load diff
84
raylib/external/dr_mp3.h
vendored
84
raylib/external/dr_mp3.h
vendored
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||
dr_mp3 - v0.6.31 - 2021-08-22
|
||||
dr_mp3 - v0.6.34 - 2022-09-17
|
||||
|
||||
David Reid - mackron@gmail.com
|
||||
|
||||
|
@ -95,7 +95,7 @@ extern "C" {
|
|||
|
||||
#define DRMP3_VERSION_MAJOR 0
|
||||
#define DRMP3_VERSION_MINOR 6
|
||||
#define DRMP3_VERSION_REVISION 31
|
||||
#define DRMP3_VERSION_REVISION 34
|
||||
#define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION)
|
||||
|
||||
#include <stddef.h> /* For size_t. */
|
||||
|
@ -107,7 +107,7 @@ typedef signed short drmp3_int16;
|
|||
typedef unsigned short drmp3_uint16;
|
||||
typedef signed int drmp3_int32;
|
||||
typedef unsigned int drmp3_uint32;
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
typedef signed __int64 drmp3_int64;
|
||||
typedef unsigned __int64 drmp3_uint64;
|
||||
#else
|
||||
|
@ -235,9 +235,15 @@ typedef drmp3_int32 drmp3_result;
|
|||
I am using "__inline__" only when we're compiling in strict ANSI mode.
|
||||
*/
|
||||
#if defined(__STRICT_ANSI__)
|
||||
#define DRMP3_INLINE __inline__ __attribute__((always_inline))
|
||||
#define DRMP3_GNUC_INLINE_HINT __inline__
|
||||
#else
|
||||
#define DRMP3_INLINE inline __attribute__((always_inline))
|
||||
#define DRMP3_GNUC_INLINE_HINT inline
|
||||
#endif
|
||||
|
||||
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__)
|
||||
#define DRMP3_INLINE DRMP3_GNUC_INLINE_HINT __attribute__((always_inline))
|
||||
#else
|
||||
#define DRMP3_INLINE DRMP3_GNUC_INLINE_HINT
|
||||
#endif
|
||||
#elif defined(__WATCOMC__)
|
||||
#define DRMP3_INLINE __inline
|
||||
|
@ -340,7 +346,6 @@ typedef struct
|
|||
typedef struct
|
||||
{
|
||||
drmp3dec decoder;
|
||||
drmp3dec_frame_info frameInfo;
|
||||
drmp3_uint32 channels;
|
||||
drmp3_uint32 sampleRate;
|
||||
drmp3_read_proc onRead;
|
||||
|
@ -595,7 +600,7 @@ DRMP3_API const char* drmp3_version_string(void)
|
|||
#define DR_MP3_ONLY_SIMD
|
||||
#endif
|
||||
|
||||
#if ((defined(_MSC_VER) && _MSC_VER >= 1400) && (defined(_M_IX86) || defined(_M_X64))) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__))
|
||||
#if ((defined(_MSC_VER) && _MSC_VER >= 1400) && defined(_M_X64)) || ((defined(__i386) || defined(_M_IX86) || defined(__i386__) || defined(__x86_64__)) && ((defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)))
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
@ -1296,7 +1301,7 @@ static void drmp3_L3_huffman(float *dst, drmp3_bs *bs, const drmp3_L3_gr_info *g
|
|||
static const drmp3_int16 tabindex[2*16] = { 0,32,64,98,0,132,180,218,292,364,426,538,648,746,0,1126,1460,1460,1460,1460,1460,1460,1460,1460,1842,1842,1842,1842,1842,1842,1842,1842 };
|
||||
static const drmp3_uint8 g_linbits[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,8,10,13,4,5,6,7,8,9,11,13 };
|
||||
|
||||
#define DRMP3_PEEK_BITS(n) (bs_cache >> (32 - n))
|
||||
#define DRMP3_PEEK_BITS(n) (bs_cache >> (32 - (n)))
|
||||
#define DRMP3_FLUSH_BITS(n) { bs_cache <<= (n); bs_sh += (n); }
|
||||
#define DRMP3_CHECK_BITS while (bs_sh >= 0) { bs_cache |= (drmp3_uint32)*bs_next_ptr++ << bs_sh; bs_sh -= 8; }
|
||||
#define DRMP3_BSPOS ((bs_next_ptr - bs->buf)*8 - 24 + bs_sh)
|
||||
|
@ -1864,7 +1869,7 @@ static void drmp3d_DCT_II(float *grbuf, int n)
|
|||
#if DRMP3_HAVE_SSE
|
||||
#define DRMP3_VSAVE2(i, v) _mm_storel_pi((__m64 *)(void*)&y[i*18], v)
|
||||
#else
|
||||
#define DRMP3_VSAVE2(i, v) vst1_f32((float32_t *)&y[i*18], vget_low_f32(v))
|
||||
#define DRMP3_VSAVE2(i, v) vst1_f32((float32_t *)&y[(i)*18], vget_low_f32(v))
|
||||
#endif
|
||||
for (i = 0; i < 7; i++, y += 4*18)
|
||||
{
|
||||
|
@ -1880,7 +1885,7 @@ static void drmp3d_DCT_II(float *grbuf, int n)
|
|||
DRMP3_VSAVE2(3, t[3][7]);
|
||||
} else
|
||||
{
|
||||
#define DRMP3_VSAVE4(i, v) DRMP3_VSTORE(&y[i*18], v)
|
||||
#define DRMP3_VSAVE4(i, v) DRMP3_VSTORE(&y[(i)*18], v)
|
||||
for (i = 0; i < 7; i++, y += 4*18)
|
||||
{
|
||||
drmp3_f4 s = DRMP3_VADD(t[3][i], t[3][i + 1]);
|
||||
|
@ -2103,7 +2108,11 @@ static void drmp3d_synth(float *xl, drmp3d_sample_t *dstl, int nch, float *lins)
|
|||
vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2);
|
||||
#endif
|
||||
#else
|
||||
#if DRMP3_HAVE_SSE
|
||||
static const drmp3_f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f };
|
||||
#else
|
||||
const drmp3_f4 g_scale = vdupq_n_f32(1.0f/32768.0f);
|
||||
#endif
|
||||
a = DRMP3_VMUL(a, g_scale);
|
||||
b = DRMP3_VMUL(b, g_scale);
|
||||
#if DRMP3_HAVE_SSE
|
||||
|
@ -2406,8 +2415,6 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num
|
|||
Main Public API
|
||||
|
||||
************************************************************************************************************************************************************/
|
||||
#include <math.h> /* For sin() and exp(). */
|
||||
|
||||
#if defined(SIZE_MAX)
|
||||
#define DRMP3_SIZE_MAX SIZE_MAX
|
||||
#else
|
||||
|
@ -2427,7 +2434,7 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num
|
|||
|
||||
/* The size in bytes of each chunk of data to read from the MP3 stream. minimp3 recommends at least 16K, but in an attempt to reduce data movement I'm making this slightly larger. */
|
||||
#ifndef DRMP3_DATA_CHUNK_SIZE
|
||||
#define DRMP3_DATA_CHUNK_SIZE DRMP3_MIN_DATA_CHUNK_SIZE*4
|
||||
#define DRMP3_DATA_CHUNK_SIZE (DRMP3_MIN_DATA_CHUNK_SIZE*4)
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -2472,24 +2479,6 @@ static DRMP3_INLINE drmp3_uint32 drmp3_gcf_u32(drmp3_uint32 a, drmp3_uint32 b)
|
|||
}
|
||||
|
||||
|
||||
static DRMP3_INLINE double drmp3_sin(double x)
|
||||
{
|
||||
/* TODO: Implement custom sin(x). */
|
||||
return sin(x);
|
||||
}
|
||||
|
||||
static DRMP3_INLINE double drmp3_exp(double x)
|
||||
{
|
||||
/* TODO: Implement custom exp(x). */
|
||||
return exp(x);
|
||||
}
|
||||
|
||||
static DRMP3_INLINE double drmp3_cos(double x)
|
||||
{
|
||||
return drmp3_sin((DRMP3_PI_D*0.5) - x);
|
||||
}
|
||||
|
||||
|
||||
static void* drmp3__malloc_default(size_t sz, void* pUserData)
|
||||
{
|
||||
(void)pUserData;
|
||||
|
@ -3434,10 +3423,23 @@ static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const
|
|||
}
|
||||
#else
|
||||
/*
|
||||
Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
|
||||
think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
|
||||
maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility.
|
||||
Use fopen() on anything other than Windows. Requires a conversion. This is annoying because
|
||||
fopen() is locale specific. The only real way I can think of to do this is with wcsrtombs(). Note
|
||||
that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
|
||||
maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler
|
||||
error I'll look into improving compatibility.
|
||||
*/
|
||||
|
||||
/*
|
||||
Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just
|
||||
need to abort with an error. If you encounter a compiler lacking such support, add it to this list
|
||||
and submit a bug report and it'll be added to the library upstream.
|
||||
*/
|
||||
#if defined(__DJGPP__)
|
||||
{
|
||||
/* Nothing to do here. This will fall through to the error check below. */
|
||||
}
|
||||
#else
|
||||
{
|
||||
mbstate_t mbs;
|
||||
size_t lenMB;
|
||||
|
@ -3479,6 +3481,7 @@ static drmp3_result drmp3_wfopen(FILE** ppFile, const wchar_t* pFilePath, const
|
|||
|
||||
drmp3__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (*ppFile == NULL) {
|
||||
return DRMP3_ERROR;
|
||||
|
@ -4473,6 +4476,19 @@ counts rather than sample counts.
|
|||
/*
|
||||
REVISION HISTORY
|
||||
================
|
||||
v0.6.34 - 2022-09-17
|
||||
- Fix compilation with DJGPP.
|
||||
- Fix compilation when compiling with x86 with no SSE2.
|
||||
- Remove an unnecessary variable from the drmp3 structure.
|
||||
|
||||
v0.6.33 - 2022-04-10
|
||||
- Fix compilation error with the MSVC ARM64 build.
|
||||
- Fix compilation error on older versions of GCC.
|
||||
- Remove some unused functions.
|
||||
|
||||
v0.6.32 - 2021-12-11
|
||||
- Fix a warning with Clang.
|
||||
|
||||
v0.6.31 - 2021-08-22
|
||||
- Fix a bug when loading from memory.
|
||||
|
||||
|
|
109
raylib/external/dr_wav.h
vendored
109
raylib/external/dr_wav.h
vendored
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file.
|
||||
dr_wav - v0.13.4 - 2021-12-08
|
||||
dr_wav - v0.13.7 - 2022-09-17
|
||||
|
||||
David Reid - mackron@gmail.com
|
||||
|
||||
|
@ -92,6 +92,9 @@ Build Options
|
|||
#define DR_WAV_NO_STDIO
|
||||
Disables APIs that initialize a decoder from a file such as `drwav_init_file()`, `drwav_init_file_write()`, etc.
|
||||
|
||||
#define DR_WAV_NO_WCHAR
|
||||
Disables all functions ending with `_w`. Use this if your compiler does not provide wchar.h. Not required if DR_WAV_NO_STDIO is also defined.
|
||||
|
||||
|
||||
|
||||
Notes
|
||||
|
@ -125,7 +128,7 @@ extern "C" {
|
|||
|
||||
#define DRWAV_VERSION_MAJOR 0
|
||||
#define DRWAV_VERSION_MINOR 13
|
||||
#define DRWAV_VERSION_REVISION 4
|
||||
#define DRWAV_VERSION_REVISION 7
|
||||
#define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION)
|
||||
|
||||
#include <stddef.h> /* For size_t. */
|
||||
|
@ -1297,14 +1300,21 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b);
|
|||
#ifndef dr_wav_c
|
||||
#define dr_wav_c
|
||||
|
||||
#ifdef __MRC__
|
||||
/* MrC currently doesn't compile dr_wav correctly with any optimizations enabled. */
|
||||
#pragma options opt off
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h> /* For memcpy(), memset() */
|
||||
#include <string.h>
|
||||
#include <limits.h> /* For INT_MAX */
|
||||
|
||||
#ifndef DR_WAV_NO_STDIO
|
||||
#include <stdio.h>
|
||||
#ifndef DR_WAV_NO_WCHAR
|
||||
#include <wchar.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Standard library stuff. */
|
||||
#ifndef DRWAV_ASSERT
|
||||
|
@ -1359,9 +1369,15 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b);
|
|||
I am using "__inline__" only when we're compiling in strict ANSI mode.
|
||||
*/
|
||||
#if defined(__STRICT_ANSI__)
|
||||
#define DRWAV_INLINE __inline__ __attribute__((always_inline))
|
||||
#define DRWAV_GNUC_INLINE_HINT __inline__
|
||||
#else
|
||||
#define DRWAV_INLINE inline __attribute__((always_inline))
|
||||
#define DRWAV_GNUC_INLINE_HINT inline
|
||||
#endif
|
||||
|
||||
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__)
|
||||
#define DRWAV_INLINE DRWAV_GNUC_INLINE_HINT __attribute__((always_inline))
|
||||
#else
|
||||
#define DRWAV_INLINE DRWAV_GNUC_INLINE_HINT
|
||||
#endif
|
||||
#elif defined(__WATCOMC__)
|
||||
#define DRWAV_INLINE __inline
|
||||
|
@ -1966,7 +1982,7 @@ DRWAV_PRIVATE drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_pr
|
|||
fmtOut->extendedSize = 0;
|
||||
fmtOut->validBitsPerSample = 0;
|
||||
fmtOut->channelMask = 0;
|
||||
memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat));
|
||||
DRWAV_ZERO_MEMORY(fmtOut->subFormat, sizeof(fmtOut->subFormat));
|
||||
|
||||
if (header.sizeInBytes > 16) {
|
||||
drwav_uint8 fmt_cbSize[2];
|
||||
|
@ -2137,7 +2153,7 @@ DRWAV_PRIVATE void drwav__metadata_request_extra_memory_for_stage_2(drwav__metad
|
|||
DRWAV_PRIVATE drwav_result drwav__metadata_alloc(drwav__metadata_parser* pParser, drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
if (pParser->extraCapacity != 0 || pParser->metadataCount != 0) {
|
||||
free(pParser->pData);
|
||||
pAllocationCallbacks->onFree(pParser->pData, pAllocationCallbacks->pUserData);
|
||||
|
||||
pParser->pData = (drwav_uint8*)pAllocationCallbacks->onMalloc(drwav__metadata_memory_capacity(pParser), pAllocationCallbacks->pUserData);
|
||||
pParser->pDataCursor = pParser->pData;
|
||||
|
@ -2316,6 +2332,17 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_acid_to_metadata_obj(drwav__metadata_pars
|
|||
return bytesRead;
|
||||
}
|
||||
|
||||
DRWAV_PRIVATE size_t drwav__strlen(const char* str)
|
||||
{
|
||||
size_t result = 0;
|
||||
|
||||
while (*str++) {
|
||||
result += 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DRWAV_PRIVATE size_t drwav__strlen_clamped(const char* str, size_t maxToRead)
|
||||
{
|
||||
size_t result = 0;
|
||||
|
@ -2335,7 +2362,7 @@ DRWAV_PRIVATE char* drwav__metadata_copy_string(drwav__metadata_parser* pParser,
|
|||
char* result = (char*)drwav__metadata_get_memory(pParser, len + 1, 1);
|
||||
DRWAV_ASSERT(result != NULL);
|
||||
|
||||
memcpy(result, str, len);
|
||||
DRWAV_COPY_MEMORY(result, str, len);
|
||||
result[len] = '\0';
|
||||
|
||||
return result;
|
||||
|
@ -2516,7 +2543,7 @@ DRWAV_PRIVATE drwav_uint64 drwav__read_bext_to_metadata_obj(drwav__metadata_pars
|
|||
DRWAV_ASSERT(pMetadata->data.bext.pCodingHistory != NULL);
|
||||
|
||||
bytesRead += drwav__metadata_parser_read(pParser, pMetadata->data.bext.pCodingHistory, extraBytes, NULL);
|
||||
pMetadata->data.bext.codingHistorySize = (drwav_uint32)strlen(pMetadata->data.bext.pCodingHistory);
|
||||
pMetadata->data.bext.codingHistorySize = (drwav_uint32)drwav__strlen(pMetadata->data.bext.pCodingHistory);
|
||||
} else {
|
||||
pMetadata->data.bext.pCodingHistory = NULL;
|
||||
pMetadata->data.bext.codingHistorySize = 0;
|
||||
|
@ -2780,21 +2807,21 @@ DRWAV_PRIVATE drwav_uint64 drwav__metadata_process_chunk(drwav__metadata_parser*
|
|||
if (bytesJustRead != DRWAV_BEXT_DESCRIPTION_BYTES) {
|
||||
return bytesRead;
|
||||
}
|
||||
allocSizeNeeded += strlen(buffer) + 1;
|
||||
allocSizeNeeded += drwav__strlen(buffer) + 1;
|
||||
|
||||
buffer[DRWAV_BEXT_ORIGINATOR_NAME_BYTES] = '\0';
|
||||
bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_ORIGINATOR_NAME_BYTES, &bytesRead);
|
||||
if (bytesJustRead != DRWAV_BEXT_ORIGINATOR_NAME_BYTES) {
|
||||
return bytesRead;
|
||||
}
|
||||
allocSizeNeeded += strlen(buffer) + 1;
|
||||
allocSizeNeeded += drwav__strlen(buffer) + 1;
|
||||
|
||||
buffer[DRWAV_BEXT_ORIGINATOR_REF_BYTES] = '\0';
|
||||
bytesJustRead = drwav__metadata_parser_read(pParser, buffer, DRWAV_BEXT_ORIGINATOR_REF_BYTES, &bytesRead);
|
||||
if (bytesJustRead != DRWAV_BEXT_ORIGINATOR_REF_BYTES) {
|
||||
return bytesRead;
|
||||
}
|
||||
allocSizeNeeded += strlen(buffer) + 1;
|
||||
allocSizeNeeded += drwav__strlen(buffer) + 1;
|
||||
allocSizeNeeded += (size_t)pChunkHeader->sizeInBytes - DRWAV_BEXT_BYTES; /* Coding history. */
|
||||
|
||||
drwav__metadata_request_extra_memory_for_stage_2(pParser, allocSizeNeeded, 1);
|
||||
|
@ -3157,7 +3184,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc on
|
|||
translatedFormatTag = drwav_bytes_to_u16(fmt.subFormat + 0);
|
||||
}
|
||||
|
||||
memset(&metadataParser, 0, sizeof(metadataParser));
|
||||
DRWAV_ZERO_MEMORY(&metadataParser, sizeof(metadataParser));
|
||||
|
||||
/* Not tested on W64. */
|
||||
if (!sequential && pWav->allowedMetadataTypes != drwav_metadata_type_none && (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64)) {
|
||||
|
@ -3746,7 +3773,7 @@ DRWAV_PRIVATE size_t drwav__write_or_count_metadata(drwav* pWav, drwav_metadata*
|
|||
bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxMomentaryLoudness);
|
||||
bytesWritten += drwav__write_or_count_u16ne_to_le(pWav, pMetadata->data.bext.maxShortTermLoudness);
|
||||
|
||||
memset(reservedBuf, 0, sizeof(reservedBuf));
|
||||
DRWAV_ZERO_MEMORY(reservedBuf, sizeof(reservedBuf));
|
||||
bytesWritten += drwav__write_or_count(pWav, reservedBuf, sizeof(reservedBuf));
|
||||
|
||||
if (pMetadata->data.bext.codingHistorySize > 0) {
|
||||
|
@ -4704,6 +4731,7 @@ fallback, so if you notice your compiler not detecting this properly I'm happy t
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DR_WAV_NO_WCHAR
|
||||
DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
if (ppFile != NULL) {
|
||||
|
@ -4732,10 +4760,23 @@ DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath,
|
|||
}
|
||||
#else
|
||||
/*
|
||||
Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
|
||||
think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
|
||||
maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility.
|
||||
Use fopen() on anything other than Windows. Requires a conversion. This is annoying because
|
||||
fopen() is locale specific. The only real way I can think of to do this is with wcsrtombs(). Note
|
||||
that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
|
||||
maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler
|
||||
error I'll look into improving compatibility.
|
||||
*/
|
||||
|
||||
/*
|
||||
Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just
|
||||
need to abort with an error. If you encounter a compiler lacking such support, add it to this list
|
||||
and submit a bug report and it'll be added to the library upstream.
|
||||
*/
|
||||
#if defined(__DJGPP__)
|
||||
{
|
||||
/* Nothing to do here. This will fall through to the error check below. */
|
||||
}
|
||||
#else
|
||||
{
|
||||
mbstate_t mbs;
|
||||
size_t lenMB;
|
||||
|
@ -4777,6 +4818,7 @@ DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath,
|
|||
|
||||
drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (*ppFile == NULL) {
|
||||
return DRWAV_ERROR;
|
||||
|
@ -4785,6 +4827,7 @@ DRWAV_PRIVATE drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath,
|
|||
|
||||
return DRWAV_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
DRWAV_PRIVATE size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead)
|
||||
|
@ -4840,6 +4883,7 @@ DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drw
|
|||
return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, drwav_metadata_type_none, pAllocationCallbacks);
|
||||
}
|
||||
|
||||
#ifndef DR_WAV_NO_WCHAR
|
||||
DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks);
|
||||
|
@ -4855,6 +4899,7 @@ DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename
|
|||
/* This takes ownership of the FILE* object. */
|
||||
return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, drwav_metadata_type_none, pAllocationCallbacks);
|
||||
}
|
||||
#endif
|
||||
|
||||
DRWAV_API drwav_bool32 drwav_init_file_with_metadata(drwav* pWav, const char* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
|
@ -4867,6 +4912,7 @@ DRWAV_API drwav_bool32 drwav_init_file_with_metadata(drwav* pWav, const char* fi
|
|||
return drwav_init_file__internal_FILE(pWav, pFile, NULL, NULL, flags, drwav_metadata_type_all_including_unknown, pAllocationCallbacks);
|
||||
}
|
||||
|
||||
#ifndef DR_WAV_NO_WCHAR
|
||||
DRWAV_API drwav_bool32 drwav_init_file_with_metadata_w(drwav* pWav, const wchar_t* filename, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
FILE* pFile;
|
||||
|
@ -4877,6 +4923,7 @@ DRWAV_API drwav_bool32 drwav_init_file_with_metadata_w(drwav* pWav, const wchar_
|
|||
/* This takes ownership of the FILE* object. */
|
||||
return drwav_init_file__internal_FILE(pWav, pFile, NULL, NULL, flags, drwav_metadata_type_all_including_unknown, pAllocationCallbacks);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal_FILE(drwav* pWav, FILE* pFile, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
|
@ -4909,6 +4956,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init_file_write__internal(drwav* pWav, const ch
|
|||
return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
|
||||
}
|
||||
|
||||
#ifndef DR_WAV_NO_WCHAR
|
||||
DRWAV_PRIVATE drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
FILE* pFile;
|
||||
|
@ -4919,6 +4967,7 @@ DRWAV_PRIVATE drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const
|
|||
/* This takes ownership of the FILE* object. */
|
||||
return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks);
|
||||
}
|
||||
#endif
|
||||
|
||||
DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
|
@ -4939,6 +4988,7 @@ DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav,
|
|||
return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
|
||||
}
|
||||
|
||||
#ifndef DR_WAV_NO_WCHAR
|
||||
DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks);
|
||||
|
@ -4957,6 +5007,7 @@ DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav
|
|||
|
||||
return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks);
|
||||
}
|
||||
#endif
|
||||
#endif /* DR_WAV_NO_STDIO */
|
||||
|
||||
|
||||
|
@ -5441,8 +5492,8 @@ DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetF
|
|||
}
|
||||
|
||||
/* Make sure the sample is clamped. */
|
||||
if (targetFrameIndex >= pWav->totalPCMFrameCount) {
|
||||
targetFrameIndex = pWav->totalPCMFrameCount - 1;
|
||||
if (targetFrameIndex > pWav->totalPCMFrameCount) {
|
||||
targetFrameIndex = pWav->totalPCMFrameCount;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -7650,6 +7701,7 @@ DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filen
|
|||
}
|
||||
|
||||
|
||||
#ifndef DR_WAV_NO_WCHAR
|
||||
DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
drwav wav;
|
||||
|
@ -7712,7 +7764,8 @@ DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t*
|
|||
|
||||
return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut);
|
||||
}
|
||||
#endif
|
||||
#endif /* DR_WAV_NO_WCHAR */
|
||||
#endif /* DR_WAV_NO_STDIO */
|
||||
|
||||
DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks)
|
||||
{
|
||||
|
@ -7853,12 +7906,28 @@ DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b)
|
|||
a[3] == b[3];
|
||||
}
|
||||
|
||||
#ifdef __MRC__
|
||||
/* Undo the pragma at the beginning of this file. */
|
||||
#pragma options opt reset
|
||||
#endif
|
||||
|
||||
#endif /* dr_wav_c */
|
||||
#endif /* DR_WAV_IMPLEMENTATION */
|
||||
|
||||
/*
|
||||
REVISION HISTORY
|
||||
================
|
||||
v0.13.7 - 2022-09-17
|
||||
- Fix compilation with DJGPP.
|
||||
- Add support for disabling wchar_t with DR_WAV_NO_WCHAR.
|
||||
|
||||
v0.13.6 - 2022-04-10
|
||||
- Fix compilation error on older versions of GCC.
|
||||
- Remove some dependencies on the standard library.
|
||||
|
||||
v0.13.5 - 2022-01-26
|
||||
- Fix an error when seeking to the end of the file.
|
||||
|
||||
v0.13.4 - 2021-12-08
|
||||
- Fix some static analysis warnings.
|
||||
|
||||
|
|
4774
raylib/external/glad_gles2.h
vendored
Normal file
4774
raylib/external/glad_gles2.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
7
raylib/external/jar_xm.h
vendored
7
raylib/external/jar_xm.h
vendored
|
@ -518,10 +518,6 @@ int jar_xm_create_context(jar_xm_context_t** ctxp, const char* moddata, uint32_t
|
|||
return jar_xm_create_context_safe(ctxp, moddata, SIZE_MAX, rate);
|
||||
}
|
||||
|
||||
#ifdef ALIGN
|
||||
#undef ALIGN
|
||||
#endif
|
||||
|
||||
#define ALIGN(x, b) (((x) + ((b) - 1)) & ~((b) - 1))
|
||||
#define ALIGN_PTR(x, b) (void*)(((uintptr_t)(x) + ((b) - 1)) & ~((b) - 1))
|
||||
int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, size_t moddata_length, uint32_t rate) {
|
||||
|
@ -802,7 +798,7 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd
|
|||
mod->num_patterns = READ_U16(offset + 10);
|
||||
mod->num_instruments = READ_U16(offset + 12);
|
||||
mod->patterns = (jar_xm_pattern_t*)mempool;
|
||||
mod->linear_interpolation = 0; // Linear interpolation can be set after loading
|
||||
mod->linear_interpolation = 1; // Linear interpolation can be set after loading
|
||||
mod->ramping = 1; // ramping can be set after loading
|
||||
mempool += mod->num_patterns * sizeof(jar_xm_pattern_t);
|
||||
mempool = ALIGN_PTR(mempool, 16);
|
||||
|
@ -2257,6 +2253,7 @@ void jar_xm_reset(jar_xm_context_t* ctx) {
|
|||
for (uint16_t i = 0; i < jar_xm_get_number_of_channels(ctx); i++) {
|
||||
jar_xm_cut_note(&ctx->channels[i]);
|
||||
}
|
||||
ctx->generated_samples = 0;
|
||||
ctx->current_row = 0;
|
||||
ctx->current_table_index = 0;
|
||||
ctx->current_tick = 0;
|
||||
|
|
4442
raylib/external/miniaudio.h
vendored
4442
raylib/external/miniaudio.h
vendored
File diff suppressed because it is too large
Load diff
660
raylib/external/qoa.h
vendored
Normal file
660
raylib/external/qoa.h
vendored
Normal file
|
@ -0,0 +1,660 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2023, Dominic Szablewski - https://phoboslab.org
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
QOA - The "Quite OK Audio" format for fast, lossy audio compression
|
||||
|
||||
|
||||
-- Data Format
|
||||
|
||||
A QOA file has an 8 byte file header, followed by a number of frames. Each frame
|
||||
consists of an 8 byte frame header, the current 8 byte en-/decoder state per
|
||||
channel and 256 slices per channel. Each slice is 8 bytes wide and encodes 20
|
||||
samples of audio data.
|
||||
|
||||
Note that the last frame of a file may contain less than 256 slices per channel.
|
||||
The last slice (per channel) in the last frame may contain less 20 samples, but
|
||||
the slice will still be 8 bytes wide, with the unused samples zeroed out.
|
||||
|
||||
The samplerate and number of channels is only stated in the frame headers, but
|
||||
not in the file header. A decoder may peek into the first frame of the file to
|
||||
find these values.
|
||||
|
||||
In a valid QOA file all frames have the same number of channels and the same
|
||||
samplerate. These restrictions may be relaxed for streaming. This remains to
|
||||
be decided.
|
||||
|
||||
All values in a QOA file are BIG ENDIAN. Luckily, EVERYTHING in a QOA file,
|
||||
including the headers, is 64 bit aligned, so it's possible to read files with
|
||||
just a read_u64() that does the byte swapping if necessary.
|
||||
|
||||
In pseudocode, the file layout is as follows:
|
||||
|
||||
struct {
|
||||
struct {
|
||||
char magic[4]; // magic bytes 'qoaf'
|
||||
uint32_t samples; // number of samples per channel in this file
|
||||
} file_header; // = 64 bits
|
||||
|
||||
struct {
|
||||
struct {
|
||||
uint8_t num_channels; // number of channels
|
||||
uint24_t samplerate; // samplerate in hz
|
||||
uint16_t fsamples; // sample count per channel in this frame
|
||||
uint16_t fsize; // frame size (including the frame header)
|
||||
} frame_header; // = 64 bits
|
||||
|
||||
struct {
|
||||
int16_t history[4]; // = 64 bits
|
||||
int16_t weights[4]; // = 64 bits
|
||||
} lms_state[num_channels];
|
||||
|
||||
qoa_slice_t slices[256][num_channels]; // = 64 bits each
|
||||
} frames[samples * channels / qoa_max_framesize()];
|
||||
} qoa_file;
|
||||
|
||||
Wheras the 64bit qoa_slice_t is defined as follows:
|
||||
|
||||
.- QOA_SLICE -- 64 bits, 20 samples --------------------------/ /------------.
|
||||
| Byte[0] | Byte[1] | Byte[2] \ \ Byte[7] |
|
||||
| 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | 7 6 5 / / 2 1 0 |
|
||||
|------------+--------+--------+--------+---------+---------+-\ \--+---------|
|
||||
| sf_index | r00 | r01 | r02 | r03 | r04 | / / | r19 |
|
||||
`-------------------------------------------------------------\ \------------`
|
||||
|
||||
`sf_index` defines the scalefactor to use for this slice as an index into the
|
||||
qoa_scalefactor_tab[16]
|
||||
|
||||
`r00`--`r19` are the residuals for the individual samples, divided by the
|
||||
scalefactor and quantized by the qoa_quant_tab[].
|
||||
|
||||
In the decoder, a prediction of the next sample is computed by multiplying the
|
||||
state (the last four output samples) with the predictor. The residual from the
|
||||
slice is then dequantized using the qoa_dequant_tab[] and added to the
|
||||
prediction. The result is clamped to int16 to form the final output sample.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Header - Public functions */
|
||||
|
||||
#ifndef QOA_H
|
||||
#define QOA_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define QOA_MIN_FILESIZE 16
|
||||
#define QOA_MAX_CHANNELS 8
|
||||
|
||||
#define QOA_SLICE_LEN 20
|
||||
#define QOA_SLICES_PER_FRAME 256
|
||||
#define QOA_FRAME_LEN (QOA_SLICES_PER_FRAME * QOA_SLICE_LEN)
|
||||
#define QOA_LMS_LEN 4
|
||||
#define QOA_MAGIC 0x716f6166 /* 'qoaf' */
|
||||
|
||||
#define QOA_FRAME_SIZE(channels, slices) \
|
||||
(8 + QOA_LMS_LEN * 4 * channels + 8 * slices * channels)
|
||||
|
||||
typedef struct {
|
||||
int history[QOA_LMS_LEN];
|
||||
int weights[QOA_LMS_LEN];
|
||||
} qoa_lms_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned int channels;
|
||||
unsigned int samplerate;
|
||||
unsigned int samples;
|
||||
qoa_lms_t lms[QOA_MAX_CHANNELS];
|
||||
#ifdef QOA_RECORD_TOTAL_ERROR
|
||||
double error;
|
||||
#endif
|
||||
} qoa_desc;
|
||||
|
||||
unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes);
|
||||
unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes);
|
||||
void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len);
|
||||
|
||||
unsigned int qoa_max_frame_size(qoa_desc *qoa);
|
||||
unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa);
|
||||
unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len);
|
||||
short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *file);
|
||||
|
||||
#ifndef QOA_NO_STDIO
|
||||
|
||||
int qoa_write(const char *filename, const short *sample_data, qoa_desc *qoa);
|
||||
void *qoa_read(const char *filename, qoa_desc *qoa);
|
||||
|
||||
#endif /* QOA_NO_STDIO */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* QOA_H */
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Implementation */
|
||||
|
||||
#ifdef QOA_IMPLEMENTATION
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef QOA_MALLOC
|
||||
#define QOA_MALLOC(sz) malloc(sz)
|
||||
#define QOA_FREE(p) free(p)
|
||||
#endif
|
||||
|
||||
typedef unsigned long long qoa_uint64_t;
|
||||
|
||||
|
||||
/* The quant_tab provides an index into the dequant_tab for residuals in the
|
||||
range of -8 .. 8. It maps this range to just 3bits and becomes less accurate at
|
||||
the higher end. Note that the residual zero is identical to the lowest positive
|
||||
value. This is mostly fine, since the qoa_div() function always rounds away
|
||||
from zero. */
|
||||
|
||||
static int qoa_quant_tab[17] = {
|
||||
7, 7, 7, 5, 5, 3, 3, 1, /* -8..-1 */
|
||||
0, /* 0 */
|
||||
0, 2, 2, 4, 4, 6, 6, 6 /* 1.. 8 */
|
||||
};
|
||||
|
||||
|
||||
/* We have 16 different scalefactors. Like the quantized residuals these become
|
||||
less accurate at the higher end. In theory, the highest scalefactor that we
|
||||
would need to encode the highest 16bit residual is (2**16)/8 = 8192. However we
|
||||
rely on the LMS filter to predict samples accurately enough that a maximum
|
||||
residual of one quarter of the 16 bit range is high sufficient. I.e. with the
|
||||
scalefactor 2048 times the quant range of 8 we can encode residuals up to 2**14.
|
||||
|
||||
The scalefactor values are computed as:
|
||||
scalefactor_tab[s] <- round(pow(s + 1, 2.75)) */
|
||||
|
||||
static int qoa_scalefactor_tab[16] = {
|
||||
1, 7, 21, 45, 84, 138, 211, 304, 421, 562, 731, 928, 1157, 1419, 1715, 2048
|
||||
};
|
||||
|
||||
|
||||
/* The reciprocal_tab maps each of the 16 scalefactors to their rounded
|
||||
reciprocals 1/scalefactor. This allows us to calculate the scaled residuals in
|
||||
the encoder with just one multiplication instead of an expensive division. We
|
||||
do this in .16 fixed point with integers, instead of floats.
|
||||
|
||||
The reciprocal_tab is computed as:
|
||||
reciprocal_tab[s] <- ((1<<16) + scalefactor_tab[s] - 1) / scalefactor_tab[s] */
|
||||
|
||||
static int qoa_reciprocal_tab[16] = {
|
||||
65536, 9363, 3121, 1457, 781, 475, 311, 216, 156, 117, 90, 71, 57, 47, 39, 32
|
||||
};
|
||||
|
||||
|
||||
/* The dequant_tab maps each of the scalefactors and quantized residuals to
|
||||
their unscaled & dequantized version.
|
||||
|
||||
Since qoa_div rounds away from the zero, the smallest entries are mapped to 3/4
|
||||
instead of 1. The dequant_tab assumes the following dequantized values for each
|
||||
of the quant_tab indices and is computed as:
|
||||
float dqt[8] = {0.75, -0.75, 2.5, -2.5, 4.5, -4.5, 7, -7};
|
||||
dequant_tab[s][q] <- round(scalefactor_tab[s] * dqt[q]) */
|
||||
|
||||
static int qoa_dequant_tab[16][8] = {
|
||||
{ 1, -1, 3, -3, 5, -5, 7, -7},
|
||||
{ 5, -5, 18, -18, 32, -32, 49, -49},
|
||||
{ 16, -16, 53, -53, 95, -95, 147, -147},
|
||||
{ 34, -34, 113, -113, 203, -203, 315, -315},
|
||||
{ 63, -63, 210, -210, 378, -378, 588, -588},
|
||||
{ 104, -104, 345, -345, 621, -621, 966, -966},
|
||||
{ 158, -158, 528, -528, 950, -950, 1477, -1477},
|
||||
{ 228, -228, 760, -760, 1368, -1368, 2128, -2128},
|
||||
{ 316, -316, 1053, -1053, 1895, -1895, 2947, -2947},
|
||||
{ 422, -422, 1405, -1405, 2529, -2529, 3934, -3934},
|
||||
{ 548, -548, 1828, -1828, 3290, -3290, 5117, -5117},
|
||||
{ 696, -696, 2320, -2320, 4176, -4176, 6496, -6496},
|
||||
{ 868, -868, 2893, -2893, 5207, -5207, 8099, -8099},
|
||||
{1064, -1064, 3548, -3548, 6386, -6386, 9933, -9933},
|
||||
{1286, -1286, 4288, -4288, 7718, -7718, 12005, -12005},
|
||||
{1536, -1536, 5120, -5120, 9216, -9216, 14336, -14336},
|
||||
};
|
||||
|
||||
|
||||
/* The Least Mean Squares Filter is the heart of QOA. It predicts the next
|
||||
sample based on the previous 4 reconstructed samples. It does so by continuously
|
||||
adjusting 4 weights based on the residual of the previous prediction.
|
||||
|
||||
The next sample is predicted as the sum of (weight[i] * history[i]).
|
||||
|
||||
The adjustment of the weights is done with a "Sign-Sign-LMS" that adds or
|
||||
subtracts the residual to each weight, based on the corresponding sample from
|
||||
the history. This, surprisingly, is sufficient to get worthwhile predictions.
|
||||
|
||||
This is all done with fixed point integers. Hence the right-shifts when updating
|
||||
the weights and calculating the prediction. */
|
||||
|
||||
static int qoa_lms_predict(qoa_lms_t *lms) {
|
||||
int prediction = 0;
|
||||
for (int i = 0; i < QOA_LMS_LEN; i++) {
|
||||
prediction += lms->weights[i] * lms->history[i];
|
||||
}
|
||||
return prediction >> 13;
|
||||
}
|
||||
|
||||
static void qoa_lms_update(qoa_lms_t *lms, int sample, int residual) {
|
||||
int delta = residual >> 4;
|
||||
for (int i = 0; i < QOA_LMS_LEN; i++) {
|
||||
lms->weights[i] += lms->history[i] < 0 ? -delta : delta;
|
||||
}
|
||||
|
||||
for (int i = 0; i < QOA_LMS_LEN-1; i++) {
|
||||
lms->history[i] = lms->history[i+1];
|
||||
}
|
||||
lms->history[QOA_LMS_LEN-1] = sample;
|
||||
}
|
||||
|
||||
|
||||
/* qoa_div() implements a rounding division, but avoids rounding to zero for
|
||||
small numbers. E.g. 0.1 will be rounded to 1. Note that 0 itself still
|
||||
returns as 0, which is handled in the qoa_quant_tab[].
|
||||
qoa_div() takes an index into the .16 fixed point qoa_reciprocal_tab as an
|
||||
argument, so it can do the division with a cheaper integer multiplication. */
|
||||
|
||||
static inline int qoa_div(int v, int scalefactor) {
|
||||
int reciprocal = qoa_reciprocal_tab[scalefactor];
|
||||
int n = (v * reciprocal + (1 << 15)) >> 16;
|
||||
n = n + ((v > 0) - (v < 0)) - ((n > 0) - (n < 0)); /* round away from 0 */
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline int qoa_clamp(int v, int min, int max) {
|
||||
return (v < min) ? min : (v > max) ? max : v;
|
||||
}
|
||||
|
||||
static inline qoa_uint64_t qoa_read_u64(const unsigned char *bytes, unsigned int *p) {
|
||||
bytes += *p;
|
||||
*p += 8;
|
||||
return
|
||||
((qoa_uint64_t)(bytes[0]) << 56) | ((qoa_uint64_t)(bytes[1]) << 48) |
|
||||
((qoa_uint64_t)(bytes[2]) << 40) | ((qoa_uint64_t)(bytes[3]) << 32) |
|
||||
((qoa_uint64_t)(bytes[4]) << 24) | ((qoa_uint64_t)(bytes[5]) << 16) |
|
||||
((qoa_uint64_t)(bytes[6]) << 8) | ((qoa_uint64_t)(bytes[7]) << 0);
|
||||
}
|
||||
|
||||
static inline void qoa_write_u64(qoa_uint64_t v, unsigned char *bytes, unsigned int *p) {
|
||||
bytes += *p;
|
||||
*p += 8;
|
||||
bytes[0] = (v >> 56) & 0xff;
|
||||
bytes[1] = (v >> 48) & 0xff;
|
||||
bytes[2] = (v >> 40) & 0xff;
|
||||
bytes[3] = (v >> 32) & 0xff;
|
||||
bytes[4] = (v >> 24) & 0xff;
|
||||
bytes[5] = (v >> 16) & 0xff;
|
||||
bytes[6] = (v >> 8) & 0xff;
|
||||
bytes[7] = (v >> 0) & 0xff;
|
||||
}
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Encoder */
|
||||
|
||||
unsigned int qoa_encode_header(qoa_desc *qoa, unsigned char *bytes) {
|
||||
unsigned int p = 0;
|
||||
qoa_write_u64(((qoa_uint64_t)QOA_MAGIC << 32) | qoa->samples, bytes, &p);
|
||||
return p;
|
||||
}
|
||||
|
||||
unsigned int qoa_encode_frame(const short *sample_data, qoa_desc *qoa, unsigned int frame_len, unsigned char *bytes) {
|
||||
unsigned int channels = qoa->channels;
|
||||
|
||||
unsigned int p = 0;
|
||||
unsigned int slices = (frame_len + QOA_SLICE_LEN - 1) / QOA_SLICE_LEN;
|
||||
unsigned int frame_size = QOA_FRAME_SIZE(channels, slices);
|
||||
|
||||
/* Write the frame header */
|
||||
qoa_write_u64((
|
||||
(qoa_uint64_t)qoa->channels << 56 |
|
||||
(qoa_uint64_t)qoa->samplerate << 32 |
|
||||
(qoa_uint64_t)frame_len << 16 |
|
||||
(qoa_uint64_t)frame_size
|
||||
), bytes, &p);
|
||||
|
||||
/* Write the current LMS state */
|
||||
for (int c = 0; c < channels; c++) {
|
||||
qoa_uint64_t weights = 0;
|
||||
qoa_uint64_t history = 0;
|
||||
for (int i = 0; i < QOA_LMS_LEN; i++) {
|
||||
history = (history << 16) | (qoa->lms[c].history[i] & 0xffff);
|
||||
weights = (weights << 16) | (qoa->lms[c].weights[i] & 0xffff);
|
||||
}
|
||||
qoa_write_u64(history, bytes, &p);
|
||||
qoa_write_u64(weights, bytes, &p);
|
||||
}
|
||||
|
||||
/* We encode all samples with the channels interleaved on a slice level.
|
||||
E.g. for stereo: (ch-0, slice 0), (ch 1, slice 0), (ch 0, slice 1), ...*/
|
||||
for (int sample_index = 0; sample_index < frame_len; sample_index += QOA_SLICE_LEN) {
|
||||
|
||||
for (int c = 0; c < channels; c++) {
|
||||
int slice_len = qoa_clamp(QOA_SLICE_LEN, 0, frame_len - sample_index);
|
||||
int slice_start = sample_index * channels + c;
|
||||
int slice_end = (sample_index + slice_len) * channels + c;
|
||||
|
||||
/* Brute for search for the best scalefactor. Just go through all
|
||||
16 scalefactors, encode all samples for the current slice and
|
||||
meassure the total squared error. */
|
||||
qoa_uint64_t best_error = -1;
|
||||
qoa_uint64_t best_slice;
|
||||
qoa_lms_t best_lms;
|
||||
|
||||
for (int scalefactor = 0; scalefactor < 16; scalefactor++) {
|
||||
|
||||
/* We have to reset the LMS state to the last known good one
|
||||
before trying each scalefactor, as each pass updates the LMS
|
||||
state when encoding. */
|
||||
qoa_lms_t lms = qoa->lms[c];
|
||||
qoa_uint64_t slice = scalefactor;
|
||||
qoa_uint64_t current_error = 0;
|
||||
|
||||
for (int si = slice_start; si < slice_end; si += channels) {
|
||||
int sample = sample_data[si];
|
||||
int predicted = qoa_lms_predict(&lms);
|
||||
|
||||
int residual = sample - predicted;
|
||||
int scaled = qoa_div(residual, scalefactor);
|
||||
int clamped = qoa_clamp(scaled, -8, 8);
|
||||
int quantized = qoa_quant_tab[clamped + 8];
|
||||
int dequantized = qoa_dequant_tab[scalefactor][quantized];
|
||||
int reconstructed = qoa_clamp(predicted + dequantized, -32768, 32767);
|
||||
|
||||
long long error = (sample - reconstructed);
|
||||
current_error += error * error;
|
||||
if (current_error > best_error) {
|
||||
break;
|
||||
}
|
||||
|
||||
qoa_lms_update(&lms, reconstructed, dequantized);
|
||||
slice = (slice << 3) | quantized;
|
||||
}
|
||||
|
||||
if (current_error < best_error) {
|
||||
best_error = current_error;
|
||||
best_slice = slice;
|
||||
best_lms = lms;
|
||||
}
|
||||
}
|
||||
|
||||
qoa->lms[c] = best_lms;
|
||||
#ifdef QOA_RECORD_TOTAL_ERROR
|
||||
qoa->error += best_error;
|
||||
#endif
|
||||
|
||||
/* If this slice was shorter than QOA_SLICE_LEN, we have to left-
|
||||
shift all encoded data, to ensure the rightmost bits are the empty
|
||||
ones. This should only happen in the last frame of a file as all
|
||||
slices are completely filled otherwise. */
|
||||
best_slice <<= (QOA_SLICE_LEN - slice_len) * 3;
|
||||
qoa_write_u64(best_slice, bytes, &p);
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void *qoa_encode(const short *sample_data, qoa_desc *qoa, unsigned int *out_len) {
|
||||
if (
|
||||
qoa->samples == 0 ||
|
||||
qoa->samplerate == 0 || qoa->samplerate > 0xffffff ||
|
||||
qoa->channels == 0 || qoa->channels > QOA_MAX_CHANNELS
|
||||
) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Calculate the encoded size and allocate */
|
||||
unsigned int num_frames = (qoa->samples + QOA_FRAME_LEN-1) / QOA_FRAME_LEN;
|
||||
unsigned int num_slices = (qoa->samples + QOA_SLICE_LEN-1) / QOA_SLICE_LEN;
|
||||
unsigned int encoded_size = 8 + /* 8 byte file header */
|
||||
num_frames * 8 + /* 8 byte frame headers */
|
||||
num_frames * QOA_LMS_LEN * 4 * qoa->channels + /* 4 * 4 bytes lms state per channel */
|
||||
num_slices * 8 * qoa->channels; /* 8 byte slices */
|
||||
|
||||
unsigned char *bytes = QOA_MALLOC(encoded_size);
|
||||
|
||||
for (int c = 0; c < qoa->channels; c++) {
|
||||
/* Set the initial LMS weights to {0, 0, -1, 2}. This helps with the
|
||||
prediction of the first few ms of a file. */
|
||||
qoa->lms[c].weights[0] = 0;
|
||||
qoa->lms[c].weights[1] = 0;
|
||||
qoa->lms[c].weights[2] = -(1<<13);
|
||||
qoa->lms[c].weights[3] = (1<<14);
|
||||
|
||||
/* Explicitly set the history samples to 0, as we might have some
|
||||
garbage in there. */
|
||||
for (int i = 0; i < QOA_LMS_LEN; i++) {
|
||||
qoa->lms[c].history[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Encode the header and go through all frames */
|
||||
unsigned int p = qoa_encode_header(qoa, bytes);
|
||||
#ifdef QOA_RECORD_TOTAL_ERROR
|
||||
qoa->error = 0;
|
||||
#endif
|
||||
|
||||
int frame_len = QOA_FRAME_LEN;
|
||||
for (int sample_index = 0; sample_index < qoa->samples; sample_index += frame_len) {
|
||||
frame_len = qoa_clamp(QOA_FRAME_LEN, 0, qoa->samples - sample_index);
|
||||
const short *frame_samples = sample_data + sample_index * qoa->channels;
|
||||
unsigned int frame_size = qoa_encode_frame(frame_samples, qoa, frame_len, bytes + p);
|
||||
p += frame_size;
|
||||
}
|
||||
|
||||
*out_len = p;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Decoder */
|
||||
|
||||
unsigned int qoa_max_frame_size(qoa_desc *qoa) {
|
||||
return QOA_FRAME_SIZE(qoa->channels, QOA_SLICES_PER_FRAME);
|
||||
}
|
||||
|
||||
unsigned int qoa_decode_header(const unsigned char *bytes, int size, qoa_desc *qoa) {
|
||||
unsigned int p = 0;
|
||||
if (size < QOA_MIN_FILESIZE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Read the file header, verify the magic number ('qoaf') and read the
|
||||
total number of samples. */
|
||||
qoa_uint64_t file_header = qoa_read_u64(bytes, &p);
|
||||
|
||||
if ((file_header >> 32) != QOA_MAGIC) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
qoa->samples = file_header & 0xffffffff;
|
||||
if (!qoa->samples) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Peek into the first frame header to get the number of channels and
|
||||
the samplerate. */
|
||||
qoa_uint64_t frame_header = qoa_read_u64(bytes, &p);
|
||||
qoa->channels = (frame_header >> 56) & 0x0000ff;
|
||||
qoa->samplerate = (frame_header >> 32) & 0xffffff;
|
||||
|
||||
if (qoa->channels == 0 || qoa->samples == 0 || qoa->samplerate == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 8;
|
||||
}
|
||||
|
||||
unsigned int qoa_decode_frame(const unsigned char *bytes, unsigned int size, qoa_desc *qoa, short *sample_data, unsigned int *frame_len) {
|
||||
unsigned int p = 0;
|
||||
*frame_len = 0;
|
||||
|
||||
if (size < 8 + QOA_LMS_LEN * 4 * qoa->channels) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read and verify the frame header */
|
||||
qoa_uint64_t frame_header = qoa_read_u64(bytes, &p);
|
||||
int channels = (frame_header >> 56) & 0x0000ff;
|
||||
int samplerate = (frame_header >> 32) & 0xffffff;
|
||||
int samples = (frame_header >> 16) & 0x00ffff;
|
||||
int frame_size = (frame_header ) & 0x00ffff;
|
||||
|
||||
int data_size = frame_size - 8 - QOA_LMS_LEN * 4 * channels;
|
||||
int num_slices = data_size / 8;
|
||||
int max_total_samples = num_slices * QOA_SLICE_LEN;
|
||||
|
||||
if (
|
||||
channels != qoa->channels ||
|
||||
samplerate != qoa->samplerate ||
|
||||
frame_size > size ||
|
||||
samples * channels > max_total_samples
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Read the LMS state: 4 x 2 bytes history, 4 x 2 bytes weights per channel */
|
||||
for (int c = 0; c < channels; c++) {
|
||||
qoa_uint64_t history = qoa_read_u64(bytes, &p);
|
||||
qoa_uint64_t weights = qoa_read_u64(bytes, &p);
|
||||
for (int i = 0; i < QOA_LMS_LEN; i++) {
|
||||
qoa->lms[c].history[i] = ((signed short)(history >> 48));
|
||||
history <<= 16;
|
||||
qoa->lms[c].weights[i] = ((signed short)(weights >> 48));
|
||||
weights <<= 16;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Decode all slices for all channels in this frame */
|
||||
for (int sample_index = 0; sample_index < samples; sample_index += QOA_SLICE_LEN) {
|
||||
for (int c = 0; c < channels; c++) {
|
||||
qoa_uint64_t slice = qoa_read_u64(bytes, &p);
|
||||
|
||||
int scalefactor = (slice >> 60) & 0xf;
|
||||
int slice_start = sample_index * channels + c;
|
||||
int slice_end = qoa_clamp(sample_index + QOA_SLICE_LEN, 0, samples) * channels + c;
|
||||
|
||||
for (int si = slice_start; si < slice_end; si += channels) {
|
||||
int predicted = qoa_lms_predict(&qoa->lms[c]);
|
||||
int quantized = (slice >> 57) & 0x7;
|
||||
int dequantized = qoa_dequant_tab[scalefactor][quantized];
|
||||
int reconstructed = qoa_clamp(predicted + dequantized, -32768, 32767);
|
||||
|
||||
sample_data[si] = reconstructed;
|
||||
slice <<= 3;
|
||||
|
||||
qoa_lms_update(&qoa->lms[c], reconstructed, dequantized);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*frame_len = samples;
|
||||
return p;
|
||||
}
|
||||
|
||||
short *qoa_decode(const unsigned char *bytes, int size, qoa_desc *qoa) {
|
||||
unsigned int p = qoa_decode_header(bytes, size, qoa);
|
||||
if (!p) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Calculate the required size of the sample buffer and allocate */
|
||||
int total_samples = qoa->samples * qoa->channels;
|
||||
short *sample_data = QOA_MALLOC(total_samples * sizeof(short));
|
||||
|
||||
unsigned int sample_index = 0;
|
||||
unsigned int frame_len;
|
||||
unsigned int frame_size;
|
||||
|
||||
/* Decode all frames */
|
||||
do {
|
||||
short *sample_ptr = sample_data + sample_index * qoa->channels;
|
||||
frame_size = qoa_decode_frame(bytes + p, size - p, qoa, sample_ptr, &frame_len);
|
||||
|
||||
p += frame_size;
|
||||
sample_index += frame_len;
|
||||
} while (frame_size && sample_index < qoa->samples);
|
||||
|
||||
qoa->samples = sample_index;
|
||||
return sample_data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
File read/write convenience functions */
|
||||
|
||||
#ifndef QOA_NO_STDIO
|
||||
#include <stdio.h>
|
||||
|
||||
int qoa_write(const char *filename, const short *sample_data, qoa_desc *qoa) {
|
||||
FILE *f = fopen(filename, "wb");
|
||||
unsigned int size;
|
||||
void *encoded;
|
||||
|
||||
if (!f) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
encoded = qoa_encode(sample_data, qoa, &size);
|
||||
if (!encoded) {
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fwrite(encoded, 1, size, f);
|
||||
fclose(f);
|
||||
|
||||
QOA_FREE(encoded);
|
||||
return size;
|
||||
}
|
||||
|
||||
void *qoa_read(const char *filename, qoa_desc *qoa) {
|
||||
FILE *f = fopen(filename, "rb");
|
||||
int size, bytes_read;
|
||||
void *data;
|
||||
short *sample_data;
|
||||
|
||||
if (!f) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_END);
|
||||
size = ftell(f);
|
||||
if (size <= 0) {
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
data = QOA_MALLOC(size);
|
||||
if (!data) {
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bytes_read = fread(data, 1, size, f);
|
||||
fclose(f);
|
||||
|
||||
sample_data = qoa_decode(data, bytes_read, qoa);
|
||||
QOA_FREE(data);
|
||||
return sample_data;
|
||||
}
|
||||
|
||||
#endif /* QOA_NO_STDIO */
|
||||
#endif /* QOA_IMPLEMENTATION */
|
278
raylib/external/qoaplay.c
vendored
Normal file
278
raylib/external/qoaplay.c
vendored
Normal file
|
@ -0,0 +1,278 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* qoaplay - QOA stream playing helper functions
|
||||
*
|
||||
* qoaplay is a tiny abstraction to read and decode a QOA file "on the fly".
|
||||
* It reads and decodes one frame at a time with minimal memory requirements.
|
||||
* qoaplay also provides some functions to seek to a specific frame.
|
||||
*
|
||||
* LICENSE: MIT License
|
||||
*
|
||||
* Copyright (c) 2023 Dominic Szablewski (@phoboslab), reviewed by Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
**********************************************************************************************/
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
// QOA streaming data descriptor
|
||||
typedef struct {
|
||||
qoa_desc info; // QOA descriptor data
|
||||
|
||||
FILE *file; // QOA file to read, if NULL, using memory buffer -> file_data
|
||||
unsigned char *file_data; // QOA file data on memory
|
||||
unsigned int file_data_size; // QOA file data on memory size
|
||||
unsigned int file_data_offset; // QOA file data on memory offset for next read
|
||||
|
||||
unsigned int first_frame_pos; // First frame position (after QOA header, required for offset)
|
||||
unsigned int sample_position; // Current streaming sample position
|
||||
|
||||
unsigned char *buffer; // Buffer used to read samples from file/memory (used on decoding)
|
||||
unsigned int buffer_len; // Buffer length to read samples for streaming
|
||||
|
||||
short *sample_data; // Sample data decoded
|
||||
unsigned int sample_data_len; // Sample data decoded length
|
||||
unsigned int sample_data_pos; // Sample data decoded position
|
||||
|
||||
} qoaplay_desc;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" { // Prevents name mangling of functions
|
||||
#endif
|
||||
|
||||
qoaplay_desc *qoaplay_open(const char *path);
|
||||
qoaplay_desc *qoaplay_open_memory(const unsigned char *data, int data_size);
|
||||
void qoaplay_close(qoaplay_desc *qoa_ctx);
|
||||
|
||||
void qoaplay_rewind(qoaplay_desc *qoa_ctx);
|
||||
void qoaplay_seek_frame(qoaplay_desc *qoa_ctx, int frame);
|
||||
unsigned int qoaplay_decode(qoaplay_desc *qoa_ctx, float *sample_data, int num_samples);
|
||||
unsigned int qoaplay_decode_frame(qoaplay_desc *qoa_ctx);
|
||||
double qoaplay_get_duration(qoaplay_desc *qoa_ctx);
|
||||
double qoaplay_get_time(qoaplay_desc *qoa_ctx);
|
||||
int qoaplay_get_frame(qoaplay_desc *qoa_ctx);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // Prevents name mangling of functions
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Open QOA file, keep FILE pointer to keep reading from file
|
||||
qoaplay_desc *qoaplay_open(const char *path)
|
||||
{
|
||||
FILE *file = fopen(path, "rb");
|
||||
if (!file) return NULL;
|
||||
|
||||
// Read and decode the file header
|
||||
unsigned char header[QOA_MIN_FILESIZE];
|
||||
int read = fread(header, QOA_MIN_FILESIZE, 1, file);
|
||||
if (!read) return NULL;
|
||||
|
||||
qoa_desc qoa;
|
||||
unsigned int first_frame_pos = qoa_decode_header(header, QOA_MIN_FILESIZE, &qoa);
|
||||
if (!first_frame_pos) return NULL;
|
||||
|
||||
// Rewind the file back to beginning of the first frame
|
||||
fseek(file, first_frame_pos, SEEK_SET);
|
||||
|
||||
// Allocate one chunk of memory for the qoaplay_desc struct
|
||||
// + the sample data for one frame
|
||||
// + a buffer to hold one frame of encoded data
|
||||
unsigned int buffer_size = qoa_max_frame_size(&qoa);
|
||||
unsigned int sample_data_size = qoa.channels*QOA_FRAME_LEN*sizeof(short)*2;
|
||||
qoaplay_desc *qoa_ctx = QOA_MALLOC(sizeof(qoaplay_desc) + buffer_size + sample_data_size);
|
||||
memset(qoa_ctx, 0, sizeof(qoaplay_desc));
|
||||
|
||||
qoa_ctx->file = file;
|
||||
qoa_ctx->file_data = NULL;
|
||||
qoa_ctx->file_data_size = 0;
|
||||
qoa_ctx->file_data_offset = 0;
|
||||
qoa_ctx->first_frame_pos = first_frame_pos;
|
||||
|
||||
// Setup data pointers to previously allocated data
|
||||
qoa_ctx->buffer = ((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc);
|
||||
qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + buffer_size);
|
||||
|
||||
qoa_ctx->info.channels = qoa.channels;
|
||||
qoa_ctx->info.samplerate = qoa.samplerate;
|
||||
qoa_ctx->info.samples = qoa.samples;
|
||||
|
||||
return qoa_ctx;
|
||||
}
|
||||
|
||||
// Open QOA file from memory, no FILE pointer required
|
||||
qoaplay_desc *qoaplay_open_memory(const unsigned char *data, int data_size)
|
||||
{
|
||||
// Read and decode the file header
|
||||
unsigned char header[QOA_MIN_FILESIZE];
|
||||
memcpy(header, data, QOA_MIN_FILESIZE);
|
||||
|
||||
qoa_desc qoa;
|
||||
unsigned int first_frame_pos = qoa_decode_header(header, QOA_MIN_FILESIZE, &qoa);
|
||||
if (!first_frame_pos) return NULL;
|
||||
|
||||
// Allocate one chunk of memory for the qoaplay_desc struct
|
||||
// + the sample data for one frame
|
||||
// + a buffer to hold one frame of encoded data
|
||||
unsigned int buffer_size = qoa_max_frame_size(&qoa);
|
||||
unsigned int sample_data_size = qoa.channels*QOA_FRAME_LEN*sizeof(short)*2;
|
||||
qoaplay_desc *qoa_ctx = QOA_MALLOC(sizeof(qoaplay_desc) + buffer_size + sample_data_size);
|
||||
memset(qoa_ctx, 0, sizeof(qoaplay_desc));
|
||||
|
||||
qoa_ctx->file = NULL;
|
||||
|
||||
// Keep a copy of file data provided to be managed internally
|
||||
qoa_ctx->file_data = (unsigned char *)QOA_MALLOC(data_size);
|
||||
memcpy(qoa_ctx->file_data, data, data_size);
|
||||
qoa_ctx->file_data_size = data_size;
|
||||
qoa_ctx->file_data_offset = 0;
|
||||
qoa_ctx->first_frame_pos = first_frame_pos;
|
||||
|
||||
// Setup data pointers to previously allocated data
|
||||
qoa_ctx->buffer = ((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc);
|
||||
qoa_ctx->sample_data = (short *)(((unsigned char *)qoa_ctx) + sizeof(qoaplay_desc) + buffer_size);
|
||||
|
||||
qoa_ctx->info.channels = qoa.channels;
|
||||
qoa_ctx->info.samplerate = qoa.samplerate;
|
||||
qoa_ctx->info.samples = qoa.samples;
|
||||
|
||||
return qoa_ctx;
|
||||
}
|
||||
|
||||
// Close QOA file (if open) and free internal memory
|
||||
void qoaplay_close(qoaplay_desc *qoa_ctx)
|
||||
{
|
||||
if (qoa_ctx->file) fclose(qoa_ctx->file);
|
||||
|
||||
if ((qoa_ctx->file_data) && (qoa_ctx->file_data_size > 0))
|
||||
{
|
||||
QOA_FREE(qoa_ctx->file_data);
|
||||
qoa_ctx->file_data_size = 0;
|
||||
}
|
||||
|
||||
QOA_FREE(qoa_ctx);
|
||||
}
|
||||
|
||||
// Decode one frame from QOA data
|
||||
unsigned int qoaplay_decode_frame(qoaplay_desc *qoa_ctx)
|
||||
{
|
||||
if (qoa_ctx->file) qoa_ctx->buffer_len = fread(qoa_ctx->buffer, 1, qoa_max_frame_size(&qoa_ctx->info), qoa_ctx->file);
|
||||
else
|
||||
{
|
||||
qoa_ctx->buffer_len = qoa_max_frame_size(&qoa_ctx->info);
|
||||
memcpy(qoa_ctx->buffer, qoa_ctx->file_data + qoa_ctx->file_data_offset, qoa_ctx->buffer_len);
|
||||
qoa_ctx->file_data_offset += qoa_ctx->buffer_len;
|
||||
}
|
||||
|
||||
unsigned int frame_len;
|
||||
qoa_decode_frame(qoa_ctx->buffer, qoa_ctx->buffer_len, &qoa_ctx->info, qoa_ctx->sample_data, &frame_len);
|
||||
qoa_ctx->sample_data_pos = 0;
|
||||
qoa_ctx->sample_data_len = frame_len;
|
||||
|
||||
return frame_len;
|
||||
}
|
||||
|
||||
// Rewind QOA file or memory pointer to beginning
|
||||
void qoaplay_rewind(qoaplay_desc *qoa_ctx)
|
||||
{
|
||||
if (qoa_ctx->file) fseek(qoa_ctx->file, qoa_ctx->first_frame_pos, SEEK_SET);
|
||||
else qoa_ctx->file_data_offset = 0;
|
||||
|
||||
qoa_ctx->sample_position = 0;
|
||||
qoa_ctx->sample_data_len = 0;
|
||||
qoa_ctx->sample_data_pos = 0;
|
||||
}
|
||||
|
||||
// Decode required QOA frames
|
||||
unsigned int qoaplay_decode(qoaplay_desc *qoa_ctx, float *sample_data, int num_samples)
|
||||
{
|
||||
int src_index = qoa_ctx->sample_data_pos*qoa_ctx->info.channels;
|
||||
int dst_index = 0;
|
||||
|
||||
for (int i = 0; i < num_samples; i++)
|
||||
{
|
||||
// Do we have to decode more samples?
|
||||
if (qoa_ctx->sample_data_len - qoa_ctx->sample_data_pos == 0)
|
||||
{
|
||||
if (!qoaplay_decode_frame(qoa_ctx))
|
||||
{
|
||||
// Loop to the beginning
|
||||
qoaplay_rewind(qoa_ctx);
|
||||
qoaplay_decode_frame(qoa_ctx);
|
||||
}
|
||||
|
||||
src_index = 0;
|
||||
}
|
||||
|
||||
// Normalize to -1..1 floats and write to dest
|
||||
for (int c = 0; c < qoa_ctx->info.channels; c++)
|
||||
{
|
||||
sample_data[dst_index++] = qoa_ctx->sample_data[src_index++]/32768.0;
|
||||
}
|
||||
|
||||
qoa_ctx->sample_data_pos++;
|
||||
qoa_ctx->sample_position++;
|
||||
}
|
||||
|
||||
return num_samples;
|
||||
}
|
||||
|
||||
// Get QOA total time duration in seconds
|
||||
double qoaplay_get_duration(qoaplay_desc *qoa_ctx)
|
||||
{
|
||||
return (double)qoa_ctx->info.samples/(double)qoa_ctx->info.samplerate;
|
||||
}
|
||||
|
||||
// Get QOA current time position in seconds
|
||||
double qoaplay_get_time(qoaplay_desc *qoa_ctx)
|
||||
{
|
||||
return (double)qoa_ctx->sample_position/(double)qoa_ctx->info.samplerate;
|
||||
}
|
||||
|
||||
// Get QOA current audio frame
|
||||
int qoaplay_get_frame(qoaplay_desc *qoa_ctx)
|
||||
{
|
||||
return qoa_ctx->sample_position/QOA_FRAME_LEN;
|
||||
}
|
||||
|
||||
// Seek QOA audio frame
|
||||
void qoaplay_seek_frame(qoaplay_desc *qoa_ctx, int frame)
|
||||
{
|
||||
if (frame < 0) frame = 0;
|
||||
|
||||
if (frame > qoa_ctx->info.samples/QOA_FRAME_LEN) frame = qoa_ctx->info.samples/QOA_FRAME_LEN;
|
||||
|
||||
qoa_ctx->sample_position = frame*QOA_FRAME_LEN;
|
||||
qoa_ctx->sample_data_len = 0;
|
||||
qoa_ctx->sample_data_pos = 0;
|
||||
|
||||
unsigned int offset = qoa_ctx->first_frame_pos + frame*qoa_max_frame_size(&qoa_ctx->info);
|
||||
|
||||
if (qoa_ctx->file) fseek(qoa_ctx->file, offset, SEEK_SET);
|
||||
else qoa_ctx->file_data_offset = offset;
|
||||
}
|
42
raylib/external/qoi.h
vendored
42
raylib/external/qoi.h
vendored
|
@ -1,31 +1,11 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2021, Dominic Szablewski - https://phoboslab.org
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
QOI - The "Quite OK Image" format for fast, lossless image compression
|
||||
|
||||
Dominic Szablewski - https://phoboslab.org
|
||||
|
||||
|
||||
-- LICENSE: The MIT License(MIT)
|
||||
|
||||
Copyright(c) 2021 Dominic Szablewski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files(the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions :
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
-- About
|
||||
|
||||
QOI encodes and decodes images in a lossless format. Compared to stb_image and
|
||||
|
@ -424,13 +404,12 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
|
|||
channels = desc->channels;
|
||||
|
||||
for (px_pos = 0; px_pos < px_len; px_pos += channels) {
|
||||
if (channels == 4) {
|
||||
px = *(qoi_rgba_t *)(pixels + px_pos);
|
||||
}
|
||||
else {
|
||||
px.rgba.r = pixels[px_pos + 0];
|
||||
px.rgba.g = pixels[px_pos + 1];
|
||||
px.rgba.b = pixels[px_pos + 2];
|
||||
|
||||
if (channels == 4) {
|
||||
px.rgba.a = pixels[px_pos + 3];
|
||||
}
|
||||
|
||||
if (px.v == px_prev.v) {
|
||||
|
@ -598,13 +577,12 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
|
|||
index[QOI_COLOR_HASH(px) % 64] = px;
|
||||
}
|
||||
|
||||
if (channels == 4) {
|
||||
*(qoi_rgba_t*)(pixels + px_pos) = px;
|
||||
}
|
||||
else {
|
||||
pixels[px_pos + 0] = px.rgba.r;
|
||||
pixels[px_pos + 1] = px.rgba.g;
|
||||
pixels[px_pos + 2] = px.rgba.b;
|
||||
|
||||
if (channels == 4) {
|
||||
pixels[px_pos + 3] = px.rgba.a;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
6
raylib/external/rl_gputex.h
vendored
6
raylib/external/rl_gputex.h
vendored
|
@ -477,10 +477,10 @@ int rl_save_ktx(const char *file_name, void *data, int width, int height, int fo
|
|||
// Calculate file data_size required
|
||||
int data_size = sizeof(ktx_header);
|
||||
|
||||
for (int i = 0, width = width, height = height; i < mipmaps; i++)
|
||||
for (int i = 0, w = width, h = height; i < mipmaps; i++)
|
||||
{
|
||||
data_size += get_pixel_data_size(width, height, format);
|
||||
width /= 2; height /= 2;
|
||||
data_size += get_pixel_data_size(w, h, format);
|
||||
w /= 2; h /= 2;
|
||||
}
|
||||
|
||||
unsigned char *file_data = RL_CALLOC(data_size, 1);
|
||||
|
|
142
raylib/external/stb_image.h
vendored
142
raylib/external/stb_image.h
vendored
|
@ -1,4 +1,4 @@
|
|||
/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb
|
||||
/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb
|
||||
no warranty implied; use at your own risk
|
||||
|
||||
Do this:
|
||||
|
@ -48,6 +48,7 @@ LICENSE
|
|||
|
||||
RECENT REVISION HISTORY:
|
||||
|
||||
2.28 (2023-01-29) many error fixes, security errors, just tons of stuff
|
||||
2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
|
||||
2.26 (2020-07-13) many minor fixes
|
||||
2.25 (2020-02-02) fix warnings
|
||||
|
@ -108,7 +109,7 @@ RECENT REVISION HISTORY:
|
|||
Cass Everitt Ryamond Barbiero github:grim210
|
||||
Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw
|
||||
Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus
|
||||
Josh Tobin Matthew Gregan github:poppolopoppo
|
||||
Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo
|
||||
Julian Raschke Gregory Mullen Christian Floisand github:darealshinji
|
||||
Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007
|
||||
Brad Weinberger Matvey Cherevko github:mosra
|
||||
|
@ -140,7 +141,7 @@ RECENT REVISION HISTORY:
|
|||
// // ... x = width, y = height, n = # 8-bit components per pixel ...
|
||||
// // ... replace '0' with '1'..'4' to force that many components per pixel
|
||||
// // ... but 'n' will always be the number that it would have been if you said 0
|
||||
// stbi_image_free(data)
|
||||
// stbi_image_free(data);
|
||||
//
|
||||
// Standard parameters:
|
||||
// int *x -- outputs image width in pixels
|
||||
|
@ -635,7 +636,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) || defined(__SYMBIAN32__)
|
||||
typedef unsigned short stbi__uint16;
|
||||
typedef signed short stbi__int16;
|
||||
typedef unsigned int stbi__uint32;
|
||||
|
@ -1063,6 +1064,23 @@ static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
|
|||
}
|
||||
#endif
|
||||
|
||||
// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow.
|
||||
static int stbi__addints_valid(int a, int b)
|
||||
{
|
||||
if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow
|
||||
if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0.
|
||||
return a <= INT_MAX - b;
|
||||
}
|
||||
|
||||
// returns 1 if the product of two signed shorts is valid, 0 on overflow.
|
||||
static int stbi__mul2shorts_valid(short a, short b)
|
||||
{
|
||||
if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow
|
||||
if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid
|
||||
if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN
|
||||
return a >= SHRT_MIN / b;
|
||||
}
|
||||
|
||||
// stbi__err - error
|
||||
// stbi__errpf - error returning pointer to float
|
||||
// stbi__errpuc - error returning pointer to unsigned char
|
||||
|
@ -1985,9 +2003,12 @@ static int stbi__build_huffman(stbi__huffman *h, int *count)
|
|||
int i,j,k=0;
|
||||
unsigned int code;
|
||||
// build size list for each symbol (from JPEG spec)
|
||||
for (i=0; i < 16; ++i)
|
||||
for (j=0; j < count[i]; ++j)
|
||||
for (i=0; i < 16; ++i) {
|
||||
for (j=0; j < count[i]; ++j) {
|
||||
h->size[k++] = (stbi_uc) (i+1);
|
||||
if(k >= 257) return stbi__err("bad size list","Corrupt JPEG");
|
||||
}
|
||||
}
|
||||
h->size[k] = 0;
|
||||
|
||||
// compute actual symbols (from jpeg spec)
|
||||
|
@ -2112,6 +2133,8 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
|
|||
|
||||
// convert the huffman code to the symbol id
|
||||
c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];
|
||||
if(c < 0 || c >= 256) // symbol id out of bounds!
|
||||
return -1;
|
||||
STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);
|
||||
|
||||
// convert the id to a symbol
|
||||
|
@ -2130,6 +2153,7 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
|
|||
unsigned int k;
|
||||
int sgn;
|
||||
if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
|
||||
if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing
|
||||
|
||||
sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative)
|
||||
k = stbi_lrot(j->code_buffer, n);
|
||||
|
@ -2144,6 +2168,7 @@ stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)
|
|||
{
|
||||
unsigned int k;
|
||||
if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
|
||||
if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing
|
||||
k = stbi_lrot(j->code_buffer, n);
|
||||
j->code_buffer = k & ~stbi__bmask[n];
|
||||
k &= stbi__bmask[n];
|
||||
|
@ -2155,6 +2180,7 @@ stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
|
|||
{
|
||||
unsigned int k;
|
||||
if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);
|
||||
if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing
|
||||
k = j->code_buffer;
|
||||
j->code_buffer <<= 1;
|
||||
--j->code_bits;
|
||||
|
@ -2192,8 +2218,10 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman
|
|||
memset(data,0,64*sizeof(data[0]));
|
||||
|
||||
diff = t ? stbi__extend_receive(j, t) : 0;
|
||||
if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG");
|
||||
dc = j->img_comp[b].dc_pred + diff;
|
||||
j->img_comp[b].dc_pred = dc;
|
||||
if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
|
||||
data[0] = (short) (dc * dequant[0]);
|
||||
|
||||
// decode AC components, see JPEG spec
|
||||
|
@ -2207,6 +2235,7 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman
|
|||
if (r) { // fast-AC path
|
||||
k += (r >> 4) & 15; // run
|
||||
s = r & 15; // combined length
|
||||
if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available");
|
||||
j->code_buffer <<= s;
|
||||
j->code_bits -= s;
|
||||
// decode into unzigzag'd location
|
||||
|
@ -2246,8 +2275,10 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__
|
|||
if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
|
||||
diff = t ? stbi__extend_receive(j, t) : 0;
|
||||
|
||||
if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG");
|
||||
dc = j->img_comp[b].dc_pred + diff;
|
||||
j->img_comp[b].dc_pred = dc;
|
||||
if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
|
||||
data[0] = (short) (dc * (1 << j->succ_low));
|
||||
} else {
|
||||
// refinement scan for DC coefficient
|
||||
|
@ -2282,6 +2313,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
|
|||
if (r) { // fast-AC path
|
||||
k += (r >> 4) & 15; // run
|
||||
s = r & 15; // combined length
|
||||
if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available");
|
||||
j->code_buffer <<= s;
|
||||
j->code_bits -= s;
|
||||
zig = stbi__jpeg_dezigzag[k++];
|
||||
|
@ -3102,6 +3134,7 @@ static int stbi__process_marker(stbi__jpeg *z, int m)
|
|||
sizes[i] = stbi__get8(z->s);
|
||||
n += sizes[i];
|
||||
}
|
||||
if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values!
|
||||
L -= 17;
|
||||
if (tc == 0) {
|
||||
if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;
|
||||
|
@ -3351,6 +3384,28 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)
|
||||
{
|
||||
// some JPEGs have junk at end, skip over it but if we find what looks
|
||||
// like a valid marker, resume there
|
||||
while (!stbi__at_eof(j->s)) {
|
||||
int x = stbi__get8(j->s);
|
||||
while (x == 255) { // might be a marker
|
||||
if (stbi__at_eof(j->s)) return STBI__MARKER_none;
|
||||
x = stbi__get8(j->s);
|
||||
if (x != 0x00 && x != 0xff) {
|
||||
// not a stuffed zero or lead-in to another marker, looks
|
||||
// like an actual marker, return it
|
||||
return x;
|
||||
}
|
||||
// stuffed zero has x=0 now which ends the loop, meaning we go
|
||||
// back to regular scan loop.
|
||||
// repeated 0xff keeps trying to read the next byte of the marker.
|
||||
}
|
||||
}
|
||||
return STBI__MARKER_none;
|
||||
}
|
||||
|
||||
// decode image to YCbCr format
|
||||
static int stbi__decode_jpeg_image(stbi__jpeg *j)
|
||||
{
|
||||
|
@ -3367,25 +3422,22 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j)
|
|||
if (!stbi__process_scan_header(j)) return 0;
|
||||
if (!stbi__parse_entropy_coded_data(j)) return 0;
|
||||
if (j->marker == STBI__MARKER_none ) {
|
||||
// handle 0s at the end of image data from IP Kamera 9060
|
||||
while (!stbi__at_eof(j->s)) {
|
||||
int x = stbi__get8(j->s);
|
||||
if (x == 255) {
|
||||
j->marker = stbi__get8(j->s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
j->marker = stbi__skip_jpeg_junk_at_end(j);
|
||||
// if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0
|
||||
}
|
||||
m = stbi__get_marker(j);
|
||||
if (STBI__RESTART(m))
|
||||
m = stbi__get_marker(j);
|
||||
} else if (stbi__DNL(m)) {
|
||||
int Ld = stbi__get16be(j->s);
|
||||
stbi__uint32 NL = stbi__get16be(j->s);
|
||||
if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG");
|
||||
if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG");
|
||||
} else {
|
||||
if (!stbi__process_marker(j, m)) return 0;
|
||||
}
|
||||
m = stbi__get_marker(j);
|
||||
} else {
|
||||
if (!stbi__process_marker(j, m)) return 1;
|
||||
m = stbi__get_marker(j);
|
||||
}
|
||||
}
|
||||
if (j->progressive)
|
||||
stbi__jpeg_finish(j);
|
||||
|
@ -3976,6 +4028,7 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re
|
|||
unsigned char* result;
|
||||
stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));
|
||||
if (!j) return stbi__errpuc("outofmem", "Out of memory");
|
||||
memset(j, 0, sizeof(stbi__jpeg));
|
||||
STBI_NOTUSED(ri);
|
||||
j->s = s;
|
||||
stbi__setup_jpeg(j);
|
||||
|
@ -3989,6 +4042,7 @@ static int stbi__jpeg_test(stbi__context *s)
|
|||
int r;
|
||||
stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg));
|
||||
if (!j) return stbi__err("outofmem", "Out of memory");
|
||||
memset(j, 0, sizeof(stbi__jpeg));
|
||||
j->s = s;
|
||||
stbi__setup_jpeg(j);
|
||||
r = stbi__decode_jpeg_header(j, STBI__SCAN_type);
|
||||
|
@ -4014,6 +4068,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)
|
|||
int result;
|
||||
stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg)));
|
||||
if (!j) return stbi__err("outofmem", "Out of memory");
|
||||
memset(j, 0, sizeof(stbi__jpeg));
|
||||
j->s = s;
|
||||
result = stbi__jpeg_info_raw(j, x, y, comp);
|
||||
STBI_FREE(j);
|
||||
|
@ -4256,11 +4311,12 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
|
|||
a->zout = zout;
|
||||
return 1;
|
||||
}
|
||||
if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data
|
||||
z -= 257;
|
||||
len = stbi__zlength_base[z];
|
||||
if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);
|
||||
z = stbi__zhuffman_decode(a, &a->z_distance);
|
||||
if (z < 0) return stbi__err("bad huffman code","Corrupt PNG");
|
||||
if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data
|
||||
dist = stbi__zdist_base[z];
|
||||
if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
|
||||
if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
|
||||
|
@ -4955,7 +5011,7 @@ STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
|
|||
static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set;
|
||||
static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set;
|
||||
|
||||
STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply)
|
||||
STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply)
|
||||
{
|
||||
stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply;
|
||||
stbi__unpremultiply_on_load_set = 1;
|
||||
|
@ -5064,14 +5120,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
|
|||
if (!pal_img_n) {
|
||||
s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
|
||||
if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
|
||||
if (scan == STBI__SCAN_header) return 1;
|
||||
} else {
|
||||
// if paletted, then pal_n is our final components, and
|
||||
// img_n is # components to decompress/filter.
|
||||
s->img_n = 1;
|
||||
if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG");
|
||||
// if SCAN_header, have to scan to see if we have a tRNS
|
||||
}
|
||||
// even with SCAN_header, have to scan to see if we have a tRNS
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -5103,6 +5158,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
|
|||
if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG");
|
||||
if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG");
|
||||
has_trans = 1;
|
||||
// non-paletted with tRNS = constant alpha. if header-scanning, we can stop now.
|
||||
if (scan == STBI__SCAN_header) { ++s->img_n; return 1; }
|
||||
if (z->depth == 16) {
|
||||
for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
|
||||
} else {
|
||||
|
@ -5115,7 +5172,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
|
|||
case STBI__PNG_TYPE('I','D','A','T'): {
|
||||
if (first) return stbi__err("first not IHDR", "Corrupt PNG");
|
||||
if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
|
||||
if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
|
||||
if (scan == STBI__SCAN_header) {
|
||||
// header scan definitely stops at first IDAT
|
||||
if (pal_img_n)
|
||||
s->img_n = pal_img_n;
|
||||
return 1;
|
||||
}
|
||||
if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes");
|
||||
if ((int)(ioff + c.length) < (int)ioff) return 0;
|
||||
if (ioff + c.length > idata_limit) {
|
||||
stbi__uint32 idata_limit_old = idata_limit;
|
||||
|
@ -5498,8 +5561,22 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
|
|||
psize = (info.offset - info.extra_read - info.hsz) >> 2;
|
||||
}
|
||||
if (psize == 0) {
|
||||
if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) {
|
||||
// accept some number of extra bytes after the header, but if the offset points either to before
|
||||
// the header ends or implies a large amount of extra data, reject the file as malformed
|
||||
int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original);
|
||||
int header_limit = 1024; // max we actually read is below 256 bytes currently.
|
||||
int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size.
|
||||
if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) {
|
||||
return stbi__errpuc("bad header", "Corrupt BMP");
|
||||
}
|
||||
// we established that bytes_read_so_far is positive and sensible.
|
||||
// the first half of this test rejects offsets that are either too small positives, or
|
||||
// negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn
|
||||
// ensures the number computed in the second half of the test can't overflow.
|
||||
if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) {
|
||||
return stbi__errpuc("bad offset", "Corrupt BMP");
|
||||
} else {
|
||||
stbi__skip(s, info.offset - bytes_read_so_far);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7187,12 +7264,12 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re
|
|||
// Run
|
||||
value = stbi__get8(s);
|
||||
count -= 128;
|
||||
if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
|
||||
if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
|
||||
for (z = 0; z < count; ++z)
|
||||
scanline[i++ * 4 + k] = value;
|
||||
} else {
|
||||
// Dump
|
||||
if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
|
||||
if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
|
||||
for (z = 0; z < count; ++z)
|
||||
scanline[i++ * 4 + k] = stbi__get8(s);
|
||||
}
|
||||
|
@ -7446,10 +7523,17 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req
|
|||
|
||||
out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0);
|
||||
if (!out) return stbi__errpuc("outofmem", "Out of memory");
|
||||
stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8));
|
||||
if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) {
|
||||
STBI_FREE(out);
|
||||
return stbi__errpuc("bad PNM", "PNM file truncated");
|
||||
}
|
||||
|
||||
if (req_comp && req_comp != s->img_n) {
|
||||
if (ri->bits_per_channel == 16) {
|
||||
out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y);
|
||||
} else {
|
||||
out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);
|
||||
}
|
||||
if (out == NULL) return out; // stbi__convert_format frees input on failure
|
||||
}
|
||||
return out;
|
||||
|
@ -7486,6 +7570,8 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c)
|
|||
while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {
|
||||
value = value*10 + (*c - '0');
|
||||
*c = (char) stbi__get8(s);
|
||||
if((value > 214748364) || (value == 214748364 && *c > '7'))
|
||||
return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int");
|
||||
}
|
||||
|
||||
return value;
|
||||
|
@ -7516,9 +7602,13 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)
|
|||
stbi__pnm_skip_whitespace(s, &c);
|
||||
|
||||
*x = stbi__pnm_getinteger(s, &c); // read width
|
||||
if(*x == 0)
|
||||
return stbi__err("invalid width", "PPM image header had zero or overflowing width");
|
||||
stbi__pnm_skip_whitespace(s, &c);
|
||||
|
||||
*y = stbi__pnm_getinteger(s, &c); // read height
|
||||
if (*y == 0)
|
||||
return stbi__err("invalid width", "PPM image header had zero or overflowing width");
|
||||
stbi__pnm_skip_whitespace(s, &c);
|
||||
|
||||
maxv = stbi__pnm_getinteger(s, &c); // read max value
|
||||
|
|
File diff suppressed because it is too large
Load diff
650
raylib/raudio.c
650
raylib/raudio.c
File diff suppressed because it is too large
Load diff
|
@ -141,24 +141,6 @@ func ResumeSound(sound Sound) {
|
|||
C.ResumeSound(*csound)
|
||||
}
|
||||
|
||||
// PlaySoundMulti - Play a sound (using multichannel buffer pool)
|
||||
func PlaySoundMulti(sound Sound) {
|
||||
csound := sound.cptr()
|
||||
C.PlaySoundMulti(*csound)
|
||||
}
|
||||
|
||||
// StopSoundMulti - Stop any sound playing (using multichannel buffer pool)
|
||||
func StopSoundMulti() {
|
||||
C.StopSoundMulti()
|
||||
}
|
||||
|
||||
// GetSoundsPlaying - Get number of sounds playing in the multichannel
|
||||
func GetSoundsPlaying() int {
|
||||
ret := C.GetSoundsPlaying()
|
||||
v := int(ret)
|
||||
return v
|
||||
}
|
||||
|
||||
// IsSoundPlaying - Check if a sound is currently playing
|
||||
func IsSoundPlaying(sound Sound) bool {
|
||||
csound := sound.cptr()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**********************************************************************************************
|
||||
*
|
||||
* raylib v4.5-dev - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com)
|
||||
* raylib v4.5 - A simple and easy-to-use library to enjoy videogames programming (www.raylib.com)
|
||||
*
|
||||
* FEATURES:
|
||||
* - NO external dependencies, all required libraries included with raylib
|
||||
|
@ -57,7 +57,7 @@
|
|||
* raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||
* BSD-like license that allows static linking with closed source software:
|
||||
*
|
||||
* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||
* will the authors be held liable for any damages arising from the use of this software.
|
||||
|
@ -81,7 +81,10 @@
|
|||
|
||||
#include <stdarg.h> // Required for: va_list - Only used by TraceLogCallback
|
||||
|
||||
#define RAYLIB_VERSION "4.5-dev"
|
||||
#define RAYLIB_VERSION_MAJOR 4
|
||||
#define RAYLIB_VERSION_MINOR 5
|
||||
#define RAYLIB_VERSION_PATCH 0
|
||||
#define RAYLIB_VERSION "4.5"
|
||||
|
||||
// Function specifiers in case library is build/used as a shared library (Windows)
|
||||
// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
|
||||
|
@ -213,7 +216,7 @@ typedef struct Vector4 {
|
|||
// Quaternion, 4 components (Vector4 alias)
|
||||
typedef Vector4 Quaternion;
|
||||
|
||||
// Matrix, 4x4 components, column major, OpenGL style, right handed
|
||||
// Matrix, 4x4 components, column major, OpenGL style, right-handed
|
||||
typedef struct Matrix {
|
||||
float m0, m4, m8, m12; // Matrix first row (4 components)
|
||||
float m1, m5, m9, m13; // Matrix second row (4 components)
|
||||
|
@ -410,8 +413,8 @@ typedef struct Ray {
|
|||
// RayCollision, ray hit information
|
||||
typedef struct RayCollision {
|
||||
bool hit; // Did the ray hit something?
|
||||
float distance; // Distance to nearest hit
|
||||
Vector3 point; // Point of nearest hit
|
||||
float distance; // Distance to the nearest hit
|
||||
Vector3 point; // Point of the nearest hit
|
||||
Vector3 normal; // Surface normal of hit
|
||||
} RayCollision;
|
||||
|
||||
|
@ -678,7 +681,7 @@ typedef enum {
|
|||
MOUSE_CURSOR_RESIZE_NS = 6, // Vertical resize/move arrow shape
|
||||
MOUSE_CURSOR_RESIZE_NWSE = 7, // Top-left to bottom-right diagonal resize/move arrow shape
|
||||
MOUSE_CURSOR_RESIZE_NESW = 8, // The top-right to bottom-left diagonal resize/move arrow shape
|
||||
MOUSE_CURSOR_RESIZE_ALL = 9, // The omni-directional resize/move cursor shape
|
||||
MOUSE_CURSOR_RESIZE_ALL = 9, // The omnidirectional resize/move cursor shape
|
||||
MOUSE_CURSOR_NOT_ALLOWED = 10 // The operation-not-allowed shape
|
||||
} MouseCursor;
|
||||
|
||||
|
@ -836,10 +839,10 @@ typedef enum {
|
|||
typedef enum {
|
||||
CUBEMAP_LAYOUT_AUTO_DETECT = 0, // Automatically detect layout type
|
||||
CUBEMAP_LAYOUT_LINE_VERTICAL, // Layout is defined by a vertical line with faces
|
||||
CUBEMAP_LAYOUT_LINE_HORIZONTAL, // Layout is defined by an horizontal line with faces
|
||||
CUBEMAP_LAYOUT_LINE_HORIZONTAL, // Layout is defined by a horizontal line with faces
|
||||
CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR, // Layout is defined by a 3x4 cross with cubemap faces
|
||||
CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE, // Layout is defined by a 4x3 cross with cubemap faces
|
||||
CUBEMAP_LAYOUT_PANORAMA // Layout is defined by a panorama image (equirectangular map)
|
||||
CUBEMAP_LAYOUT_PANORAMA // Layout is defined by a panorama image (equirrectangular map)
|
||||
} CubemapLayout;
|
||||
|
||||
// Font type, defines generation method
|
||||
|
@ -857,12 +860,12 @@ typedef enum {
|
|||
BLEND_ADD_COLORS, // Blend textures adding colors (alternative)
|
||||
BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative)
|
||||
BLEND_ALPHA_PREMULTIPLY, // Blend premultiplied textures considering alpha
|
||||
BLEND_CUSTOM, // Blend textures using custom src/dst factors (use rlSetBlendMode())
|
||||
BLEND_CUSTOM_SEPARATE // Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendModeSeparate())
|
||||
BLEND_CUSTOM, // Blend textures using custom src/dst factors (use rlSetBlendFactors())
|
||||
BLEND_CUSTOM_SEPARATE // Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendFactorsSeparate())
|
||||
} BlendMode;
|
||||
|
||||
// Gesture
|
||||
// NOTE: It could be used as flags to enable only some gestures
|
||||
// NOTE: Provided as bit-wise flags to enable only desired gestures
|
||||
typedef enum {
|
||||
GESTURE_NONE = 0, // No gesture
|
||||
GESTURE_TAP = 1, // Tap gesture
|
||||
|
@ -900,7 +903,7 @@ typedef enum {
|
|||
} NPatchLayout;
|
||||
|
||||
// Callbacks to hook some internal functions
|
||||
// WARNING: This callbacks are intended for advance users
|
||||
// WARNING: These callbacks are intended for advance users
|
||||
typedef void (*TraceLogCallback)(int logLevel, const char *text, va_list args); // Logging: Redirect trace log messages
|
||||
typedef unsigned char *(*LoadFileDataCallback)(const char *fileName, unsigned int *bytesRead); // FileIO: Load binary data
|
||||
typedef bool (*SaveFileDataCallback)(const char *fileName, void *data, unsigned int bytesToWrite); // FileIO: Save binary data
|
||||
|
@ -938,7 +941,8 @@ RLAPI void ToggleFullscreen(void); // Toggle wind
|
|||
RLAPI void MaximizeWindow(void); // Set window state: maximized, if resizable (only PLATFORM_DESKTOP)
|
||||
RLAPI void MinimizeWindow(void); // Set window state: minimized, if resizable (only PLATFORM_DESKTOP)
|
||||
RLAPI void RestoreWindow(void); // Set window state: not minimized/maximized (only PLATFORM_DESKTOP)
|
||||
RLAPI void SetWindowIcon(Image image); // Set icon for window (only PLATFORM_DESKTOP)
|
||||
RLAPI void SetWindowIcon(Image image); // Set icon for window (single image, RGBA 32bit, only PLATFORM_DESKTOP)
|
||||
RLAPI void SetWindowIcons(Image *images, int count); // Set icon for window (multiple images, RGBA 32bit, only PLATFORM_DESKTOP)
|
||||
RLAPI void SetWindowTitle(const char *title); // Set title for window (only PLATFORM_DESKTOP)
|
||||
RLAPI void SetWindowPosition(int x, int y); // Set window position on screen (only PLATFORM_DESKTOP)
|
||||
RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window (fullscreen mode)
|
||||
|
@ -1009,6 +1013,7 @@ RLAPI void UnloadVrStereoConfig(VrStereoConfig config); // Unload VR s
|
|||
// NOTE: Shader functionality is not available on OpenGL 1.1
|
||||
RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations
|
||||
RLAPI Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations
|
||||
RLAPI bool IsShaderReady(Shader shader); // Check if a shader is ready
|
||||
RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
|
||||
RLAPI int GetShaderLocationAttrib(Shader shader, const char *attribName); // Get shader attribute location
|
||||
RLAPI void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformType); // Set shader uniform value
|
||||
|
@ -1058,7 +1063,7 @@ 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 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 ExportDataAsCode(const char *data, unsigned int size, const char *fileName); // Export data to code (.h), returns true on success
|
||||
RLAPI bool ExportDataAsCode(const unsigned 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 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
|
||||
|
@ -1152,13 +1157,8 @@ RLAPI float GetGesturePinchAngle(void); // Get gesture pinch ang
|
|||
//------------------------------------------------------------------------------------
|
||||
// Camera System Functions (Module: rcamera)
|
||||
//------------------------------------------------------------------------------------
|
||||
RLAPI void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available)
|
||||
RLAPI void UpdateCamera(Camera *camera); // Update camera position for selected mode
|
||||
|
||||
RLAPI void SetCameraPanControl(int keyPan); // Set camera pan key to combine with mouse movement (free camera)
|
||||
RLAPI void SetCameraAltControl(int keyAlt); // Set camera alt key to combine with mouse movement (free camera)
|
||||
RLAPI void SetCameraSmoothZoomControl(int keySmoothZoom); // Set camera smooth zoom key to combine with mouse (free camera)
|
||||
RLAPI void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras)
|
||||
RLAPI void UpdateCamera(Camera *camera, int mode); // Update camera position for selected mode
|
||||
RLAPI void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom); // Update camera movement/rotation
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Basic Shapes Drawing Functions (Module: shapes)
|
||||
|
@ -1224,13 +1224,14 @@ RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2);
|
|||
//------------------------------------------------------------------------------------
|
||||
|
||||
// Image loading functions
|
||||
// NOTE: This functions do not require GPU access
|
||||
// NOTE: These functions do not require GPU access
|
||||
RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM)
|
||||
RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data
|
||||
RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data)
|
||||
RLAPI Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load image from memory buffer, fileType refers to extension: i.e. '.png'
|
||||
RLAPI Image LoadImageFromTexture(Texture2D texture); // Load image from GPU texture data
|
||||
RLAPI Image LoadImageFromScreen(void); // Load image from screen buffer and (screenshot)
|
||||
RLAPI bool IsImageReady(Image image); // Check if an image is ready
|
||||
RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM)
|
||||
RLAPI bool ExportImage(Image image, const char *fileName); // Export image data to file, returns true on success
|
||||
RLAPI bool ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes, returns true on success
|
||||
|
@ -1258,6 +1259,7 @@ RLAPI void ImageAlphaCrop(Image *image, float threshold);
|
|||
RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color
|
||||
RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image
|
||||
RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel
|
||||
RLAPI void ImageBlurGaussian(Image *image, int blurSize); // Apply Gaussian blur using a box blur approximation
|
||||
RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (Bicubic scaling algorithm)
|
||||
RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); // Resize image (Nearest-Neighbor scaling algorithm)
|
||||
RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill); // Resize canvas and fill with color
|
||||
|
@ -1305,7 +1307,9 @@ RLAPI Texture2D LoadTexture(const char *fileName);
|
|||
RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data
|
||||
RLAPI TextureCubemap LoadTextureCubemap(Image image, int layout); // Load cubemap from image, multiple image cubemap layouts supported
|
||||
RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer)
|
||||
RLAPI bool IsTextureReady(Texture2D texture); // Check if a texture is ready
|
||||
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
|
||||
RLAPI bool IsRenderTextureReady(RenderTexture2D target); // Check if a render texture is ready
|
||||
RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM)
|
||||
RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data
|
||||
RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data
|
||||
|
@ -1320,11 +1324,8 @@ RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint);
|
|||
RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2
|
||||
RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters
|
||||
RLAPI void DrawTextureRec(Texture2D texture, Rectangle source, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle
|
||||
RLAPI void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint); // Draw texture quad with tiling and offset parameters
|
||||
RLAPI void DrawTextureTiled(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, float scale, Color tint); // Draw part of a texture (defined by a rectangle) with rotation and scale tiled into dest.
|
||||
RLAPI void DrawTexturePro(Texture2D texture, Rectangle source, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters
|
||||
RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle dest, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely
|
||||
RLAPI void DrawTexturePoly(Texture2D texture, Vector2 center, Vector2 *points, Vector2 *texcoords, int pointCount, Color tint); // Draw a textured polygon
|
||||
|
||||
// Color/pixel related functions
|
||||
RLAPI Color Fade(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f
|
||||
|
@ -1333,6 +1334,9 @@ RLAPI Vector4 ColorNormalize(Color color); // G
|
|||
RLAPI Color ColorFromNormalized(Vector4 normalized); // Get Color from normalized values [0..1]
|
||||
RLAPI Vector3 ColorToHSV(Color color); // Get HSV values for a Color, hue [0..360], saturation/value [0..1]
|
||||
RLAPI Color ColorFromHSV(float hue, float saturation, float value); // Get a Color from HSV values, hue [0..360], saturation/value [0..1]
|
||||
RLAPI Color ColorTint(Color color, Color tint); // Get color multiplied with another color
|
||||
RLAPI Color ColorBrightness(Color color, float factor); // Get color with brightness correction, brightness factor goes from -1.0f to 1.0f
|
||||
RLAPI Color ColorContrast(Color color, float contrast); // Get color with contrast correction, contrast values between -1.0f and 1.0f
|
||||
RLAPI Color ColorAlpha(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f
|
||||
RLAPI Color ColorAlphaBlend(Color dst, Color src, Color tint); // Get src alpha-blended into dst color with tint
|
||||
RLAPI Color GetColor(unsigned int hexValue); // Get Color structure from hexadecimal value
|
||||
|
@ -1350,6 +1354,7 @@ RLAPI Font LoadFont(const char *fileName);
|
|||
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 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 bool IsFontReady(Font font); // Check if a font is ready
|
||||
RLAPI GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount, int type); // Load font data for further use
|
||||
RLAPI Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **recs, int glyphCount, int fontSize, int padding, int packMethod); // Generate image font atlas using chars info
|
||||
RLAPI void UnloadFontData(GlyphInfo *chars, int glyphCount); // Unload font chars info data (RAM)
|
||||
|
@ -1414,8 +1419,6 @@ RLAPI void DrawCube(Vector3 position, float width, float height, float length, C
|
|||
RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version)
|
||||
RLAPI void DrawCubeWires(Vector3 position, float width, float height, float length, Color color); // Draw cube wires
|
||||
RLAPI void DrawCubeWiresV(Vector3 position, Vector3 size, Color color); // Draw cube wires (Vector version)
|
||||
RLAPI void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color); // Draw cube textured
|
||||
RLAPI void DrawCubeTextureRec(Texture2D texture, Rectangle source, Vector3 position, float width, float height, float length, Color color); // Draw cube with a region of a texture
|
||||
RLAPI void DrawSphere(Vector3 centerPos, float radius, Color color); // Draw sphere
|
||||
RLAPI void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere with extended parameters
|
||||
RLAPI void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires
|
||||
|
@ -1436,8 +1439,8 @@ RLAPI void DrawGrid(int slices, float spacing);
|
|||
// Model management functions
|
||||
RLAPI Model LoadModel(const char *fileName); // Load model from files (meshes and materials)
|
||||
RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh (default material)
|
||||
RLAPI bool IsModelReady(Model model); // Check if a model is ready
|
||||
RLAPI void UnloadModel(Model model); // Unload model (including meshes) from memory (RAM and/or VRAM)
|
||||
RLAPI void UnloadModelKeepMeshes(Model model); // Unload model (but not meshes) from memory (RAM and/or VRAM)
|
||||
RLAPI BoundingBox GetModelBoundingBox(Model model); // Compute model bounding box limits (considers all meshes)
|
||||
|
||||
// Model drawing functions
|
||||
|
@ -1476,6 +1479,7 @@ RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
|
|||
// Material loading/unloading functions
|
||||
RLAPI Material *LoadMaterials(const char *fileName, int *materialCount); // Load materials from model file
|
||||
RLAPI Material LoadMaterialDefault(void); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)
|
||||
RLAPI bool IsMaterialReady(Material material); // Check if a material is ready
|
||||
RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM)
|
||||
RLAPI void SetMaterialTexture(Material *material, int mapType, Texture2D texture); // Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...)
|
||||
RLAPI void SetModelMeshMaterial(Model *model, int meshId, int materialId); // Set material for a mesh
|
||||
|
@ -1511,8 +1515,10 @@ RLAPI void SetMasterVolume(float volume); // Set mas
|
|||
// Wave/Sound loading/unloading functions
|
||||
RLAPI Wave LoadWave(const char *fileName); // Load wave data from file
|
||||
RLAPI Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int dataSize); // Load wave from memory buffer, fileType refers to extension: i.e. '.wav'
|
||||
RLAPI bool IsWaveReady(Wave wave); // Checks if wave data is ready
|
||||
RLAPI Sound LoadSound(const char *fileName); // Load sound from file
|
||||
RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
|
||||
RLAPI bool IsSoundReady(Sound sound); // Checks if a sound is ready
|
||||
RLAPI void UpdateSound(Sound sound, const void *data, int sampleCount); // Update sound buffer with new data
|
||||
RLAPI void UnloadWave(Wave wave); // Unload wave data
|
||||
RLAPI void UnloadSound(Sound sound); // Unload sound
|
||||
|
@ -1524,9 +1530,6 @@ RLAPI void PlaySound(Sound sound); // Play a
|
|||
RLAPI void StopSound(Sound sound); // Stop playing a sound
|
||||
RLAPI void PauseSound(Sound sound); // Pause a sound
|
||||
RLAPI void ResumeSound(Sound sound); // Resume a paused sound
|
||||
RLAPI void PlaySoundMulti(Sound sound); // Play a sound (using multichannel buffer pool)
|
||||
RLAPI void StopSoundMulti(void); // Stop any sound playing (using multichannel buffer pool)
|
||||
RLAPI int GetSoundsPlaying(void); // Get number of sounds playing in the multichannel
|
||||
RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing
|
||||
RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level)
|
||||
RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level)
|
||||
|
@ -1540,6 +1543,7 @@ RLAPI void UnloadWaveSamples(float *samples); // Unload
|
|||
// Music management functions
|
||||
RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file
|
||||
RLAPI Music LoadMusicStreamFromMemory(const char *fileType, const unsigned char *data, int dataSize); // Load music stream from data
|
||||
RLAPI bool IsMusicReady(Music music); // Checks if a music stream is ready
|
||||
RLAPI void UnloadMusicStream(Music music); // Unload music stream
|
||||
RLAPI void PlayMusicStream(Music music); // Start music playing
|
||||
RLAPI bool IsMusicStreamPlaying(Music music); // Check if music is playing
|
||||
|
@ -1556,6 +1560,7 @@ RLAPI float GetMusicTimePlayed(Music music); // Get cur
|
|||
|
||||
// AudioStream management functions
|
||||
RLAPI AudioStream LoadAudioStream(unsigned int sampleRate, unsigned int sampleSize, unsigned int channels); // Load audio stream (to stream raw audio pcm data)
|
||||
RLAPI bool IsAudioStreamReady(AudioStream stream); // Checks if an audio stream is ready
|
||||
RLAPI void UnloadAudioStream(AudioStream stream); // Unload audio stream and free memory
|
||||
RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int frameCount); // Update audio stream buffers with data
|
||||
RLAPI bool IsAudioStreamProcessed(AudioStream stream); // Check if any audio stream buffers requires refill
|
||||
|
@ -1573,6 +1578,9 @@ RLAPI void SetAudioStreamCallback(AudioStream stream, AudioCallback callback);
|
|||
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
|
||||
|
||||
RLAPI void AttachAudioMixedProcessor(AudioCallback processor); // Attach audio stream processor to the entire audio pipeline
|
||||
RLAPI void DetachAudioMixedProcessor(AudioCallback processor); // Detach audio stream processor from the entire audio pipeline
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
*
|
||||
* LICENSE: zlib/libpng
|
||||
*
|
||||
* Copyright (c) 2015-2022 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2015-2023 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||
* will the authors be held liable for any damages arising from the use of this software.
|
||||
|
@ -306,10 +306,33 @@ RMAPI float Vector2DistanceSqr(Vector2 v1, Vector2 v2)
|
|||
return result;
|
||||
}
|
||||
|
||||
// Calculate angle from two vectors
|
||||
// Calculate angle between two vectors
|
||||
// NOTE: Angle is calculated from origin point (0, 0)
|
||||
RMAPI float Vector2Angle(Vector2 v1, Vector2 v2)
|
||||
{
|
||||
float result = atan2f(v2.y, v2.x) - atan2f(v1.y, v1.x);
|
||||
float result = atan2f(v2.y - v1.y, v2.x - v1.x);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Calculate angle defined by a two vectors line
|
||||
// NOTE: Parameters need to be normalized
|
||||
// Current implementation should be aligned with glm::angle
|
||||
RMAPI float Vector2LineAngle(Vector2 start, Vector2 end)
|
||||
{
|
||||
float result = 0.0f;
|
||||
|
||||
float dot = start.x*end.x + start.y*end.y; // Dot product
|
||||
|
||||
float dotClamp = (dot < -1.0f)? -1.0f : dot; // Clamp
|
||||
if (dotClamp > 1.0f) dotClamp = 1.0f;
|
||||
|
||||
result = acosf(dotClamp);
|
||||
|
||||
// Alternative implementation, more costly
|
||||
//float v1Length = sqrtf((start.x*start.x) + (start.y*start.y));
|
||||
//float v2Length = sqrtf((end.x*end.x) + (end.y*end.y));
|
||||
//float result = -acosf((start.x*end.x + start.y*end.y)/(v1Length*v2Length));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -889,7 +912,7 @@ RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view)
|
|||
{
|
||||
Vector3 result = { 0 };
|
||||
|
||||
// Calculate unproject matrix (multiply view patrix by projection matrix) and invert it
|
||||
// Calculate unprojected matrix (multiply view matrix by projection matrix) and invert it
|
||||
Matrix matViewProj = { // MatrixMultiply(view, projection);
|
||||
view.m0*projection.m0 + view.m1*projection.m4 + view.m2*projection.m8 + view.m3*projection.m12,
|
||||
view.m0*projection.m1 + view.m1*projection.m5 + view.m2*projection.m9 + view.m3*projection.m13,
|
||||
|
@ -952,7 +975,7 @@ RMAPI Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view)
|
|||
// Create quaternion from source point
|
||||
Quaternion quat = { source.x, source.y, source.z, 1.0f };
|
||||
|
||||
// Multiply quat point by unproject matrix
|
||||
// Multiply quat point by unprojecte matrix
|
||||
Quaternion qtransformed = { // QuaternionTransform(quat, matViewProjInv)
|
||||
matViewProjInv.m0*quat.x + matViewProjInv.m4*quat.y + matViewProjInv.m8*quat.z + matViewProjInv.m12*quat.w,
|
||||
matViewProjInv.m1*quat.x + matViewProjInv.m5*quat.y + matViewProjInv.m9*quat.z + matViewProjInv.m13*quat.w,
|
||||
|
|
|
@ -8,44 +8,14 @@ package rl
|
|||
*/
|
||||
import "C"
|
||||
|
||||
// SetCameraMode - Set camera mode (multiple camera modes available)
|
||||
func SetCameraMode(camera Camera, mode CameraMode) {
|
||||
ccamera := camera.cptr()
|
||||
cmode := (C.int)(mode)
|
||||
C.SetCameraMode(*ccamera, cmode)
|
||||
}
|
||||
|
||||
// UpdateCamera - Update camera position for selected mode
|
||||
func UpdateCamera(camera *Camera) {
|
||||
func UpdateCamera(camera *Camera, mode CameraMode) {
|
||||
ccamera := camera.cptr()
|
||||
C.UpdateCamera(ccamera)
|
||||
C.UpdateCamera(ccamera, C.int(mode))
|
||||
}
|
||||
|
||||
// SetCameraPanControl - Set camera pan key to combine with mouse movement (free camera)
|
||||
func SetCameraPanControl(panKey int32) {
|
||||
cpanKey := (C.int)(panKey)
|
||||
C.SetCameraPanControl(cpanKey)
|
||||
}
|
||||
|
||||
// SetCameraAltControl - Set camera alt key to combine with mouse movement (free camera)
|
||||
func SetCameraAltControl(altKey int32) {
|
||||
caltKey := (C.int)(altKey)
|
||||
C.SetCameraAltControl(caltKey)
|
||||
}
|
||||
|
||||
// SetCameraSmoothZoomControl - Set camera smooth zoom key to combine with mouse (free camera)
|
||||
func SetCameraSmoothZoomControl(szKey int32) {
|
||||
cszKey := (C.int)(szKey)
|
||||
C.SetCameraSmoothZoomControl(cszKey)
|
||||
}
|
||||
|
||||
// SetCameraMoveControls - Set camera move controls (1st person and 3rd person cameras)
|
||||
func SetCameraMoveControls(frontKey int32, backKey int32, rightKey int32, leftKey int32, upKey int32, downKey int32) {
|
||||
cfrontKey := (C.int)(frontKey)
|
||||
cbackKey := (C.int)(backKey)
|
||||
crightKey := (C.int)(rightKey)
|
||||
cleftKey := (C.int)(leftKey)
|
||||
cupKey := (C.int)(upKey)
|
||||
cdownKey := (C.int)(downKey)
|
||||
C.SetCameraMoveControls(cfrontKey, cbackKey, crightKey, cleftKey, cupKey, cdownKey)
|
||||
// UpdateCameraPro - Update camera movement/rotation
|
||||
func UpdateCameraPro(camera *Camera, movement Vector3, rotation Vector3, zoom float32) {
|
||||
ccamera := camera.cptr()
|
||||
C.UpdateCameraPro(ccamera, *movement.cptr(), *rotation.cptr(), C.float(zoom))
|
||||
}
|
||||
|
|
750
raylib/rcamera.h
750
raylib/rcamera.h
|
@ -1,8 +1,6 @@
|
|||
/*******************************************************************************************
|
||||
*
|
||||
* rcamera - Basic camera system for multiple camera modes
|
||||
*
|
||||
* NOTE: Memory footprint of this library is aproximately 52 bytes (global variables)
|
||||
* rcamera - Basic camera system with support for multiple camera modes
|
||||
*
|
||||
* CONFIGURATION:
|
||||
*
|
||||
|
@ -17,12 +15,13 @@
|
|||
*
|
||||
* CONTRIBUTORS:
|
||||
* Ramon Santamaria: Supervision, review, update and maintenance
|
||||
* Christoph Wagner: Complete redesign, using raymath (2022)
|
||||
* Marc Palau: Initial implementation (2014)
|
||||
*
|
||||
*
|
||||
* LICENSE: zlib/libpng
|
||||
*
|
||||
* Copyright (c) 2015-2022 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2022-2023 Christoph Wagner (@Crydsch) & Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||
* will the authors be held liable for any damages arising from the use of this software.
|
||||
|
@ -47,24 +46,35 @@
|
|||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
//----------------------------------------------------------------------------------
|
||||
//...
|
||||
// Function specifiers definition
|
||||
#ifndef RLAPI
|
||||
#define RLAPI // Functions defined as 'extern' by default (implicit specifiers)
|
||||
#endif
|
||||
|
||||
#if defined(CAMERA_STANDALONE)
|
||||
#define CAMERA_CULL_DISTANCE_NEAR 0.01
|
||||
#define CAMERA_CULL_DISTANCE_FAR 1000.0
|
||||
#else
|
||||
#define CAMERA_CULL_DISTANCE_NEAR RL_CULL_DISTANCE_NEAR
|
||||
#define CAMERA_CULL_DISTANCE_FAR RL_CULL_DISTANCE_FAR
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
// NOTE: Below types are required for CAMERA_STANDALONE usage
|
||||
//----------------------------------------------------------------------------------
|
||||
#if defined(CAMERA_STANDALONE)
|
||||
// Vector2 type
|
||||
// Vector2, 2 components
|
||||
typedef struct Vector2 {
|
||||
float x;
|
||||
float y;
|
||||
float x; // Vector x component
|
||||
float y; // Vector y component
|
||||
} Vector2;
|
||||
|
||||
// Vector3 type
|
||||
// Vector3, 3 components
|
||||
typedef struct Vector3 {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float x; // Vector x component
|
||||
float y; // Vector y component
|
||||
float z; // Vector z component
|
||||
} Vector3;
|
||||
|
||||
// Camera type, defines a camera position/orientation in 3d space
|
||||
|
@ -73,25 +83,25 @@
|
|||
Vector3 target; // Camera target it looks-at
|
||||
Vector3 up; // Camera up vector (rotation over its axis)
|
||||
float fovy; // Camera field-of-view apperture in Y (degrees) in perspective, used as near plane width in orthographic
|
||||
int type; // Camera type, defines projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC
|
||||
int projection; // Camera projection type: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC
|
||||
} Camera3D;
|
||||
|
||||
typedef Camera3D Camera; // Camera type fallback, defaults to Camera3D
|
||||
|
||||
// Camera projection
|
||||
typedef enum {
|
||||
CAMERA_PERSPECTIVE = 0, // Perspective projection
|
||||
CAMERA_ORTHOGRAPHIC // Orthographic projection
|
||||
} CameraProjection;
|
||||
|
||||
// Camera system modes
|
||||
typedef enum {
|
||||
CAMERA_CUSTOM = 0,
|
||||
CAMERA_FREE,
|
||||
CAMERA_ORBITAL,
|
||||
CAMERA_FIRST_PERSON,
|
||||
CAMERA_THIRD_PERSON
|
||||
CAMERA_CUSTOM = 0, // Camera custom, controlled by user (UpdateCamera() does nothing)
|
||||
CAMERA_FREE, // Camera free mode
|
||||
CAMERA_ORBITAL, // Camera orbital, around target, zoom supported
|
||||
CAMERA_FIRST_PERSON, // Camera first person
|
||||
CAMERA_THIRD_PERSON // Camera third person
|
||||
} CameraMode;
|
||||
|
||||
// Camera projection modes
|
||||
typedef enum {
|
||||
CAMERA_PERSPECTIVE = 0,
|
||||
CAMERA_ORTHOGRAPHIC
|
||||
} CameraProjection;
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
@ -107,17 +117,23 @@
|
|||
extern "C" { // Prevents name mangling of functions
|
||||
#endif
|
||||
|
||||
#if defined(CAMERA_STANDALONE)
|
||||
void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available)
|
||||
void UpdateCamera(Camera *camera); // Update camera position for selected mode
|
||||
RLAPI Vector3 GetCameraForward(Camera *camera);
|
||||
RLAPI Vector3 GetCameraUp(Camera *camera);
|
||||
RLAPI Vector3 GetCameraRight(Camera *camera);
|
||||
|
||||
void SetCameraPanControl(int keyPan); // Set camera pan key to combine with mouse movement (free camera)
|
||||
void SetCameraAltControl(int keyAlt); // Set camera alt key to combine with mouse movement (free camera)
|
||||
void SetCameraSmoothZoomControl(int szoomKey); // Set camera smooth zoom key to combine with mouse (free camera)
|
||||
void SetCameraMoveControls(int keyFront, int keyBack,
|
||||
int keyRight, int keyLeft,
|
||||
int keyUp, int keyDown); // Set camera move controls (1st person and 3rd person cameras)
|
||||
#endif
|
||||
// Camera movement
|
||||
RLAPI void CameraMoveForward(Camera *camera, float distance, bool moveInWorldPlane);
|
||||
RLAPI void CameraMoveUp(Camera *camera, float distance);
|
||||
RLAPI void CameraMoveRight(Camera *camera, float distance, bool moveInWorldPlane);
|
||||
RLAPI void CameraMoveToTarget(Camera *camera, float delta);
|
||||
|
||||
// Camera rotation
|
||||
RLAPI void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget);
|
||||
RLAPI void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp);
|
||||
RLAPI void CameraRoll(Camera *camera, float angle);
|
||||
|
||||
RLAPI Matrix GetCameraViewMatrix(Camera *camera);
|
||||
RLAPI Matrix GetCameraProjectionMatrix(Camera* camera, float aspect);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
@ -134,425 +150,355 @@ void SetCameraMoveControls(int keyFront, int keyBack,
|
|||
|
||||
#if defined(CAMERA_IMPLEMENTATION)
|
||||
|
||||
#include <math.h> // Required for: sinf(), cosf(), sqrtf()
|
||||
#include "raymath.h" // Required for vector maths:
|
||||
// Vector3Add()
|
||||
// Vector3Subtract()
|
||||
// Vector3Scale()
|
||||
// Vector3Normalize()
|
||||
// Vector3Distance()
|
||||
// Vector3CrossProduct()
|
||||
// Vector3RotateByAxisAngle()
|
||||
// Vector3Angle()
|
||||
// Vector3Negate()
|
||||
// MatrixLookAt()
|
||||
// MatrixPerspective()
|
||||
// MatrixOrtho()
|
||||
// MatrixIdentity()
|
||||
|
||||
// raylib required functionality:
|
||||
// GetMouseDelta()
|
||||
// GetMouseWheelMove()
|
||||
// IsKeyDown()
|
||||
// IsKeyPressed()
|
||||
// GetFrameTime()
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
//----------------------------------------------------------------------------------
|
||||
#ifndef PI
|
||||
#define PI 3.14159265358979323846
|
||||
#endif
|
||||
#ifndef DEG2RAD
|
||||
#define DEG2RAD (PI/180.0f)
|
||||
#endif
|
||||
#ifndef RAD2DEG
|
||||
#define RAD2DEG (180.0f/PI)
|
||||
#endif
|
||||
#define CAMERA_MOVE_SPEED 0.09f
|
||||
#define CAMERA_ROTATION_SPEED 0.03f
|
||||
|
||||
// Camera mouse movement sensitivity
|
||||
#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.5f // TODO: it should be independant of framerate
|
||||
#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f // TODO: it should be independant of framerate
|
||||
#define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f
|
||||
|
||||
// FREE_CAMERA
|
||||
#define CAMERA_FREE_MOUSE_SENSITIVITY 0.01f
|
||||
#define CAMERA_FREE_DISTANCE_MIN_CLAMP 0.3f
|
||||
#define CAMERA_FREE_DISTANCE_MAX_CLAMP 120.0f
|
||||
#define CAMERA_FREE_MIN_CLAMP 85.0f
|
||||
#define CAMERA_FREE_MAX_CLAMP -85.0f
|
||||
#define CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY 0.05f
|
||||
#define CAMERA_FREE_PANNING_DIVIDER 5.1f
|
||||
|
||||
// ORBITAL_CAMERA
|
||||
#define CAMERA_ORBITAL_SPEED 0.5f // Radians per second
|
||||
|
||||
// FIRST_PERSON
|
||||
//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY 0.003f
|
||||
#define CAMERA_FIRST_PERSON_FOCUS_DISTANCE 25.0f
|
||||
#define CAMERA_FIRST_PERSON_MIN_CLAMP 89.0f
|
||||
#define CAMERA_FIRST_PERSON_MAX_CLAMP -89.0f
|
||||
|
||||
// When walking, y-position of the player moves up-down at step frequency (swinging) but
|
||||
// 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_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
|
||||
//#define CAMERA_THIRD_PERSON_MOUSE_SENSITIVITY 0.003f
|
||||
#define CAMERA_THIRD_PERSON_DISTANCE_CLAMP 1.2f
|
||||
#define CAMERA_THIRD_PERSON_MIN_CLAMP 5.0f
|
||||
#define CAMERA_THIRD_PERSON_MAX_CLAMP -85.0f
|
||||
#define CAMERA_THIRD_PERSON_OFFSET (Vector3){ 0.4f, 0.0f, 0.0f }
|
||||
#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 8.0f
|
||||
#define CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f
|
||||
#define CAMERA_FIRST_PERSON_WAVING_DIVIDER 200.0f
|
||||
|
||||
// PLAYER (used by camera)
|
||||
#define PLAYER_MOVEMENT_SENSITIVITY 2.0f
|
||||
#define PLAYER_MOVEMENT_SENSITIVITY 20.0f
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
// Camera move modes (first person and third person cameras)
|
||||
typedef enum {
|
||||
MOVE_FRONT = 0,
|
||||
MOVE_BACK,
|
||||
MOVE_RIGHT,
|
||||
MOVE_LEFT,
|
||||
MOVE_UP,
|
||||
MOVE_DOWN
|
||||
} CameraMove;
|
||||
|
||||
// Camera global state context data [56 bytes]
|
||||
typedef struct {
|
||||
unsigned int mode; // Current camera mode
|
||||
float targetDistance; // Camera distance from position to target
|
||||
float playerEyesPosition; // Player eyes position from ground (in meters)
|
||||
Vector2 angle; // Camera angle in plane XZ
|
||||
|
||||
// Camera movement control keys
|
||||
int moveControl[6]; // Move controls (CAMERA_FIRST_PERSON)
|
||||
int smoothZoomControl; // Smooth zoom control key
|
||||
int altControl; // Alternative control key
|
||||
int panControl; // Pan view control key
|
||||
} CameraData;
|
||||
//...
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
static CameraData CAMERA = { // Global CAMERA state context
|
||||
.mode = 0,
|
||||
.targetDistance = 0,
|
||||
.playerEyesPosition = 1.85f,
|
||||
.angle = { 0 },
|
||||
.moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' },
|
||||
.smoothZoomControl = 341, // raylib: KEY_LEFT_CONTROL
|
||||
.altControl = 342, // raylib: KEY_LEFT_ALT
|
||||
.panControl = 2 // raylib: MOUSE_BUTTON_MIDDLE
|
||||
};
|
||||
//...
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module specific Functions Declaration
|
||||
//----------------------------------------------------------------------------------
|
||||
#if defined(CAMERA_STANDALONE)
|
||||
// NOTE: Camera controls depend on some raylib input functions
|
||||
static void EnableCursor() {} // Unlock cursor
|
||||
static void DisableCursor() {} // Lock cursor
|
||||
|
||||
static int IsKeyDown(int key) { return 0; }
|
||||
|
||||
static int IsMouseButtonDown(int button) { return 0;}
|
||||
static float GetMouseWheelMove() { return 0.0f; }
|
||||
static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; }
|
||||
#endif
|
||||
//...
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Select camera mode (multiple camera modes available)
|
||||
void SetCameraMode(Camera camera, int mode)
|
||||
// Returns the cameras forward vector (normalized)
|
||||
Vector3 GetCameraForward(Camera *camera)
|
||||
{
|
||||
Vector3 v1 = camera.position;
|
||||
Vector3 v2 = camera.target;
|
||||
|
||||
float dx = v2.x - v1.x;
|
||||
float dy = v2.y - v1.y;
|
||||
float dz = v2.z - v1.z;
|
||||
|
||||
CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance to target
|
||||
|
||||
// Camera angle calculation
|
||||
CAMERA.angle.x = atan2f(dx, dz); // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
|
||||
CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz)); // Camera angle in plane XY (0 aligned with X, move positive CW)
|
||||
|
||||
CAMERA.playerEyesPosition = camera.position.y; // Init player eyes position to camera Y position
|
||||
|
||||
// Lock cursor for first person and third person cameras
|
||||
if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor();
|
||||
else EnableCursor();
|
||||
|
||||
CAMERA.mode = mode;
|
||||
return Vector3Normalize(Vector3Subtract(camera->target, camera->position));
|
||||
}
|
||||
|
||||
// Update camera depending on selected mode
|
||||
// NOTE: Camera controls depend on some raylib functions:
|
||||
// System: EnableCursor(), DisableCursor()
|
||||
// Mouse: IsMouseButtonDown(), GetMousePosition(), GetMouseWheelMove()
|
||||
// Keys: IsKeyDown()
|
||||
void UpdateCamera(Camera *camera)
|
||||
// Returns the cameras up vector (normalized)
|
||||
// Note: The up vector might not be perpendicular to the forward vector
|
||||
Vector3 GetCameraUp(Camera *camera)
|
||||
{
|
||||
static float swingCounter = 0.0f; // Used for 1st person swinging movement
|
||||
return Vector3Normalize(camera->up);
|
||||
}
|
||||
|
||||
// TODO: Compute CAMERA.targetDistance and CAMERA.angle here (?)
|
||||
// Returns the cameras right vector (normalized)
|
||||
Vector3 GetCameraRight(Camera *camera)
|
||||
{
|
||||
Vector3 forward = GetCameraForward(camera);
|
||||
Vector3 up = GetCameraUp(camera);
|
||||
|
||||
// Mouse movement detection
|
||||
return Vector3CrossProduct(forward, up);
|
||||
}
|
||||
|
||||
// Moves the camera in its forward direction
|
||||
void CameraMoveForward(Camera *camera, float distance, bool moveInWorldPlane)
|
||||
{
|
||||
Vector3 forward = GetCameraForward(camera);
|
||||
|
||||
if (moveInWorldPlane)
|
||||
{
|
||||
// Project vector onto world plane
|
||||
forward.y = 0;
|
||||
forward = Vector3Normalize(forward);
|
||||
}
|
||||
|
||||
// Scale by distance
|
||||
forward = Vector3Scale(forward, distance);
|
||||
|
||||
// Move position and target
|
||||
camera->position = Vector3Add(camera->position, forward);
|
||||
camera->target = Vector3Add(camera->target, forward);
|
||||
}
|
||||
|
||||
// Moves the camera in its up direction
|
||||
void CameraMoveUp(Camera *camera, float distance)
|
||||
{
|
||||
Vector3 up = GetCameraUp(camera);
|
||||
|
||||
// Scale by distance
|
||||
up = Vector3Scale(up, distance);
|
||||
|
||||
// Move position and target
|
||||
camera->position = Vector3Add(camera->position, up);
|
||||
camera->target = Vector3Add(camera->target, up);
|
||||
}
|
||||
|
||||
// Moves the camera target in its current right direction
|
||||
void CameraMoveRight(Camera *camera, float distance, bool moveInWorldPlane)
|
||||
{
|
||||
Vector3 right = GetCameraRight(camera);
|
||||
|
||||
if (moveInWorldPlane)
|
||||
{
|
||||
// Project vector onto world plane
|
||||
right.y = 0;
|
||||
right = Vector3Normalize(right);
|
||||
}
|
||||
|
||||
// Scale by distance
|
||||
right = Vector3Scale(right, distance);
|
||||
|
||||
// Move position and target
|
||||
camera->position = Vector3Add(camera->position, right);
|
||||
camera->target = Vector3Add(camera->target, right);
|
||||
}
|
||||
|
||||
// Moves the camera position closer/farther to/from the camera target
|
||||
void CameraMoveToTarget(Camera *camera, float delta)
|
||||
{
|
||||
float distance = Vector3Distance(camera->position, camera->target);
|
||||
|
||||
// Apply delta
|
||||
distance += delta;
|
||||
|
||||
// Distance must be greater than 0
|
||||
if (distance < 0) distance = 0.001f;
|
||||
|
||||
// Set new distance by moving the position along the forward vector
|
||||
Vector3 forward = GetCameraForward(camera);
|
||||
camera->position = Vector3Add(camera->target, Vector3Scale(forward, -distance));
|
||||
}
|
||||
|
||||
// Rotates the camera around its up vector
|
||||
// Yaw is "looking left and right"
|
||||
// If rotateAroundTarget is false, the camera rotates around its position
|
||||
// Note: angle must be provided in radians
|
||||
void CameraYaw(Camera *camera, float angle, bool rotateAroundTarget)
|
||||
{
|
||||
// Rotation axis
|
||||
Vector3 up = GetCameraUp(camera);
|
||||
|
||||
// View vector
|
||||
Vector3 targetPosition = Vector3Subtract(camera->target, camera->position);
|
||||
|
||||
// Rotate view vector around up axis
|
||||
targetPosition = Vector3RotateByAxisAngle(targetPosition, up, angle);
|
||||
|
||||
if (rotateAroundTarget)
|
||||
{
|
||||
// Move position relative to target
|
||||
camera->position = Vector3Subtract(camera->target, targetPosition);
|
||||
}
|
||||
else // rotate around camera.position
|
||||
{
|
||||
// Move target relative to position
|
||||
camera->target = Vector3Add(camera->position, targetPosition);
|
||||
}
|
||||
}
|
||||
|
||||
// Rotates the camera around its right vector, pitch is "looking up and down"
|
||||
// - lockView prevents camera overrotation (aka "somersaults")
|
||||
// - rotateAroundTarget defines if rotation is around target or around its position
|
||||
// - rotateUp rotates the up direction as well (typically only usefull in CAMERA_FREE)
|
||||
// NOTE: angle must be provided in radians
|
||||
void CameraPitch(Camera *camera, float angle, bool lockView, bool rotateAroundTarget, bool rotateUp)
|
||||
{
|
||||
// Up direction
|
||||
Vector3 up = GetCameraUp(camera);
|
||||
|
||||
// View vector
|
||||
Vector3 targetPosition = Vector3Subtract(camera->target, camera->position);
|
||||
|
||||
if (lockView)
|
||||
{
|
||||
// In these camera modes we clamp the Pitch angle
|
||||
// to allow only viewing straight up or down.
|
||||
|
||||
// Clamp view up
|
||||
float maxAngleUp = Vector3Angle(up, targetPosition);
|
||||
maxAngleUp -= 0.001f; // avoid numerical errors
|
||||
if (angle > maxAngleUp) angle = maxAngleUp;
|
||||
|
||||
// Clamp view down
|
||||
float maxAngleDown = Vector3Angle(Vector3Negate(up), targetPosition);
|
||||
maxAngleDown *= -1.0f; // downwards angle is negative
|
||||
maxAngleDown += 0.001f; // avoid numerical errors
|
||||
if (angle < maxAngleDown) angle = maxAngleDown;
|
||||
}
|
||||
|
||||
// Rotation axis
|
||||
Vector3 right = GetCameraRight(camera);
|
||||
|
||||
// Rotate view vector around right axis
|
||||
targetPosition = Vector3RotateByAxisAngle(targetPosition, right, angle);
|
||||
|
||||
if (rotateAroundTarget)
|
||||
{
|
||||
// Move position relative to target
|
||||
camera->position = Vector3Subtract(camera->target, targetPosition);
|
||||
}
|
||||
else // rotate around camera.position
|
||||
{
|
||||
// Move target relative to position
|
||||
camera->target = Vector3Add(camera->position, targetPosition);
|
||||
}
|
||||
|
||||
if (rotateUp)
|
||||
{
|
||||
// Rotate up direction around right axis
|
||||
camera->up = Vector3RotateByAxisAngle(camera->up, right, angle);
|
||||
}
|
||||
}
|
||||
|
||||
// Rotates the camera around its forward vector
|
||||
// Roll is "turning your head sideways to the left or right"
|
||||
// Note: angle must be provided in radians
|
||||
void CameraRoll(Camera *camera, float angle)
|
||||
{
|
||||
// Rotation axis
|
||||
Vector3 forward = GetCameraForward(camera);
|
||||
|
||||
// Rotate up direction around forward axis
|
||||
camera->up = Vector3RotateByAxisAngle(camera->up, forward, angle);
|
||||
}
|
||||
|
||||
// Returns the camera view matrix
|
||||
Matrix GetCameraViewMatrix(Camera *camera)
|
||||
{
|
||||
return MatrixLookAt(camera->position, camera->target, camera->up);
|
||||
}
|
||||
|
||||
// Returns the camera projection matrix
|
||||
Matrix GetCameraProjectionMatrix(Camera *camera, float aspect)
|
||||
{
|
||||
if (camera->projection == CAMERA_PERSPECTIVE)
|
||||
{
|
||||
return MatrixPerspective(camera->fovy*DEG2RAD, aspect, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR);
|
||||
}
|
||||
else if (camera->projection == CAMERA_ORTHOGRAPHIC)
|
||||
{
|
||||
double top = camera->fovy/2.0;
|
||||
double right = top*aspect;
|
||||
|
||||
return MatrixOrtho(-right, right, -top, top, CAMERA_CULL_DISTANCE_NEAR, CAMERA_CULL_DISTANCE_FAR);
|
||||
}
|
||||
|
||||
return MatrixIdentity();
|
||||
}
|
||||
|
||||
#ifndef CAMERA_STANDALONE
|
||||
// Update camera position for selected mode
|
||||
// Camera mode: CAMERA_FREE, CAMERA_FIRST_PERSON, CAMERA_THIRD_PERSON, CAMERA_ORBITAL or CUSTOM
|
||||
void UpdateCamera(Camera *camera, int mode)
|
||||
{
|
||||
Vector2 mousePositionDelta = GetMouseDelta();
|
||||
float mouseWheelMove = GetMouseWheelMove();
|
||||
|
||||
// Keys input detection
|
||||
// TODO: Input detection is raylib-dependant, it could be moved outside the module
|
||||
bool keyPan = IsMouseButtonDown(CAMERA.panControl);
|
||||
bool keyAlt = IsKeyDown(CAMERA.altControl);
|
||||
bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl);
|
||||
bool direction[6] = { IsKeyDown(CAMERA.moveControl[MOVE_FRONT]),
|
||||
IsKeyDown(CAMERA.moveControl[MOVE_BACK]),
|
||||
IsKeyDown(CAMERA.moveControl[MOVE_RIGHT]),
|
||||
IsKeyDown(CAMERA.moveControl[MOVE_LEFT]),
|
||||
IsKeyDown(CAMERA.moveControl[MOVE_UP]),
|
||||
IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) };
|
||||
bool moveInWorldPlane = ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON));
|
||||
bool rotateAroundTarget = ((mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL));
|
||||
bool lockView = ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL));
|
||||
bool rotateUp = (mode == CAMERA_FREE);
|
||||
|
||||
// Support for multiple automatic camera modes
|
||||
// NOTE: In case of CAMERA_CUSTOM nothing happens here, user must update it manually
|
||||
switch (CAMERA.mode)
|
||||
if (mode == CAMERA_ORBITAL)
|
||||
{
|
||||
case CAMERA_FREE: // Camera free controls, using standard 3d-content-creation scheme
|
||||
{
|
||||
// Camera zoom
|
||||
if ((CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
|
||||
{
|
||||
CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
|
||||
if (CAMERA.targetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP;
|
||||
}
|
||||
|
||||
// Camera looking down
|
||||
else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
|
||||
{
|
||||
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
|
||||
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
|
||||
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
|
||||
}
|
||||
else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0))
|
||||
{
|
||||
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
|
||||
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
|
||||
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
|
||||
|
||||
// if (camera->target.y < 0) camera->target.y = -0.001;
|
||||
}
|
||||
else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0))
|
||||
{
|
||||
CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
|
||||
if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
|
||||
}
|
||||
// Camera looking up
|
||||
else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
|
||||
{
|
||||
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
|
||||
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
|
||||
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
|
||||
}
|
||||
else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0))
|
||||
{
|
||||
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
|
||||
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
|
||||
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
|
||||
|
||||
// if (camera->target.y > 0) camera->target.y = 0.001;
|
||||
}
|
||||
else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0))
|
||||
{
|
||||
CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
|
||||
if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
|
||||
}
|
||||
|
||||
// Input keys checks
|
||||
if (keyPan)
|
||||
{
|
||||
if (keyAlt) // Alternative key behaviour
|
||||
{
|
||||
if (szoomKey)
|
||||
{
|
||||
// Camera smooth zoom
|
||||
CAMERA.targetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY);
|
||||
// Orbital can just orbit
|
||||
Matrix rotation = MatrixRotate(GetCameraUp(camera), CAMERA_ORBITAL_SPEED*GetFrameTime());
|
||||
Vector3 view = Vector3Subtract(camera->position, camera->target);
|
||||
view = Vector3Transform(view, rotation);
|
||||
camera->position = Vector3Add(camera->target, view);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Camera rotation
|
||||
CAMERA.angle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY;
|
||||
CAMERA.angle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY;
|
||||
if (IsKeyDown(KEY_DOWN)) CameraPitch(camera, -CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp);
|
||||
if (IsKeyDown(KEY_UP)) CameraPitch(camera, CAMERA_ROTATION_SPEED, lockView, rotateAroundTarget, rotateUp);
|
||||
if (IsKeyDown(KEY_RIGHT)) CameraYaw(camera, -CAMERA_ROTATION_SPEED, rotateAroundTarget);
|
||||
if (IsKeyDown(KEY_LEFT)) CameraYaw(camera, CAMERA_ROTATION_SPEED, rotateAroundTarget);
|
||||
if (IsKeyDown(KEY_Q)) CameraRoll(camera, -CAMERA_ROTATION_SPEED);
|
||||
if (IsKeyDown(KEY_E)) CameraRoll(camera, CAMERA_ROTATION_SPEED);
|
||||
|
||||
// Angle clamp
|
||||
if (CAMERA.angle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD;
|
||||
else if (CAMERA.angle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Camera panning
|
||||
camera->target.x += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
|
||||
camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
|
||||
camera->target.z += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(CAMERA.angle.x) + (mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(CAMERA.angle.x)*sinf(CAMERA.angle.y))*(CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER);
|
||||
}
|
||||
CameraYaw(camera, -mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY, rotateAroundTarget);
|
||||
CameraPitch(camera, -mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY, lockView, rotateAroundTarget, rotateUp);
|
||||
|
||||
// Camera movement
|
||||
if (IsKeyDown(KEY_W)) CameraMoveForward(camera, CAMERA_MOVE_SPEED, moveInWorldPlane);
|
||||
if (IsKeyDown(KEY_A)) CameraMoveRight(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane);
|
||||
if (IsKeyDown(KEY_S)) CameraMoveForward(camera, -CAMERA_MOVE_SPEED, moveInWorldPlane);
|
||||
if (IsKeyDown(KEY_D)) CameraMoveRight(camera, CAMERA_MOVE_SPEED, moveInWorldPlane);
|
||||
//if (IsKeyDown(KEY_SPACE)) CameraMoveUp(camera, CAMERA_MOVE_SPEED);
|
||||
//if (IsKeyDown(KEY_LEFT_CONTROL)) CameraMoveUp(camera, -CAMERA_MOVE_SPEED);
|
||||
}
|
||||
|
||||
// Update camera position with changes
|
||||
camera->position.x = -sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
|
||||
camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance + camera->target.y;
|
||||
camera->position.z = -cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
|
||||
|
||||
} break;
|
||||
case CAMERA_ORBITAL: // Camera just orbits around target, only zoom allowed
|
||||
if ((mode == CAMERA_THIRD_PERSON) || (mode == CAMERA_ORBITAL))
|
||||
{
|
||||
CAMERA.angle.x += CAMERA_ORBITAL_SPEED*GetFrameTime(); // Camera orbit angle
|
||||
CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom
|
||||
|
||||
// Camera distance clamp
|
||||
if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
|
||||
|
||||
// Update camera position with changes
|
||||
camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
|
||||
camera->position.y = ((CAMERA.angle.y <= 0.0f)? 1 : -1)*sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
|
||||
camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
|
||||
|
||||
} break;
|
||||
case CAMERA_FIRST_PERSON: // Camera moves as in a first-person game, controls are configurable
|
||||
{
|
||||
camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
|
||||
sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
|
||||
cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
|
||||
cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
|
||||
|
||||
camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
|
||||
sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
|
||||
1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
|
||||
|
||||
camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
|
||||
cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
|
||||
sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
|
||||
sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
|
||||
|
||||
// Camera orientation calculation
|
||||
CAMERA.angle.x -= mousePositionDelta.x*CAMERA_MOUSE_MOVE_SENSITIVITY*GetFrameTime();
|
||||
CAMERA.angle.y -= mousePositionDelta.y*CAMERA_MOUSE_MOVE_SENSITIVITY*GetFrameTime();
|
||||
|
||||
// Angle clamp
|
||||
if (CAMERA.angle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD;
|
||||
else if (CAMERA.angle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD;
|
||||
|
||||
// Calculate translation matrix
|
||||
Matrix matTranslation = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, (CAMERA.targetDistance/CAMERA_FREE_PANNING_DIVIDER),
|
||||
0.0f, 0.0f, 0.0f, 1.0f };
|
||||
|
||||
// Calculate rotation matrix
|
||||
Matrix matRotation = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f };
|
||||
|
||||
float cosz = cosf(0.0f);
|
||||
float sinz = sinf(0.0f);
|
||||
float cosy = cosf(-(PI*2 - CAMERA.angle.x));
|
||||
float siny = sinf(-(PI*2 - CAMERA.angle.x));
|
||||
float cosx = cosf(-(PI*2 - CAMERA.angle.y));
|
||||
float sinx = sinf(-(PI*2 - CAMERA.angle.y));
|
||||
|
||||
matRotation.m0 = cosz*cosy;
|
||||
matRotation.m4 = (cosz*siny*sinx) - (sinz*cosx);
|
||||
matRotation.m8 = (cosz*siny*cosx) + (sinz*sinx);
|
||||
matRotation.m1 = sinz*cosy;
|
||||
matRotation.m5 = (sinz*siny*sinx) + (cosz*cosx);
|
||||
matRotation.m9 = (sinz*siny*cosx) - (cosz*sinx);
|
||||
matRotation.m2 = -siny;
|
||||
matRotation.m6 = cosy*sinx;
|
||||
matRotation.m10= cosy*cosx;
|
||||
|
||||
// Multiply translation and rotation matrices
|
||||
Matrix matTransform = { 0 };
|
||||
matTransform.m0 = matTranslation.m0*matRotation.m0 + matTranslation.m1*matRotation.m4 + matTranslation.m2*matRotation.m8 + matTranslation.m3*matRotation.m12;
|
||||
matTransform.m1 = matTranslation.m0*matRotation.m1 + matTranslation.m1*matRotation.m5 + matTranslation.m2*matRotation.m9 + matTranslation.m3*matRotation.m13;
|
||||
matTransform.m2 = matTranslation.m0*matRotation.m2 + matTranslation.m1*matRotation.m6 + matTranslation.m2*matRotation.m10 + matTranslation.m3*matRotation.m14;
|
||||
matTransform.m3 = matTranslation.m0*matRotation.m3 + matTranslation.m1*matRotation.m7 + matTranslation.m2*matRotation.m11 + matTranslation.m3*matRotation.m15;
|
||||
matTransform.m4 = matTranslation.m4*matRotation.m0 + matTranslation.m5*matRotation.m4 + matTranslation.m6*matRotation.m8 + matTranslation.m7*matRotation.m12;
|
||||
matTransform.m5 = matTranslation.m4*matRotation.m1 + matTranslation.m5*matRotation.m5 + matTranslation.m6*matRotation.m9 + matTranslation.m7*matRotation.m13;
|
||||
matTransform.m6 = matTranslation.m4*matRotation.m2 + matTranslation.m5*matRotation.m6 + matTranslation.m6*matRotation.m10 + matTranslation.m7*matRotation.m14;
|
||||
matTransform.m7 = matTranslation.m4*matRotation.m3 + matTranslation.m5*matRotation.m7 + matTranslation.m6*matRotation.m11 + matTranslation.m7*matRotation.m15;
|
||||
matTransform.m8 = matTranslation.m8*matRotation.m0 + matTranslation.m9*matRotation.m4 + matTranslation.m10*matRotation.m8 + matTranslation.m11*matRotation.m12;
|
||||
matTransform.m9 = matTranslation.m8*matRotation.m1 + matTranslation.m9*matRotation.m5 + matTranslation.m10*matRotation.m9 + matTranslation.m11*matRotation.m13;
|
||||
matTransform.m10 = matTranslation.m8*matRotation.m2 + matTranslation.m9*matRotation.m6 + matTranslation.m10*matRotation.m10 + matTranslation.m11*matRotation.m14;
|
||||
matTransform.m11 = matTranslation.m8*matRotation.m3 + matTranslation.m9*matRotation.m7 + matTranslation.m10*matRotation.m11 + matTranslation.m11*matRotation.m15;
|
||||
matTransform.m12 = matTranslation.m12*matRotation.m0 + matTranslation.m13*matRotation.m4 + matTranslation.m14*matRotation.m8 + matTranslation.m15*matRotation.m12;
|
||||
matTransform.m13 = matTranslation.m12*matRotation.m1 + matTranslation.m13*matRotation.m5 + matTranslation.m14*matRotation.m9 + matTranslation.m15*matRotation.m13;
|
||||
matTransform.m14 = matTranslation.m12*matRotation.m2 + matTranslation.m13*matRotation.m6 + matTranslation.m14*matRotation.m10 + matTranslation.m15*matRotation.m14;
|
||||
matTransform.m15 = matTranslation.m12*matRotation.m3 + matTranslation.m13*matRotation.m7 + matTranslation.m14*matRotation.m11 + matTranslation.m15*matRotation.m15;
|
||||
|
||||
camera->target.x = camera->position.x - matTransform.m12;
|
||||
camera->target.y = camera->position.y - matTransform.m13;
|
||||
camera->target.z = camera->position.z - matTransform.m14;
|
||||
|
||||
// Camera position update
|
||||
// NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position'
|
||||
camera->position.y = CAMERA.playerEyesPosition;
|
||||
|
||||
// Camera swinging (y-movement), only when walking (some key pressed)
|
||||
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;
|
||||
case CAMERA_THIRD_PERSON: // Camera moves as in a third-person game, following target at a distance, controls are configurable
|
||||
{
|
||||
camera->position.x += (sinf(CAMERA.angle.x)*direction[MOVE_BACK] -
|
||||
sinf(CAMERA.angle.x)*direction[MOVE_FRONT] -
|
||||
cosf(CAMERA.angle.x)*direction[MOVE_LEFT] +
|
||||
cosf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
|
||||
|
||||
camera->position.y += (sinf(CAMERA.angle.y)*direction[MOVE_FRONT] -
|
||||
sinf(CAMERA.angle.y)*direction[MOVE_BACK] +
|
||||
1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
|
||||
|
||||
camera->position.z += (cosf(CAMERA.angle.x)*direction[MOVE_BACK] -
|
||||
cosf(CAMERA.angle.x)*direction[MOVE_FRONT] +
|
||||
sinf(CAMERA.angle.x)*direction[MOVE_LEFT] -
|
||||
sinf(CAMERA.angle.x)*direction[MOVE_RIGHT])*PLAYER_MOVEMENT_SENSITIVITY*GetFrameTime();
|
||||
|
||||
// Camera orientation calculation
|
||||
CAMERA.angle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
|
||||
CAMERA.angle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
|
||||
|
||||
// Angle clamp
|
||||
if (CAMERA.angle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD;
|
||||
else if (CAMERA.angle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) CAMERA.angle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD;
|
||||
|
||||
// Camera zoom
|
||||
CAMERA.targetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
|
||||
|
||||
// Camera distance clamp
|
||||
if (CAMERA.targetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) CAMERA.targetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
|
||||
|
||||
camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
|
||||
|
||||
if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
|
||||
else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
|
||||
|
||||
camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
|
||||
|
||||
} break;
|
||||
case CAMERA_CUSTOM: break;
|
||||
default: break;
|
||||
// Zoom target distance
|
||||
CameraMoveToTarget(camera, -GetMouseWheelMove());
|
||||
if (IsKeyPressed(KEY_KP_SUBTRACT)) CameraMoveToTarget(camera, 2.0f);
|
||||
if (IsKeyPressed(KEY_KP_ADD)) CameraMoveToTarget(camera, -2.0f);
|
||||
}
|
||||
}
|
||||
#endif // !CAMERA_STANDALONE
|
||||
|
||||
// Set camera pan key to combine with mouse movement (free camera)
|
||||
void SetCameraPanControl(int keyPan) { CAMERA.panControl = keyPan; }
|
||||
|
||||
// Set camera alt key to combine with mouse movement (free camera)
|
||||
void SetCameraAltControl(int keyAlt) { CAMERA.altControl = keyAlt; }
|
||||
|
||||
// Set camera smooth zoom key to combine with mouse (free camera)
|
||||
void SetCameraSmoothZoomControl(int szoomKey) { CAMERA.smoothZoomControl = szoomKey; }
|
||||
|
||||
// Set camera move controls (1st person and 3rd person cameras)
|
||||
void SetCameraMoveControls(int keyFront, int keyBack, int keyRight, int keyLeft, int keyUp, int keyDown)
|
||||
// Update camera movement, movement/rotation values should be provided by user
|
||||
void UpdateCameraPro(Camera *camera, Vector3 movement, Vector3 rotation, float zoom)
|
||||
{
|
||||
CAMERA.moveControl[MOVE_FRONT] = keyFront;
|
||||
CAMERA.moveControl[MOVE_BACK] = keyBack;
|
||||
CAMERA.moveControl[MOVE_RIGHT] = keyRight;
|
||||
CAMERA.moveControl[MOVE_LEFT] = keyLeft;
|
||||
CAMERA.moveControl[MOVE_UP] = keyUp;
|
||||
CAMERA.moveControl[MOVE_DOWN] = keyDown;
|
||||
// Required values
|
||||
// movement.x - Move forward/backward
|
||||
// movement.y - Move right/left
|
||||
// movement.z - Move up/down
|
||||
// rotation.x - yaw
|
||||
// rotation.y - pitch
|
||||
// rotation.z - roll
|
||||
// zoom - Move towards target
|
||||
|
||||
bool lockView = true;
|
||||
bool rotateAroundTarget = false;
|
||||
bool rotateUp = false;
|
||||
bool moveInWorldPlane = true;
|
||||
|
||||
// Camera rotation
|
||||
CameraPitch(camera, -rotation.y*DEG2RAD, lockView, rotateAroundTarget, rotateUp);
|
||||
CameraYaw(camera, -rotation.x*DEG2RAD, rotateAroundTarget);
|
||||
CameraRoll(camera, rotation.z*DEG2RAD);
|
||||
|
||||
// Camera movement
|
||||
CameraMoveForward(camera, movement.x, moveInWorldPlane);
|
||||
CameraMoveRight(camera, movement.y, moveInWorldPlane);
|
||||
CameraMoveUp(camera, movement.z);
|
||||
|
||||
// Zoom target distance
|
||||
CameraMoveToTarget(camera, zoom);
|
||||
}
|
||||
|
||||
#endif // CAMERA_IMPLEMENTATION
|
||||
|
|
336
raylib/rcore.c
336
raylib/rcore.c
|
@ -89,7 +89,7 @@
|
|||
*
|
||||
* LICENSE: zlib/libpng
|
||||
*
|
||||
* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||
* will the authors be held liable for any damages arising from the use of this software.
|
||||
|
@ -151,10 +151,13 @@
|
|||
#include "external/sdefl.h" // Deflate (RFC 1951) compressor
|
||||
#endif
|
||||
|
||||
#if (defined(__linux__) || defined(PLATFORM_WEB)) && _POSIX_C_SOURCE < 199309L
|
||||
#if (defined(__linux__) || defined(PLATFORM_WEB)) && (_POSIX_C_SOURCE < 199309L)
|
||||
#undef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 199309L // Required for: CLOCK_MONOTONIC if compiled with c99 without gnu ext.
|
||||
#endif
|
||||
#if defined(__linux__) && !defined(_GNU_SOURCE)
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
// Platform specific defines to handle GetApplicationDirectory()
|
||||
#if defined (PLATFORM_DESKTOP)
|
||||
|
@ -239,6 +242,7 @@
|
|||
#include <unistd.h> // Required for: usleep()
|
||||
|
||||
//#define GLFW_EXPOSE_NATIVE_COCOA // WARNING: Fails due to type redefinition
|
||||
void *glfwGetCocoaWindow(GLFWwindow* handle);
|
||||
#include "GLFW/glfw3native.h" // Required for: glfwGetCocoaWindow()
|
||||
#endif
|
||||
|
||||
|
@ -705,17 +709,15 @@ const char *TextFormat(const char *text, ...); // Formatting of text with
|
|||
#if defined(PLATFORM_ANDROID)
|
||||
// To allow easier porting to android, we allow the user to define a
|
||||
// main function which we call from android_main, defined by ourselves
|
||||
//extern int main(int argc, char *argv[]);
|
||||
extern void android_run();
|
||||
extern int main(int argc, char *argv[]);
|
||||
|
||||
void android_main(struct android_app *app)
|
||||
{
|
||||
char arg0[] = "raylib"; // NOTE: argv[] are mutable
|
||||
CORE.Android.app = app;
|
||||
|
||||
(void)android_run();
|
||||
// NOTE: Return codes != 0 are skipped
|
||||
//(void)main(1, (char *[]) { arg0, NULL });
|
||||
(void)main(1, (char *[]) { arg0, NULL });
|
||||
}
|
||||
|
||||
// NOTE: Add this to header (if apps really need it)
|
||||
|
@ -767,7 +769,7 @@ void InitWindow(int width, int height, const char *title)
|
|||
CORE.Input.Keyboard.exitKey = KEY_ESCAPE;
|
||||
CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f };
|
||||
CORE.Input.Mouse.cursor = MOUSE_CURSOR_ARROW;
|
||||
CORE.Input.Gamepad.lastButtonPressed = -1;
|
||||
CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
|
||||
#if defined(SUPPORT_EVENTS_WAITING)
|
||||
CORE.Window.eventWaiting = true;
|
||||
#endif
|
||||
|
@ -847,6 +849,7 @@ void InitWindow(int width, int height, const char *title)
|
|||
TRACELOG(LOG_FATAL, "Failed to initialize Graphic Device");
|
||||
return;
|
||||
}
|
||||
else SetWindowPosition(GetMonitorWidth(GetCurrentMonitor())/2 - CORE.Window.screen.width/2, GetMonitorHeight(GetCurrentMonitor())/2 - CORE.Window.screen.height/2);
|
||||
|
||||
// Initialize hi-res timer
|
||||
InitTimer();
|
||||
|
@ -863,7 +866,7 @@ void InitWindow(int width, int height, const char *title)
|
|||
LoadFontDefault();
|
||||
#if defined(SUPPORT_MODULE_RSHAPES)
|
||||
Rectangle rec = GetFontDefault().recs[95];
|
||||
// NOTE: We setup a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering
|
||||
// NOTE: We set up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering
|
||||
SetShapesTexture(GetFontDefault().texture, (Rectangle){ rec.x + 1, rec.y + 1, rec.width - 2, rec.height - 2 }); // WARNING: Module required: rshapes
|
||||
#endif
|
||||
#else
|
||||
|
@ -921,9 +924,6 @@ void InitWindow(int width, int height, const char *title)
|
|||
emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback);
|
||||
#endif
|
||||
|
||||
CORE.Input.Mouse.currentPosition.x = (float)CORE.Window.screen.width/2.0f;
|
||||
CORE.Input.Mouse.currentPosition.y = (float)CORE.Window.screen.height/2.0f;
|
||||
|
||||
#if defined(SUPPORT_EVENTS_AUTOMATION)
|
||||
events = (AutomationEvent *)malloc(MAX_CODE_AUTOMATION_EVENTS*sizeof(AutomationEvent));
|
||||
CORE.Time.frameCounter = 0;
|
||||
|
@ -1141,9 +1141,8 @@ bool IsWindowMinimized(void)
|
|||
{
|
||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
||||
return ((CORE.Window.flags & FLAG_WINDOW_MINIMIZED) > 0);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if window has been maximized (only PLATFORM_DESKTOP)
|
||||
|
@ -1151,9 +1150,8 @@ bool IsWindowMaximized(void)
|
|||
{
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
return ((CORE.Window.flags & FLAG_WINDOW_MAXIMIZED) > 0);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if window has the focus
|
||||
|
@ -1161,9 +1159,11 @@ bool IsWindowFocused(void)
|
|||
{
|
||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
||||
return ((CORE.Window.flags & FLAG_WINDOW_UNFOCUSED) == 0);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
return CORE.Android.appEnabled;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if window has been resizedLastFrame
|
||||
|
@ -1316,7 +1316,7 @@ void MaximizeWindow(void)
|
|||
void MinimizeWindow(void)
|
||||
{
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
// NOTE: Following function launches callback that sets appropiate flag!
|
||||
// NOTE: Following function launches callback that sets appropriate flag!
|
||||
glfwIconifyWindow(CORE.Window.handle);
|
||||
#endif
|
||||
}
|
||||
|
@ -1415,13 +1415,13 @@ void SetWindowState(unsigned int flags)
|
|||
// State change: FLAG_WINDOW_TRANSPARENT
|
||||
if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) != (flags & FLAG_WINDOW_TRANSPARENT)) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only by configured before window initialization");
|
||||
TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_HIGHDPI
|
||||
if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) != (flags & FLAG_WINDOW_HIGHDPI)) && ((flags & FLAG_WINDOW_HIGHDPI) > 0))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "WINDOW: High DPI can only by configured before window initialization");
|
||||
TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
|
||||
|
@ -1434,13 +1434,13 @@ void SetWindowState(unsigned int flags)
|
|||
// State change: FLAG_MSAA_4X_HINT
|
||||
if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) != (flags & FLAG_MSAA_4X_HINT)) && ((flags & FLAG_MSAA_4X_HINT) > 0))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "WINDOW: MSAA can only by configured before window initialization");
|
||||
TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization");
|
||||
}
|
||||
|
||||
// State change: FLAG_INTERLACED_HINT
|
||||
if (((CORE.Window.flags & FLAG_INTERLACED_HINT) != (flags & FLAG_INTERLACED_HINT)) && ((flags & FLAG_INTERLACED_HINT) > 0))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only by configured before window initialization");
|
||||
TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1523,13 +1523,13 @@ void ClearWindowState(unsigned int flags)
|
|||
// State change: FLAG_WINDOW_TRANSPARENT
|
||||
if (((CORE.Window.flags & FLAG_WINDOW_TRANSPARENT) > 0) && ((flags & FLAG_WINDOW_TRANSPARENT) > 0))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only by configured before window initialization");
|
||||
TRACELOG(LOG_WARNING, "WINDOW: Framebuffer transparency can only be configured before window initialization");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_HIGHDPI
|
||||
if (((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0) && ((flags & FLAG_WINDOW_HIGHDPI) > 0))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "WINDOW: High DPI can only by configured before window initialization");
|
||||
TRACELOG(LOG_WARNING, "WINDOW: High DPI can only be configured before window initialization");
|
||||
}
|
||||
|
||||
// State change: FLAG_WINDOW_MOUSE_PASSTHROUGH
|
||||
|
@ -1542,22 +1542,30 @@ void ClearWindowState(unsigned int flags)
|
|||
// State change: FLAG_MSAA_4X_HINT
|
||||
if (((CORE.Window.flags & FLAG_MSAA_4X_HINT) > 0) && ((flags & FLAG_MSAA_4X_HINT) > 0))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "WINDOW: MSAA can only by configured before window initialization");
|
||||
TRACELOG(LOG_WARNING, "WINDOW: MSAA can only be configured before window initialization");
|
||||
}
|
||||
|
||||
// State change: FLAG_INTERLACED_HINT
|
||||
if (((CORE.Window.flags & FLAG_INTERLACED_HINT) > 0) && ((flags & FLAG_INTERLACED_HINT) > 0))
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only by configured before window initialization");
|
||||
TRACELOG(LOG_WARNING, "RPI: Interlaced mode can only be configured before window initialization");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set icon for window (only PLATFORM_DESKTOP)
|
||||
// NOTE: Image must be in RGBA format, 8bit per channel
|
||||
// NOTE 1: Image must be in RGBA format, 8bit per channel
|
||||
// NOTE 2: Image is scaled by the OS for all required sizes
|
||||
void SetWindowIcon(Image image)
|
||||
{
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
if (image.data == NULL)
|
||||
{
|
||||
// Revert to the default window icon, pass in an empty image array
|
||||
glfwSetWindowIcon(CORE.Window.handle, 0, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
|
||||
{
|
||||
GLFWimage icon[1] = { 0 };
|
||||
|
@ -1571,6 +1579,44 @@ void SetWindowIcon(Image image)
|
|||
glfwSetWindowIcon(CORE.Window.handle, 1, icon);
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "GLFW: Window icon image must be in R8G8B8A8 pixel format");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set icon for window (multiple images, only PLATFORM_DESKTOP)
|
||||
// NOTE 1: Images must be in RGBA format, 8bit per channel
|
||||
// NOTE 2: The multiple images are used depending on provided sizes
|
||||
// Standard Windows icon sizes: 256, 128, 96, 64, 48, 32, 24, 16
|
||||
void SetWindowIcons(Image *images, int count)
|
||||
{
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
if ((images == NULL) || (count <= 0))
|
||||
{
|
||||
// Revert to the default window icon, pass in an empty image array
|
||||
glfwSetWindowIcon(CORE.Window.handle, 0, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
int valid = 0;
|
||||
GLFWimage *icons = RL_CALLOC(count, sizeof(GLFWimage));
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (images[i].format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8)
|
||||
{
|
||||
icons[valid].width = images[i].width;
|
||||
icons[valid].height = images[i].height;
|
||||
icons[valid].pixels = (unsigned char *)images[i].data;
|
||||
|
||||
valid++;
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "GLFW: Window icon image must be in R8G8B8A8 pixel format");
|
||||
}
|
||||
// NOTE: Images data is copied internally before this function returns
|
||||
glfwSetWindowIcon(CORE.Window.handle, valid, icons);
|
||||
|
||||
RL_FREE(icons);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1667,16 +1713,17 @@ void *GetWindowHandle(void)
|
|||
// NOTE: Returned handle is: void *HWND (windows.h)
|
||||
return glfwGetWin32Window(CORE.Window.handle);
|
||||
#endif
|
||||
#if defined(__linux__)
|
||||
#if defined(PLATFORM_DESKTOP) && defined(__linux__)
|
||||
// NOTE: Returned handle is: unsigned long Window (X.h)
|
||||
// typedef unsigned long XID;
|
||||
// typedef XID Window;
|
||||
//unsigned long id = (unsigned long)glfwGetX11Window(window);
|
||||
return NULL; // TODO: Find a way to return value... cast to void *?
|
||||
//unsigned long id = (unsigned long)glfwGetX11Window(CORE.Window.handle);
|
||||
//return NULL; // TODO: Find a way to return value... cast to void *?
|
||||
return (void *)CORE.Window.handle;
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
// NOTE: Returned handle is: (objc_object *)
|
||||
return NULL; // TODO: return (void *)glfwGetCocoaWindow(window);
|
||||
return (void *)glfwGetCocoaWindow(CORE.Window.handle);
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
|
@ -1785,6 +1832,12 @@ int GetMonitorWidth(int monitor)
|
|||
else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor");
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
|
||||
#endif
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
if (CORE.Android.app->window != NULL)
|
||||
{
|
||||
return ANativeWindow_getWidth(CORE.Android.app->window);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -1804,6 +1857,12 @@ int GetMonitorHeight(int monitor)
|
|||
else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor");
|
||||
}
|
||||
else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
|
||||
#endif
|
||||
#if defined(PLATFORM_ANDROID)
|
||||
if (CORE.Android.app->window != NULL)
|
||||
{
|
||||
return ANativeWindow_getHeight(CORE.Android.app->window);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
@ -1935,10 +1994,40 @@ void SetClipboardText(const char *text)
|
|||
glfwSetClipboardString(CORE.Window.handle, text);
|
||||
#endif
|
||||
#if defined(PLATFORM_WEB)
|
||||
emscripten_run_script(TextFormat("navigator.clipboard.writeText('%s')", text));
|
||||
// Security check to (partially) avoid malicious code
|
||||
if (strchr(text, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided Clipboard could be potentially malicious, avoid [\'] character");
|
||||
else emscripten_run_script(TextFormat("navigator.clipboard.writeText('%s')", text));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get clipboard text content
|
||||
// NOTE: returned string is allocated and freed by GLFW
|
||||
const char *GetClipboardText(void)
|
||||
{
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
return glfwGetClipboardString(CORE.Window.handle);
|
||||
#endif
|
||||
#if defined(PLATFORM_WEB)
|
||||
/*
|
||||
// Accessing clipboard data from browser is tricky due to security reasons
|
||||
// The method to use is navigator.clipboard.readText() but this is an asynchronous method
|
||||
// that will return at some moment after the function is called with the required data
|
||||
emscripten_run_script_string("navigator.clipboard.readText() \
|
||||
.then(text => { document.getElementById('clipboard').innerText = text; console.log('Pasted content: ', text); }) \
|
||||
.catch(err => { console.error('Failed to read clipboard contents: ', err); });"
|
||||
);
|
||||
|
||||
// The main issue is getting that data, one approach could be using ASYNCIFY and wait
|
||||
// for the data but it requires adding Asyncify emscripten library on compilation
|
||||
|
||||
// Another approach could be just copy the data in a HTML text field and try to retrieve it
|
||||
// later on if available... and clean it for future accesses
|
||||
*/
|
||||
return NULL;
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Enable waiting for events on EndDrawing(), no automatic event polling
|
||||
void EnableEventWaiting(void)
|
||||
{
|
||||
|
@ -1951,19 +2040,6 @@ void DisableEventWaiting(void)
|
|||
CORE.Window.eventWaiting = false;
|
||||
}
|
||||
|
||||
// Get clipboard text content
|
||||
// NOTE: returned string is allocated and freed by GLFW
|
||||
const char *GetClipboardText(void)
|
||||
{
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
return glfwGetClipboardString(CORE.Window.handle);
|
||||
#endif
|
||||
#if defined(PLATFORM_WEB)
|
||||
return emscripten_run_script_string("navigator.clipboard.readText()");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Show mouse cursor
|
||||
void ShowCursor(void)
|
||||
{
|
||||
|
@ -1999,6 +2075,8 @@ void EnableCursor(void)
|
|||
#if defined(PLATFORM_WEB)
|
||||
emscripten_exit_pointerlock();
|
||||
#endif
|
||||
// Set cursor position in the middle
|
||||
SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
|
||||
|
||||
CORE.Input.Mouse.cursorHidden = false;
|
||||
}
|
||||
|
@ -2012,6 +2090,8 @@ void DisableCursor(void)
|
|||
#if defined(PLATFORM_WEB)
|
||||
emscripten_request_pointerlock("#canvas", 1);
|
||||
#endif
|
||||
// Set cursor position in the middle
|
||||
SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2);
|
||||
|
||||
CORE.Input.Mouse.cursorHidden = true;
|
||||
}
|
||||
|
@ -2173,7 +2253,7 @@ void EndMode2D(void)
|
|||
}
|
||||
|
||||
// Initializes 3D mode with custom camera (3D)
|
||||
void BeginMode3D(Camera3D camera)
|
||||
void BeginMode3D(Camera camera)
|
||||
{
|
||||
rlDrawRenderBatchActive(); // Update and draw internal render batch
|
||||
|
||||
|
@ -2448,10 +2528,6 @@ Shader LoadShader(const char *vsFileName, const char *fsFileName)
|
|||
Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
|
||||
{
|
||||
Shader shader = { 0 };
|
||||
shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int));
|
||||
|
||||
// NOTE: All locations must be reseted to -1 (no location)
|
||||
for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
|
||||
|
||||
shader.id = rlLoadShaderCode(vsCode, fsCode);
|
||||
|
||||
|
@ -2468,7 +2544,12 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
|
|||
|
||||
// NOTE: If any location is not found, loc point becomes -1
|
||||
|
||||
// Get handles to GLSL input attibute locations
|
||||
shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int));
|
||||
|
||||
// All locations reset to -1 (no location)
|
||||
for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
|
||||
|
||||
// Get handles to GLSL input attribute locations
|
||||
shader.locs[SHADER_LOC_VERTEX_POSITION] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION);
|
||||
shader.locs[SHADER_LOC_VERTEX_TEXCOORD01] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD);
|
||||
shader.locs[SHADER_LOC_VERTEX_TEXCOORD02] = rlGetLocationAttrib(shader.id, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2);
|
||||
|
@ -2493,12 +2574,46 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
|
|||
return shader;
|
||||
}
|
||||
|
||||
// Check if a shader is ready
|
||||
bool IsShaderReady(Shader shader)
|
||||
{
|
||||
return ((shader.id > 0) && // Validate shader id (loaded successfully)
|
||||
(shader.locs != NULL)); // Validate memory has been allocated for default shader locations
|
||||
|
||||
// The following locations are tried to be set automatically (locs[i] >= 0),
|
||||
// any of them can be checked for validation but the only mandatory one is, afaik, SHADER_LOC_VERTEX_POSITION
|
||||
// NOTE: Users can also setup manually their own attributes/uniforms and do not used the default raylib ones
|
||||
|
||||
// Vertex shader attribute locations (default)
|
||||
// shader.locs[SHADER_LOC_VERTEX_POSITION] // Set by default internal shader
|
||||
// shader.locs[SHADER_LOC_VERTEX_TEXCOORD01] // Set by default internal shader
|
||||
// shader.locs[SHADER_LOC_VERTEX_TEXCOORD02]
|
||||
// shader.locs[SHADER_LOC_VERTEX_NORMAL]
|
||||
// shader.locs[SHADER_LOC_VERTEX_TANGENT]
|
||||
// shader.locs[SHADER_LOC_VERTEX_COLOR] // Set by default internal shader
|
||||
|
||||
// Vertex shader uniform locations (default)
|
||||
// shader.locs[SHADER_LOC_MATRIX_MVP] // Set by default internal shader
|
||||
// shader.locs[SHADER_LOC_MATRIX_VIEW]
|
||||
// shader.locs[SHADER_LOC_MATRIX_PROJECTION]
|
||||
// shader.locs[SHADER_LOC_MATRIX_MODEL]
|
||||
// shader.locs[SHADER_LOC_MATRIX_NORMAL]
|
||||
|
||||
// Fragment shader uniform locations (default)
|
||||
// shader.locs[SHADER_LOC_COLOR_DIFFUSE] // Set by default internal shader
|
||||
// shader.locs[SHADER_LOC_MAP_DIFFUSE] // Set by default internal shader
|
||||
// shader.locs[SHADER_LOC_MAP_SPECULAR]
|
||||
// shader.locs[SHADER_LOC_MAP_NORMAL]
|
||||
}
|
||||
|
||||
// Unload shader from GPU memory (VRAM)
|
||||
void UnloadShader(Shader shader)
|
||||
{
|
||||
if (shader.id != rlGetShaderIdDefault())
|
||||
{
|
||||
rlUnloadShaderProgram(shader.id);
|
||||
|
||||
// NOTE: If shader loading failed, it should be 0
|
||||
RL_FREE(shader.locs);
|
||||
}
|
||||
}
|
||||
|
@ -2524,25 +2639,34 @@ void SetShaderValue(Shader shader, int locIndex, const void *value, int uniformT
|
|||
// Set shader uniform value vector
|
||||
void SetShaderValueV(Shader shader, int locIndex, const void *value, int uniformType, int count)
|
||||
{
|
||||
if (locIndex > -1)
|
||||
{
|
||||
rlEnableShader(shader.id);
|
||||
rlSetUniform(locIndex, value, uniformType, count);
|
||||
//rlDisableShader(); // Avoid reseting current shader program, in case other uniforms are set
|
||||
//rlDisableShader(); // Avoid resetting current shader program, in case other uniforms are set
|
||||
}
|
||||
}
|
||||
|
||||
// Set shader uniform value (matrix 4x4)
|
||||
void SetShaderValueMatrix(Shader shader, int locIndex, Matrix mat)
|
||||
{
|
||||
if (locIndex > -1)
|
||||
{
|
||||
rlEnableShader(shader.id);
|
||||
rlSetUniformMatrix(locIndex, mat);
|
||||
//rlDisableShader();
|
||||
}
|
||||
}
|
||||
|
||||
// Set shader uniform value for texture
|
||||
void SetShaderValueTexture(Shader shader, int locIndex, Texture2D texture)
|
||||
{
|
||||
if (locIndex > -1)
|
||||
{
|
||||
rlEnableShader(shader.id);
|
||||
rlSetUniformSampler(locIndex, texture.id);
|
||||
//rlDisableShader();
|
||||
}
|
||||
}
|
||||
|
||||
// Get a ray trace from mouse position
|
||||
|
@ -2584,7 +2708,7 @@ Ray GetMouseRay(Vector2 mouse, Camera camera)
|
|||
Vector3 farPoint = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, 1.0f }, matProj, matView);
|
||||
|
||||
// Unproject the mouse cursor in the near plane.
|
||||
// We need this as the source position because orthographic projects, compared to perspect doesn't have a
|
||||
// We need this as the source position because orthographic projects, compared to perspective doesn't have a
|
||||
// convergence point, meaning that the "eye" of the camera is more like a plane than a point.
|
||||
Vector3 cameraPlanePointerPos = Vector3Unproject((Vector3){ deviceCoords.x, deviceCoords.y, -1.0f }, matProj, matView);
|
||||
|
||||
|
@ -2757,22 +2881,24 @@ float GetFrameTime(void)
|
|||
// NOTE: On PLATFORM_DESKTOP, timer is initialized on glfwInit()
|
||||
double GetTime(void)
|
||||
{
|
||||
double time = 0.0;
|
||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
||||
return glfwGetTime(); // Elapsed time since glfwInit()
|
||||
time = glfwGetTime(); // Elapsed time since glfwInit()
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_DRM)
|
||||
struct timespec ts = { 0 };
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
unsigned long long int time = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
|
||||
unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec;
|
||||
|
||||
return (double)(time - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
|
||||
time = (double)(nanoSeconds - CORE.Time.base)*1e-9; // Elapsed time since InitTimer()
|
||||
#endif
|
||||
return time;
|
||||
}
|
||||
|
||||
// Setup window configuration flags (view FLAGS)
|
||||
// NOTE: This function is expected to be called before window creation,
|
||||
// because it setups some flags for the window creation process.
|
||||
// because it sets up some flags for the window creation process.
|
||||
// To configure window states after creation, just use SetWindowState()
|
||||
void SetConfigFlags(unsigned int flags)
|
||||
{
|
||||
|
@ -2787,6 +2913,9 @@ void SetConfigFlags(unsigned int flags)
|
|||
void TakeScreenshot(const char *fileName)
|
||||
{
|
||||
#if defined(SUPPORT_MODULE_RTEXTURES)
|
||||
// Security check to (partially) avoid malicious code on PLATFORM_WEB
|
||||
if (strchr(fileName, '\'') != NULL) { TRACELOG(LOG_WARNING, "SYSTEM: Provided fileName could be potentially malicious, avoid [\'] character"); return; }
|
||||
|
||||
Vector2 scale = GetWindowScaleDPI();
|
||||
unsigned char *imgData = rlReadScreenPixels((int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y));
|
||||
Image image = { imgData, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 };
|
||||
|
@ -2810,6 +2939,9 @@ void TakeScreenshot(const char *fileName)
|
|||
}
|
||||
|
||||
// Get a random value between min and max (both included)
|
||||
// WARNING: Ranges higher than RAND_MAX will return invalid results
|
||||
// More specifically, if (max - min) > INT_MAX there will be an overflow,
|
||||
// and otherwise if (max - min) > RAND_MAX the random value will incorrectly never exceed a certain threshold
|
||||
int GetRandomValue(int min, int max)
|
||||
{
|
||||
if (min > max)
|
||||
|
@ -2819,6 +2951,11 @@ int GetRandomValue(int min, int max)
|
|||
min = tmp;
|
||||
}
|
||||
|
||||
if ((unsigned int)(max - min) > (unsigned int)RAND_MAX)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "Invalid GetRandomValue() arguments, range should not be higher than %i", RAND_MAX);
|
||||
}
|
||||
|
||||
return (rand()%(abs(max - min) + 1) + min);
|
||||
}
|
||||
|
||||
|
@ -2989,7 +3126,7 @@ const char *GetDirectoryPath(const char *filePath)
|
|||
if (filePath[1] != ':' && filePath[0] != '\\' && filePath[0] != '/')
|
||||
{
|
||||
// For security, we set starting path to current directory,
|
||||
// obtained path will be concated to this
|
||||
// obtained path will be concatenated to this
|
||||
dirPath[0] = '.';
|
||||
dirPath[1] = '/';
|
||||
}
|
||||
|
@ -3183,14 +3320,12 @@ FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool
|
|||
}
|
||||
|
||||
// Unload directory filepaths
|
||||
// WARNING: files.count is not reseted to 0 after unloading
|
||||
void UnloadDirectoryFiles(FilePathList files)
|
||||
{
|
||||
if (files.capacity > 0)
|
||||
{
|
||||
for (unsigned int i = 0; i < files.capacity; i++) RL_FREE(files.paths[i]);
|
||||
|
||||
RL_FREE(files.paths);
|
||||
}
|
||||
}
|
||||
|
||||
// Change working directory, returns true on success
|
||||
|
@ -3275,7 +3410,7 @@ unsigned char *CompressData(const unsigned char *data, int dataSize, int *compDa
|
|||
compData = (unsigned char *)RL_CALLOC(bounds, 1);
|
||||
*compDataSize = sdeflate(&sdefl, compData, data, dataSize, COMPRESSION_QUALITY_DEFLATE); // Compression level 8, same as stbwi
|
||||
|
||||
TraceLog(LOG_INFO, "SYSTEM: Compress data: Original size: %i -> Comp. size: %i", dataSize, *compDataSize);
|
||||
TRACELOG(LOG_INFO, "SYSTEM: Compress data: Original size: %i -> Comp. size: %i", dataSize, *compDataSize);
|
||||
#endif
|
||||
|
||||
return compData;
|
||||
|
@ -3288,16 +3423,19 @@ unsigned char *DecompressData(const unsigned char *compData, int compDataSize, i
|
|||
|
||||
#if defined(SUPPORT_COMPRESSION_API)
|
||||
// Decompress data from a valid DEFLATE stream
|
||||
data = RL_CALLOC(MAX_DECOMPRESSION_SIZE*1024*1024, 1);
|
||||
data = (unsigned char *)RL_CALLOC(MAX_DECOMPRESSION_SIZE*1024*1024, 1);
|
||||
int length = sinflate(data, MAX_DECOMPRESSION_SIZE*1024*1024, compData, compDataSize);
|
||||
unsigned char *temp = RL_REALLOC(data, length);
|
||||
|
||||
// WARNING: RL_REALLOC can make (and leave) data copies in memory, be careful with sensitive compressed data!
|
||||
// TODO: Use a different approach, create another buffer, copy data manually to it and wipe original buffer memory
|
||||
unsigned char *temp = (unsigned char *)RL_REALLOC(data, length);
|
||||
|
||||
if (temp != NULL) data = temp;
|
||||
else TRACELOG(LOG_WARNING, "SYSTEM: Failed to re-allocate required decompression memory");
|
||||
|
||||
*dataSize = length;
|
||||
|
||||
TraceLog(LOG_INFO, "SYSTEM: Decompress data: Comp. size: %i -> Original size: %i", compDataSize, *dataSize);
|
||||
TRACELOG(LOG_INFO, "SYSTEM: Decompress data: Comp. size: %i -> Original size: %i", compDataSize, *dataSize);
|
||||
#endif
|
||||
|
||||
return data;
|
||||
|
@ -3316,7 +3454,7 @@ char *EncodeDataBase64(const unsigned char *data, int dataSize, int *outputSize)
|
|||
|
||||
*outputSize = 4*((dataSize + 2)/3);
|
||||
|
||||
char *encodedData = RL_MALLOC(*outputSize);
|
||||
char *encodedData = (char *)RL_MALLOC(*outputSize);
|
||||
|
||||
if (encodedData == NULL) return NULL;
|
||||
|
||||
|
@ -3404,16 +3542,12 @@ unsigned char *DecodeDataBase64(const unsigned char *data, int *outputSize)
|
|||
// Ref: https://github.com/raysan5/raylib/issues/686
|
||||
void OpenURL(const char *url)
|
||||
{
|
||||
// Small security check trying to avoid (partially) malicious code...
|
||||
// sorry for the inconvenience when you hit this point...
|
||||
if (strchr(url, '\'') != NULL)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "SYSTEM: Provided URL is not valid");
|
||||
}
|
||||
// Security check to (aprtially) avoid malicious code on PLATFORM_WEB
|
||||
if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character");
|
||||
else
|
||||
{
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
char *cmd = (char *)RL_CALLOC(strlen(url) + 10, sizeof(char));
|
||||
char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char));
|
||||
#if defined(_WIN32)
|
||||
sprintf(cmd, "explorer \"%s\"", url);
|
||||
#endif
|
||||
|
@ -3508,7 +3642,7 @@ int GetKeyPressed(void)
|
|||
CORE.Input.Keyboard.keyPressedQueue[i] = CORE.Input.Keyboard.keyPressedQueue[i + 1];
|
||||
|
||||
// Reset last character in the queue
|
||||
CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = 0;
|
||||
CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount - 1] = 0;
|
||||
CORE.Input.Keyboard.keyPressedQueueCount--;
|
||||
}
|
||||
|
||||
|
@ -3530,7 +3664,7 @@ int GetCharPressed(void)
|
|||
CORE.Input.Keyboard.charPressedQueue[i] = CORE.Input.Keyboard.charPressedQueue[i + 1];
|
||||
|
||||
// Reset last character in the queue
|
||||
CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = 0;
|
||||
CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount - 1] = 0;
|
||||
CORE.Input.Keyboard.charPressedQueueCount--;
|
||||
}
|
||||
|
||||
|
@ -3743,7 +3877,7 @@ Vector2 GetMousePosition(void)
|
|||
// Get mouse delta between frames
|
||||
Vector2 GetMouseDelta(void)
|
||||
{
|
||||
Vector2 delta = {0};
|
||||
Vector2 delta = { 0 };
|
||||
|
||||
delta.x = CORE.Input.Mouse.currentPosition.x - CORE.Input.Mouse.previousPosition.x;
|
||||
delta.y = CORE.Input.Mouse.currentPosition.y - CORE.Input.Mouse.previousPosition.y;
|
||||
|
@ -3755,6 +3889,8 @@ Vector2 GetMouseDelta(void)
|
|||
void SetMousePosition(int x, int y)
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y };
|
||||
CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
||||
|
||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
||||
// NOTE: emscripten not implemented
|
||||
glfwSetCursorPos(CORE.Window.handle, CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y);
|
||||
|
@ -3884,7 +4020,7 @@ static bool InitGraphicsDevice(int width, int height)
|
|||
CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default
|
||||
|
||||
// NOTE: Framebuffer (render area - CORE.Window.render.width, CORE.Window.render.height) could include black bars...
|
||||
// ...in top-down or left-right to match display aspect ratio (no weird scalings)
|
||||
// ...in top-down or left-right to match display aspect ratio (no weird scaling)
|
||||
|
||||
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
||||
glfwSetErrorCallback(ErrorCallback);
|
||||
|
@ -4053,8 +4189,18 @@ static bool InitGraphicsDevice(int width, int height)
|
|||
if (CORE.Window.fullscreen)
|
||||
{
|
||||
// remember center for switchinging from fullscreen to window
|
||||
if ((CORE.Window.screen.height == CORE.Window.display.height) && (CORE.Window.screen.width == CORE.Window.display.width))
|
||||
{
|
||||
// If screen width/height equal to the display, we can't calculate the window pos for toggling full-screened/windowed.
|
||||
// Toggling full-screened/windowed with pos(0, 0) can cause problems in some platforms, such as X11.
|
||||
CORE.Window.position.x = CORE.Window.display.width/4;
|
||||
CORE.Window.position.y = CORE.Window.display.height/4;
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Window.position.x = CORE.Window.display.width/2 - CORE.Window.screen.width/2;
|
||||
CORE.Window.position.y = CORE.Window.display.height/2 - CORE.Window.screen.height/2;
|
||||
}
|
||||
|
||||
if (CORE.Window.position.x < 0) CORE.Window.position.x = 0;
|
||||
if (CORE.Window.position.y < 0) CORE.Window.position.y = 0;
|
||||
|
@ -4083,7 +4229,7 @@ static bool InitGraphicsDevice(int width, int height)
|
|||
// framebuffer is rendered correctly but once displayed on a 16:9 monitor, it gets stretched
|
||||
// by the sides to fit all monitor space...
|
||||
|
||||
// Try to setup the most appropiate fullscreen framebuffer for the requested screenWidth/screenHeight
|
||||
// Try to setup the most appropriate fullscreen framebuffer for the requested screenWidth/screenHeight
|
||||
// It considers device display resolution mode and setups a framebuffer with black bars if required (render size/offset)
|
||||
// Modified global variables: CORE.Window.screen.width/CORE.Window.screen.height - CORE.Window.render.width/CORE.Window.render.height - CORE.Window.renderOffset.x/CORE.Window.renderOffset.y - CORE.Window.screenScale
|
||||
// TODO: It is a quite cumbersome solution to display size vs requested size, it should be reviewed or removed...
|
||||
|
@ -4150,7 +4296,7 @@ static bool InitGraphicsDevice(int width, int height)
|
|||
// NOTE: V-Sync can be enabled by graphic driver configuration
|
||||
if (CORE.Window.flags & FLAG_VSYNC_HINT)
|
||||
{
|
||||
// WARNING: It seems to hits a critical render path in Intel HD Graphics
|
||||
// WARNING: It seems to hit a critical render path in Intel HD Graphics
|
||||
glfwSwapInterval(1);
|
||||
TRACELOG(LOG_INFO, "DISPLAY: Trying to enable VSYNC");
|
||||
}
|
||||
|
@ -4161,12 +4307,12 @@ static bool InitGraphicsDevice(int width, int height)
|
|||
#if defined(PLATFORM_DESKTOP)
|
||||
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
|
||||
{
|
||||
// NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling
|
||||
// NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling.
|
||||
// Framebuffer scaling should be activated with: glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE);
|
||||
#if !defined(__APPLE__)
|
||||
glfwGetFramebufferSize(CORE.Window.handle, &fbWidth, &fbHeight);
|
||||
|
||||
// Screen scaling matrix is required in case desired screen area is different than display area
|
||||
// Screen scaling matrix is required in case desired screen area is different from display area
|
||||
CORE.Window.screenScale = MatrixScale((float)fbWidth/CORE.Window.screen.width, (float)fbHeight/CORE.Window.screen.height, 1.0f);
|
||||
|
||||
// Mouse input scaling for the new screen size
|
||||
|
@ -4764,7 +4910,7 @@ static void InitTimer(void)
|
|||
// NOTE: Sleep() granularity could be around 10 ms, it means, Sleep() could
|
||||
// take longer than expected... for that reason we use the busy wait loop
|
||||
// Ref: http://stackoverflow.com/questions/43057578/c-programming-win32-games-sleep-taking-longer-than-expected
|
||||
// Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timming on Win32!
|
||||
// Ref: http://www.geisswerks.com/ryan/FAQS/timing.html --> All about timing on Win32!
|
||||
void WaitTime(double seconds)
|
||||
{
|
||||
#if defined(SUPPORT_BUSY_WAIT_LOOP) || defined(SUPPORT_PARTIALBUSY_WAIT_LOOP)
|
||||
|
@ -4859,7 +5005,7 @@ void PollInputEvents(void)
|
|||
|
||||
#if !(defined(PLATFORM_RPI) || defined(PLATFORM_DRM))
|
||||
// Reset last gamepad button/axis registered state
|
||||
CORE.Input.Gamepad.lastButtonPressed = -1;
|
||||
CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
|
||||
CORE.Input.Gamepad.axisCount = 0;
|
||||
#endif
|
||||
|
||||
|
@ -5359,12 +5505,12 @@ static void CharCallback(GLFWwindow *window, unsigned int key)
|
|||
//TRACELOG(LOG_DEBUG, "Char Callback: KEY:%i(%c)", key, key);
|
||||
|
||||
// NOTE: Registers any key down considering OS keyboard layout but
|
||||
// do not detects action events, those should be managed by user...
|
||||
// does not detect action events, those should be managed by user...
|
||||
// Ref: https://github.com/glfw/glfw/issues/668#issuecomment-166794907
|
||||
// Ref: https://www.glfw.org/docs/latest/input_guide.html#input_char
|
||||
|
||||
// Check if there is space available in the queue
|
||||
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_KEY_PRESSED_QUEUE)
|
||||
if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
|
||||
{
|
||||
// Add character to the queue
|
||||
CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = key;
|
||||
|
@ -5402,7 +5548,7 @@ static void MouseButtonCallback(GLFWwindow *window, int button, int action, int
|
|||
gestureEvent.position[0].x /= (float)GetScreenWidth();
|
||||
gestureEvent.position[0].y /= (float)GetScreenHeight();
|
||||
|
||||
// Gesture data is sent to gestures system for processing
|
||||
// Gesture data is sent to gestures-system for processing
|
||||
ProcessGestureEvent(gestureEvent);
|
||||
#endif
|
||||
}
|
||||
|
@ -5433,7 +5579,7 @@ static void MouseCursorPosCallback(GLFWwindow *window, double x, double y)
|
|||
gestureEvent.position[0].x /= (float)GetScreenWidth();
|
||||
gestureEvent.position[0].y /= (float)GetScreenHeight();
|
||||
|
||||
// Gesture data is sent to gestures system for processing
|
||||
// Gesture data is sent to gestures-system for processing
|
||||
ProcessGestureEvent(gestureEvent);
|
||||
#endif
|
||||
}
|
||||
|
@ -5454,6 +5600,8 @@ static void CursorEnterCallback(GLFWwindow *window, int enter)
|
|||
// GLFW3 Window Drop Callback, runs when drop files into window
|
||||
static void WindowDropCallback(GLFWwindow *window, int count, const char **paths)
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
// In case previous dropped filepaths have not been freed, we free them
|
||||
if (CORE.Window.dropFileCount > 0)
|
||||
{
|
||||
|
@ -5474,6 +5622,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths
|
|||
CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char));
|
||||
strcpy(CORE.Window.dropFilepaths[i], paths[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -5702,14 +5851,15 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
|
|||
CORE.Input.Gamepad.ready[0] = true;
|
||||
|
||||
GamepadButton button = AndroidTranslateGamepadButton(keycode);
|
||||
if (button == GAMEPAD_BUTTON_UNKNOWN)
|
||||
return 1;
|
||||
|
||||
if (button == GAMEPAD_BUTTON_UNKNOWN) return 1;
|
||||
|
||||
if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN)
|
||||
{
|
||||
CORE.Input.Gamepad.currentButtonState[0][button] = 1;
|
||||
}
|
||||
else CORE.Input.Gamepad.currentButtonState[0][button] = 0; // Key up
|
||||
|
||||
return 1; // Handled gamepad button
|
||||
}
|
||||
|
||||
|
@ -6673,7 +6823,7 @@ static void *GamepadThread(void *arg)
|
|||
CORE.Input.Gamepad.currentButtonState[i][gamepadEvent.number] = (int)gamepadEvent.value;
|
||||
|
||||
if ((int)gamepadEvent.value == 1) CORE.Input.Gamepad.lastButtonPressed = gamepadEvent.number;
|
||||
else CORE.Input.Gamepad.lastButtonPressed = -1;
|
||||
else CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
|
||||
}
|
||||
}
|
||||
else if (gamepadEvent.type == JS_EVENT_AXIS)
|
||||
|
@ -6800,12 +6950,12 @@ static void LoadAutomationEvents(const char *fileName)
|
|||
// Load binary
|
||||
/*
|
||||
FILE *repFile = fopen(fileName, "rb");
|
||||
fread(fileId, 4, 1, repFile);
|
||||
fread(fileId, 1, 4, repFile);
|
||||
|
||||
if ((fileId[0] == 'r') && (fileId[1] == 'E') && (fileId[2] == 'P') && (fileId[1] == ' '))
|
||||
{
|
||||
fread(&eventCount, sizeof(int), 1, repFile);
|
||||
TraceLog(LOG_WARNING, "Events loaded: %i\n", eventCount);
|
||||
TRACELOG(LOG_WARNING, "Events loaded: %i\n", eventCount);
|
||||
fread(events, sizeof(AutomationEvent), eventCount, repFile);
|
||||
}
|
||||
|
||||
|
@ -6852,7 +7002,7 @@ static void ExportAutomationEvents(const char *fileName)
|
|||
// Save as binary
|
||||
/*
|
||||
FILE *repFile = fopen(fileName, "wb");
|
||||
fwrite(fileId, 4, 1, repFile);
|
||||
fwrite(fileId, sizeof(unsigned char), 4, repFile);
|
||||
fwrite(&eventCount, sizeof(int), 1, repFile);
|
||||
fwrite(events, sizeof(AutomationEvent), eventCount, repFile);
|
||||
fclose(repFile);
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
*
|
||||
* LICENSE: zlib/libpng
|
||||
*
|
||||
* Copyright (c) 2014-2022 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||
* will the authors be held liable for any damages arising from the use of this software.
|
||||
|
@ -249,7 +249,7 @@ static double rgGetCurrentTime(void);
|
|||
// Module Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
// Enable only desired getures to be detected
|
||||
// Enable only desired gestures to be detected
|
||||
void SetGesturesEnabled(unsigned int flags)
|
||||
{
|
||||
GESTURES.enabledFlags = flags;
|
||||
|
@ -300,7 +300,7 @@ void ProcessGestureEvent(GestureEvent event)
|
|||
{
|
||||
if (GESTURES.current == GESTURE_DRAG) GESTURES.Touch.upPosition = event.position[0];
|
||||
|
||||
// NOTE: GESTURES.Drag.intensity dependend on the resolution of the screen
|
||||
// NOTE: GESTURES.Drag.intensity dependent on the resolution of the screen
|
||||
GESTURES.Drag.distance = rgVector2Distance(GESTURES.Touch.downPositionA, GESTURES.Touch.upPosition);
|
||||
GESTURES.Drag.intensity = GESTURES.Drag.distance/(float)((rgGetCurrentTime() - GESTURES.Swipe.timeDuration));
|
||||
|
||||
|
@ -472,7 +472,7 @@ Vector2 GetGestureDragVector(void)
|
|||
}
|
||||
|
||||
// Get drag angle
|
||||
// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise
|
||||
// NOTE: Angle in degrees, horizontal-right is 0, counterclockwise
|
||||
float GetGestureDragAngle(void)
|
||||
{
|
||||
// NOTE: drag angle is calculated on one touch points TOUCH_ACTION_UP
|
||||
|
@ -488,8 +488,8 @@ Vector2 GetGesturePinchVector(void)
|
|||
return GESTURES.Pinch.vector;
|
||||
}
|
||||
|
||||
// Get angle beween two pinch points
|
||||
// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise
|
||||
// Get angle between two pinch points
|
||||
// NOTE: Angle in degrees, horizontal-right is 0, counterclockwise
|
||||
float GetGesturePinchAngle(void)
|
||||
{
|
||||
// NOTE: pinch angle is calculated on two touch points TOUCH_ACTION_MOVE
|
||||
|
|
|
@ -986,11 +986,11 @@ func GetShaderBufferSize(id uint32) uint32 {
|
|||
}
|
||||
|
||||
// BindImageTexture - Bind image texture
|
||||
func BindImageTexture(id uint32, index uint32, format uint32, readonly int32) {
|
||||
func BindImageTexture(id uint32, index uint32, format int32, readonly bool) {
|
||||
cid := C.uint(id)
|
||||
cindex := C.uint(index)
|
||||
cformat := C.uint(format)
|
||||
creadonly := C.int(readonly)
|
||||
cformat := C.int(format)
|
||||
creadonly := C.bool(readonly)
|
||||
C.rlBindImageTexture(cid, cindex, cformat, creadonly)
|
||||
}
|
||||
|
||||
|
|
221
raylib/rlgl.h
221
raylib/rlgl.h
|
@ -1,15 +1,15 @@
|
|||
/**********************************************************************************************
|
||||
*
|
||||
* rlgl v4.2 - A multi-OpenGL abstraction layer with an immediate-mode style API
|
||||
* rlgl v4.5 - A multi-OpenGL abstraction layer with an immediate-mode style API
|
||||
*
|
||||
* An abstraction layer for multiple OpenGL versions (1.1, 2.1, 3.3 Core, 4.3 Core, ES 2.0)
|
||||
* that provides a pseudo-OpenGL 1.1 immediate-mode style API (rlVertex, rlTranslate, rlRotate...)
|
||||
*
|
||||
* When chosing an OpenGL backend different than OpenGL 1.1, some internal buffer are
|
||||
* When choosing an OpenGL backend different than OpenGL 1.1, some internal buffer are
|
||||
* initialized on rlglInit() to accumulate vertex data.
|
||||
*
|
||||
* When an internal state change is required all the stored vertex data is renderer in batch,
|
||||
* additioanlly, rlDrawRenderBatchActive() could be called to force flushing of the batch.
|
||||
* additionally, rlDrawRenderBatchActive() could be called to force flushing of the batch.
|
||||
*
|
||||
* Some additional resources are also loaded for convenience, here the complete list:
|
||||
* - Default batch (RLGL.defaultBatch): RenderBatch system to accumulate vertex data
|
||||
|
@ -61,12 +61,11 @@
|
|||
* When loading a shader, the following vertex attribute and uniform
|
||||
* location names are tried to be set automatically:
|
||||
*
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Binded by default to shader location: 0
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: 0
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: 1
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: 2
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: 3
|
||||
* #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: 4
|
||||
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix
|
||||
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix
|
||||
* #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix
|
||||
|
@ -85,7 +84,7 @@
|
|||
*
|
||||
* LICENSE: zlib/libpng
|
||||
*
|
||||
* Copyright (c) 2014-2022 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||
* will the authors be held liable for any damages arising from the use of this software.
|
||||
|
@ -107,7 +106,7 @@
|
|||
#ifndef RLGL_H
|
||||
#define RLGL_H
|
||||
|
||||
#define RLGL_VERSION "4.2"
|
||||
#define RLGL_VERSION "4.5"
|
||||
|
||||
// Function specifiers in case library is build/used as a shared library (Windows)
|
||||
// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll
|
||||
|
@ -264,7 +263,7 @@
|
|||
#define RL_UNSIGNED_BYTE 0x1401 // GL_UNSIGNED_BYTE
|
||||
#define RL_FLOAT 0x1406 // GL_FLOAT
|
||||
|
||||
// Buffer usage hint
|
||||
// GL buffer usage hint
|
||||
#define RL_STREAM_DRAW 0x88E0 // GL_STREAM_DRAW
|
||||
#define RL_STREAM_READ 0x88E1 // GL_STREAM_READ
|
||||
#define RL_STREAM_COPY 0x88E2 // GL_STREAM_COPY
|
||||
|
@ -280,6 +279,39 @@
|
|||
#define RL_VERTEX_SHADER 0x8B31 // GL_VERTEX_SHADER
|
||||
#define RL_COMPUTE_SHADER 0x91B9 // GL_COMPUTE_SHADER
|
||||
|
||||
// GL blending factors
|
||||
#define RL_ZERO 0 // GL_ZERO
|
||||
#define RL_ONE 1 // GL_ONE
|
||||
#define RL_SRC_COLOR 0x0300 // GL_SRC_COLOR
|
||||
#define RL_ONE_MINUS_SRC_COLOR 0x0301 // GL_ONE_MINUS_SRC_COLOR
|
||||
#define RL_SRC_ALPHA 0x0302 // GL_SRC_ALPHA
|
||||
#define RL_ONE_MINUS_SRC_ALPHA 0x0303 // GL_ONE_MINUS_SRC_ALPHA
|
||||
#define RL_DST_ALPHA 0x0304 // GL_DST_ALPHA
|
||||
#define RL_ONE_MINUS_DST_ALPHA 0x0305 // GL_ONE_MINUS_DST_ALPHA
|
||||
#define RL_DST_COLOR 0x0306 // GL_DST_COLOR
|
||||
#define RL_ONE_MINUS_DST_COLOR 0x0307 // GL_ONE_MINUS_DST_COLOR
|
||||
#define RL_SRC_ALPHA_SATURATE 0x0308 // GL_SRC_ALPHA_SATURATE
|
||||
#define RL_CONSTANT_COLOR 0x8001 // GL_CONSTANT_COLOR
|
||||
#define RL_ONE_MINUS_CONSTANT_COLOR 0x8002 // GL_ONE_MINUS_CONSTANT_COLOR
|
||||
#define RL_CONSTANT_ALPHA 0x8003 // GL_CONSTANT_ALPHA
|
||||
#define RL_ONE_MINUS_CONSTANT_ALPHA 0x8004 // GL_ONE_MINUS_CONSTANT_ALPHA
|
||||
|
||||
// GL blending functions/equations
|
||||
#define RL_FUNC_ADD 0x8006 // GL_FUNC_ADD
|
||||
#define RL_MIN 0x8007 // GL_MIN
|
||||
#define RL_MAX 0x8008 // GL_MAX
|
||||
#define RL_FUNC_SUBTRACT 0x800A // GL_FUNC_SUBTRACT
|
||||
#define RL_FUNC_REVERSE_SUBTRACT 0x800B // GL_FUNC_REVERSE_SUBTRACT
|
||||
#define RL_BLEND_EQUATION 0x8009 // GL_BLEND_EQUATION
|
||||
#define RL_BLEND_EQUATION_RGB 0x8009 // GL_BLEND_EQUATION_RGB // (Same as BLEND_EQUATION)
|
||||
#define RL_BLEND_EQUATION_ALPHA 0x883D // GL_BLEND_EQUATION_ALPHA
|
||||
#define RL_BLEND_DST_RGB 0x80C8 // GL_BLEND_DST_RGB
|
||||
#define RL_BLEND_SRC_RGB 0x80C9 // GL_BLEND_SRC_RGB
|
||||
#define RL_BLEND_DST_ALPHA 0x80CA // GL_BLEND_DST_ALPHA
|
||||
#define RL_BLEND_SRC_ALPHA 0x80CB // GL_BLEND_SRC_ALPHA
|
||||
#define RL_BLEND_COLOR 0x8005 // GL_BLEND_COLOR
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Types and Structures Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
|
@ -472,18 +504,18 @@ typedef enum {
|
|||
} rlShaderAttributeDataType;
|
||||
|
||||
// Framebuffer attachment type
|
||||
// NOTE: By default up to 8 color channels defined but it can be more
|
||||
// NOTE: By default up to 8 color channels defined, but it can be more
|
||||
typedef enum {
|
||||
RL_ATTACHMENT_COLOR_CHANNEL0 = 0, // Framebuffer attachmment type: color 0
|
||||
RL_ATTACHMENT_COLOR_CHANNEL1, // Framebuffer attachmment type: color 1
|
||||
RL_ATTACHMENT_COLOR_CHANNEL2, // Framebuffer attachmment type: color 2
|
||||
RL_ATTACHMENT_COLOR_CHANNEL3, // Framebuffer attachmment type: color 3
|
||||
RL_ATTACHMENT_COLOR_CHANNEL4, // Framebuffer attachmment type: color 4
|
||||
RL_ATTACHMENT_COLOR_CHANNEL5, // Framebuffer attachmment type: color 5
|
||||
RL_ATTACHMENT_COLOR_CHANNEL6, // Framebuffer attachmment type: color 6
|
||||
RL_ATTACHMENT_COLOR_CHANNEL7, // Framebuffer attachmment type: color 7
|
||||
RL_ATTACHMENT_DEPTH = 100, // Framebuffer attachmment type: depth
|
||||
RL_ATTACHMENT_STENCIL = 200, // Framebuffer attachmment type: stencil
|
||||
RL_ATTACHMENT_COLOR_CHANNEL0 = 0, // Framebuffer attachment type: color 0
|
||||
RL_ATTACHMENT_COLOR_CHANNEL1, // Framebuffer attachment type: color 1
|
||||
RL_ATTACHMENT_COLOR_CHANNEL2, // Framebuffer attachment type: color 2
|
||||
RL_ATTACHMENT_COLOR_CHANNEL3, // Framebuffer attachment type: color 3
|
||||
RL_ATTACHMENT_COLOR_CHANNEL4, // Framebuffer attachment type: color 4
|
||||
RL_ATTACHMENT_COLOR_CHANNEL5, // Framebuffer attachment type: color 5
|
||||
RL_ATTACHMENT_COLOR_CHANNEL6, // Framebuffer attachment type: color 6
|
||||
RL_ATTACHMENT_COLOR_CHANNEL7, // Framebuffer attachment type: color 7
|
||||
RL_ATTACHMENT_DEPTH = 100, // Framebuffer attachment type: depth
|
||||
RL_ATTACHMENT_STENCIL = 200, // Framebuffer attachment type: stencil
|
||||
} rlFramebufferAttachType;
|
||||
|
||||
// Framebuffer texture attachment type
|
||||
|
@ -498,6 +530,12 @@ typedef enum {
|
|||
RL_ATTACHMENT_RENDERBUFFER = 200, // Framebuffer texture attachment type: renderbuffer
|
||||
} rlFramebufferAttachTextureType;
|
||||
|
||||
// Face culling mode
|
||||
typedef enum {
|
||||
RL_CULL_FACE_FRONT = 0,
|
||||
RL_CULL_FACE_BACK
|
||||
} rlCullMode;
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// Functions Declaration - Matrix operations
|
||||
//------------------------------------------------------------------------------------
|
||||
|
@ -508,12 +546,12 @@ extern "C" { // Prevents name mangling of functions
|
|||
|
||||
RLAPI void rlMatrixMode(int mode); // Choose the current matrix to be transformed
|
||||
RLAPI void rlPushMatrix(void); // Push the current matrix to stack
|
||||
RLAPI void rlPopMatrix(void); // Pop lattest inserted matrix from stack
|
||||
RLAPI void rlPopMatrix(void); // Pop latest inserted matrix from stack
|
||||
RLAPI void rlLoadIdentity(void); // Reset current matrix to identity matrix
|
||||
RLAPI void rlTranslatef(float x, float y, float z); // Multiply the current matrix by a translation matrix
|
||||
RLAPI void rlRotatef(float angle, float x, float y, float z); // Multiply the current matrix by a rotation matrix
|
||||
RLAPI void rlScalef(float x, float y, float z); // Multiply the current matrix by a scaling matrix
|
||||
RLAPI void rlMultMatrixf(float *matf); // Multiply the current matrix by another matrix
|
||||
RLAPI void rlMultMatrixf(const float *matf); // Multiply the current matrix by another matrix
|
||||
RLAPI void rlFrustum(double left, double right, double bottom, double top, double znear, double zfar);
|
||||
RLAPI void rlOrtho(double left, double right, double bottom, double top, double znear, double zfar);
|
||||
RLAPI void rlViewport(int x, int y, int width, int height); // Set the viewport area
|
||||
|
@ -559,6 +597,7 @@ RLAPI void rlDisableTexture(void); // Disable texture
|
|||
RLAPI void rlEnableTextureCubemap(unsigned int id); // Enable texture cubemap
|
||||
RLAPI void rlDisableTextureCubemap(void); // Disable texture cubemap
|
||||
RLAPI void rlTextureParameters(unsigned int id, int param, int value); // Set texture parameters (filter, wrap)
|
||||
RLAPI void rlCubemapParameters(unsigned int id, int param, int value); // Set cubemap parameters (filter, wrap)
|
||||
|
||||
// Shader state
|
||||
RLAPI void rlEnableShader(unsigned int id); // Enable shader program
|
||||
|
@ -578,6 +617,7 @@ RLAPI void rlEnableDepthMask(void); // Enable depth write
|
|||
RLAPI void rlDisableDepthMask(void); // Disable depth write
|
||||
RLAPI void rlEnableBackfaceCulling(void); // Enable backface culling
|
||||
RLAPI void rlDisableBackfaceCulling(void); // Disable backface culling
|
||||
RLAPI void rlSetCullFace(int mode); // Set face culling mode
|
||||
RLAPI void rlEnableScissorTest(void); // Enable scissor test
|
||||
RLAPI void rlDisableScissorTest(void); // Disable scissor test
|
||||
RLAPI void rlScissor(int x, int y, int width, int height); // Scissor test
|
||||
|
@ -603,7 +643,7 @@ RLAPI void rlSetBlendFactorsSeparate(int glSrcRGB, int glDstRGB, int glSrcAlpha,
|
|||
//------------------------------------------------------------------------------------
|
||||
// rlgl initialization functions
|
||||
RLAPI void rlglInit(int width, int height); // Initialize rlgl (buffers, shaders, textures, states)
|
||||
RLAPI void rlglClose(void); // De-inititialize rlgl (buffers, shaders, textures)
|
||||
RLAPI void rlglClose(void); // De-initialize rlgl (buffers, shaders, textures)
|
||||
RLAPI void rlLoadExtensions(void *loader); // Load OpenGL extensions (loader function required)
|
||||
RLAPI int rlGetVersion(void); // Get current OpenGL version
|
||||
RLAPI void rlSetFramebufferWidth(int width); // Set current framebuffer width
|
||||
|
@ -677,7 +717,7 @@ RLAPI void rlSetShader(unsigned int id, int *locs);
|
|||
|
||||
// Compute shader management
|
||||
RLAPI unsigned int rlLoadComputeShaderProgram(unsigned int shaderId); // Load compute shader program
|
||||
RLAPI void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ); // Dispatch compute shader (equivalent to *draw* for graphics pilepine)
|
||||
RLAPI void rlComputeShaderDispatch(unsigned int groupX, unsigned int groupY, unsigned int groupZ); // Dispatch compute shader (equivalent to *draw* for graphics pipeline)
|
||||
|
||||
// Shader buffer storage object management (ssbo)
|
||||
RLAPI unsigned int rlLoadShaderBuffer(unsigned int size, const void *data, int usageHint); // Load shader storage buffer object (SSBO)
|
||||
|
@ -689,7 +729,7 @@ RLAPI void rlCopyShaderBuffer(unsigned int destId, unsigned int srcId, unsigned
|
|||
RLAPI unsigned int rlGetShaderBufferSize(unsigned int id); // Get SSBO buffer size
|
||||
|
||||
// Buffer management
|
||||
RLAPI void rlBindImageTexture(unsigned int id, unsigned int index, unsigned int format, int readonly); // Bind image texture
|
||||
RLAPI void rlBindImageTexture(unsigned int id, unsigned int index, int format, bool readonly); // Bind image texture
|
||||
|
||||
// Matrix state management
|
||||
RLAPI Matrix rlGetMatrixModelview(void); // Get internal modelview matrix
|
||||
|
@ -751,10 +791,17 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
|
|||
#endif
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// NOTE: OpenGL ES 2.0 can be enabled on PLATFORM_DESKTOP,
|
||||
// in that case, functions are loaded from a custom glad for OpenGL ES 2.0
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
#define GLAD_GLES2_IMPLEMENTATION
|
||||
#include "external/glad_gles2.h"
|
||||
#else
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
//#include <EGL/egl.h> // EGL library -> not required, platform layer
|
||||
#include <GLES2/gl2.h> // OpenGL ES 2.0 library
|
||||
#include <GLES2/gl2ext.h> // OpenGL ES 2.0 extensions library
|
||||
#endif
|
||||
|
||||
// It seems OpenGL ES 2.0 instancing entry points are not defined on Raspberry Pi
|
||||
// provided headers (despite being defined in official Khronos GLES2 headers)
|
||||
|
@ -846,22 +893,22 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad
|
|||
|
||||
// Default shader vertex attribute names to set location points
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Binded by default to shader location: 0
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: 0
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: 1
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: 2
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: 3
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: 4
|
||||
#endif
|
||||
#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5
|
||||
#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: 5
|
||||
#endif
|
||||
|
||||
#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MVP
|
||||
|
@ -949,7 +996,8 @@ typedef struct rlglData {
|
|||
bool vao; // VAO support (OpenGL ES2 could not support VAO extension) (GL_ARB_vertex_array_object)
|
||||
bool instancing; // Instancing supported (GL_ANGLE_instanced_arrays, GL_EXT_draw_instanced + GL_EXT_instanced_arrays)
|
||||
bool texNPOT; // NPOT textures full support (GL_ARB_texture_non_power_of_two, GL_OES_texture_npot)
|
||||
bool texDepth; // Depth textures supported (GL_ARB_depth_texture, GL_WEBGL_depth_texture, GL_OES_depth_texture)
|
||||
bool texDepth; // Depth textures supported (GL_ARB_depth_texture, GL_OES_depth_texture)
|
||||
bool texDepthWebGL; // Depth textures supported WebGL specific (GL_WEBGL_depth_texture)
|
||||
bool texFloat32; // float textures support (32 bit per channel) (GL_OES_texture_float)
|
||||
bool texCompDXT; // DDS texture compression support (GL_EXT_texture_compression_s3tc, GL_WEBGL_compressed_texture_s3tc, GL_WEBKIT_WEBGL_compressed_texture_s3tc)
|
||||
bool texCompETC1; // ETC1 texture compression support (GL_OES_compressed_ETC1_RGB8_texture, GL_WEBGL_compressed_texture_etc1)
|
||||
|
@ -1041,7 +1089,7 @@ void rlLoadIdentity(void) { glLoadIdentity(); }
|
|||
void rlTranslatef(float x, float y, float z) { glTranslatef(x, y, z); }
|
||||
void rlRotatef(float angle, float x, float y, float z) { glRotatef(angle, x, y, z); }
|
||||
void rlScalef(float x, float y, float z) { glScalef(x, y, z); }
|
||||
void rlMultMatrixf(float *matf) { glMultMatrixf(matf); }
|
||||
void rlMultMatrixf(const float *matf) { glMultMatrixf(matf); }
|
||||
#endif
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// Choose the current matrix to be transformed
|
||||
|
@ -1166,7 +1214,7 @@ void rlScalef(float x, float y, float z)
|
|||
}
|
||||
|
||||
// Multiply the current matrix by another matrix
|
||||
void rlMultMatrixf(float *matf)
|
||||
void rlMultMatrixf(const float *matf)
|
||||
{
|
||||
// Matrix creation from array
|
||||
Matrix mat = { matf[0], matf[4], matf[8], matf[12],
|
||||
|
@ -1578,6 +1626,50 @@ void rlTextureParameters(unsigned int id, int param, int value)
|
|||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
// Set cubemap parameters (wrap mode/filter mode)
|
||||
void rlCubemapParameters(unsigned int id, int param, int value)
|
||||
{
|
||||
#if !defined(GRAPHICS_API_OPENGL_11)
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
|
||||
|
||||
// Reset anisotropy filter, in case it was set
|
||||
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
|
||||
|
||||
switch (param)
|
||||
{
|
||||
case RL_TEXTURE_WRAP_S:
|
||||
case RL_TEXTURE_WRAP_T:
|
||||
{
|
||||
if (value == RL_TEXTURE_WRAP_MIRROR_CLAMP)
|
||||
{
|
||||
if (RLGL.ExtSupported.texMirrorClamp) glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value);
|
||||
else TRACELOG(RL_LOG_WARNING, "GL: Clamp mirror wrap mode not supported (GL_MIRROR_CLAMP_EXT)");
|
||||
}
|
||||
else glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value);
|
||||
|
||||
} break;
|
||||
case RL_TEXTURE_MAG_FILTER:
|
||||
case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_CUBE_MAP, param, value); break;
|
||||
case RL_TEXTURE_FILTER_ANISOTROPIC:
|
||||
{
|
||||
if (value <= RLGL.ExtSupported.maxAnisotropyLevel) glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value);
|
||||
else if (RLGL.ExtSupported.maxAnisotropyLevel > 0.0f)
|
||||
{
|
||||
TRACELOG(RL_LOG_WARNING, "GL: Maximum anisotropic filter level supported is %iX", id, (int)RLGL.ExtSupported.maxAnisotropyLevel);
|
||||
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value);
|
||||
}
|
||||
else TRACELOG(RL_LOG_WARNING, "GL: Anisotropic filtering not supported");
|
||||
} break;
|
||||
#if defined(GRAPHICS_API_OPENGL_33)
|
||||
case RL_TEXTURE_MIPMAP_BIAS_RATIO: glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_LOD_BIAS, value/100.0f);
|
||||
#endif
|
||||
default: break;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Enable shader program
|
||||
void rlEnableShader(unsigned int id)
|
||||
{
|
||||
|
@ -1671,6 +1763,17 @@ void rlEnableBackfaceCulling(void) { glEnable(GL_CULL_FACE); }
|
|||
// Disable backface culling
|
||||
void rlDisableBackfaceCulling(void) { glDisable(GL_CULL_FACE); }
|
||||
|
||||
// Set face culling mode
|
||||
void rlSetCullFace(int mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case RL_CULL_FACE_BACK: glCullFace(GL_BACK); break;
|
||||
case RL_CULL_FACE_FRONT: glCullFace(GL_FRONT); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// Enable scissor test
|
||||
void rlEnableScissorTest(void) { glEnable(GL_SCISSOR_TEST); }
|
||||
|
||||
|
@ -1798,7 +1901,7 @@ void rlCheckErrors()
|
|||
void rlSetBlendMode(int mode)
|
||||
{
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
if (RLGL.State.currentBlendMode != mode || ((mode == RL_BLEND_CUSTOM || mode == RL_BLEND_CUSTOM_SEPARATE) && RLGL.State.glCustomBlendModeModified))
|
||||
if ((RLGL.State.currentBlendMode != mode) || ((mode == RL_BLEND_CUSTOM || mode == RL_BLEND_CUSTOM_SEPARATE) && RLGL.State.glCustomBlendModeModified))
|
||||
{
|
||||
rlDrawRenderBatch(RLGL.currentBatch);
|
||||
|
||||
|
@ -2094,6 +2197,12 @@ void rlLoadExtensions(void *loader)
|
|||
#endif // GRAPHICS_API_OPENGL_33
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_ES2)
|
||||
|
||||
#if defined(PLATFORM_DESKTOP)
|
||||
if (gladLoadGLES2((GLADloadfunc)loader) == 0) TRACELOG(RL_LOG_WARNING, "GLAD: Cannot load OpenGL ES2.0 functions");
|
||||
else TRACELOG(RL_LOG_INFO, "GLAD: OpenGL ES2.0 loaded successfully");
|
||||
#endif
|
||||
|
||||
// Get supported extensions list
|
||||
GLint numExt = 0;
|
||||
const char **extList = RL_MALLOC(512*sizeof(const char *)); // Allocate 512 strings pointers (2 KB)
|
||||
|
@ -2169,11 +2278,12 @@ void rlLoadExtensions(void *loader)
|
|||
if (strcmp(extList[i], (const char *)"GL_OES_texture_float") == 0) RLGL.ExtSupported.texFloat32 = true;
|
||||
|
||||
// Check depth texture support
|
||||
if ((strcmp(extList[i], (const char *)"GL_OES_depth_texture") == 0) ||
|
||||
(strcmp(extList[i], (const char *)"GL_WEBGL_depth_texture") == 0)) RLGL.ExtSupported.texDepth = true;
|
||||
if (strcmp(extList[i], (const char *)"GL_OES_depth_texture") == 0) RLGL.ExtSupported.texDepth = true;
|
||||
if (strcmp(extList[i], (const char *)"GL_WEBGL_depth_texture") == 0) RLGL.ExtSupported.texDepthWebGL = true; // WebGL requires unsized internal format
|
||||
if (RLGL.ExtSupported.texDepthWebGL) RLGL.ExtSupported.texDepth = true;
|
||||
|
||||
if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) RLGL.ExtSupported.maxDepthBits = 24;
|
||||
if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) RLGL.ExtSupported.maxDepthBits = 32;
|
||||
if (strcmp(extList[i], (const char *)"GL_OES_depth24") == 0) RLGL.ExtSupported.maxDepthBits = 24; // Not available on WebGL
|
||||
if (strcmp(extList[i], (const char *)"GL_OES_depth32") == 0) RLGL.ExtSupported.maxDepthBits = 32; // Not available on WebGL
|
||||
|
||||
// Check texture compression support: DXT
|
||||
if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) ||
|
||||
|
@ -2658,7 +2768,7 @@ void rlDrawRenderBatch(rlRenderBatch *batch)
|
|||
|
||||
for (int i = 0, vertexOffset = 0; i < batch->drawCounter; i++)
|
||||
{
|
||||
// Bind current draw call texture, activated as GL_TEXTURE0 and binded to sampler2D texture0 by default
|
||||
// Bind current draw call texture, activated as GL_TEXTURE0 and Bound to sampler2D texture0 by default
|
||||
glBindTexture(GL_TEXTURE_2D, batch->draws[i].textureId);
|
||||
|
||||
if ((batch->draws[i].mode == RL_LINES) || (batch->draws[i].mode == RL_TRIANGLES)) glDrawArrays(batch->draws[i].mode, vertexOffset, batch->draws[i].vertexCount);
|
||||
|
@ -2926,7 +3036,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format,
|
|||
}
|
||||
|
||||
// Load depth texture/renderbuffer (to be attached to fbo)
|
||||
// WARNING: OpenGL ES 2.0 requires GL_OES_depth_texture/WEBGL_depth_texture extensions
|
||||
// WARNING: OpenGL ES 2.0 requires GL_OES_depth_texture and WebGL requires WEBGL_depth_texture extensions
|
||||
unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer)
|
||||
{
|
||||
unsigned int id = 0;
|
||||
|
@ -2940,9 +3050,14 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer)
|
|||
unsigned int glInternalFormat = GL_DEPTH_COMPONENT;
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// WARNING: WebGL platform requires unsized internal format definition (GL_DEPTH_COMPONENT)
|
||||
// while other platforms using OpenGL ES 2.0 require/support sized internal formats depending on the GPU capabilities
|
||||
if (!RLGL.ExtSupported.texDepthWebGL || useRenderBuffer)
|
||||
{
|
||||
if (RLGL.ExtSupported.maxDepthBits == 32) glInternalFormat = GL_DEPTH_COMPONENT32_OES;
|
||||
else if (RLGL.ExtSupported.maxDepthBits == 24) glInternalFormat = GL_DEPTH_COMPONENT24_OES;
|
||||
else glInternalFormat = GL_DEPTH_COMPONENT16;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!useRenderBuffer && RLGL.ExtSupported.texDepth)
|
||||
|
@ -3134,6 +3249,7 @@ void rlUnloadTexture(unsigned int id)
|
|||
// NOTE: Only supports GPU mipmap generation
|
||||
void rlGenTextureMipmaps(unsigned int id, int width, int height, int format, int *mipmaps)
|
||||
{
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
glBindTexture(GL_TEXTURE_2D, id);
|
||||
|
||||
// Check if texture is power-of-two (POT)
|
||||
|
@ -3142,7 +3258,6 @@ void rlGenTextureMipmaps(unsigned int id, int width, int height, int format, int
|
|||
if (((width > 0) && ((width & (width - 1)) == 0)) &&
|
||||
((height > 0) && ((height & (height - 1)) == 0))) texIsPOT = true;
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
if ((texIsPOT) || (RLGL.ExtSupported.texNPOT))
|
||||
{
|
||||
//glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorithm: GL_FASTEST, GL_NICEST, GL_DONT_CARE
|
||||
|
@ -3154,10 +3269,12 @@ void rlGenTextureMipmaps(unsigned int id, int width, int height, int format, int
|
|||
*mipmaps = 1 + (int)floor(log(MAX(width, height))/log(2));
|
||||
TRACELOG(RL_LOG_INFO, "TEXTURE: [ID %i] Mipmaps generated automatically, total: %i", id, *mipmaps);
|
||||
}
|
||||
#endif
|
||||
else TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] Failed to generate mipmaps", id);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
#else
|
||||
TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] GPU mipmap generation not supported", id);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -3358,7 +3475,7 @@ void rlUnloadFramebuffer(unsigned int id)
|
|||
|
||||
unsigned int depthIdU = (unsigned int)depthId;
|
||||
if (depthType == GL_RENDERBUFFER) glDeleteRenderbuffers(1, &depthIdU);
|
||||
else if (depthType == GL_RENDERBUFFER) glDeleteTextures(1, &depthIdU);
|
||||
else if (depthType == GL_TEXTURE) glDeleteTextures(1, &depthIdU);
|
||||
|
||||
// NOTE: If a texture object is deleted while its image is attached to the *currently bound* framebuffer,
|
||||
// the texture image is automatically detached from the currently bound framebuffer.
|
||||
|
@ -3625,12 +3742,14 @@ unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode)
|
|||
// NOTE: We detach shader before deletion to make sure memory is freed
|
||||
if (vertexShaderId != RLGL.State.defaultVShaderId)
|
||||
{
|
||||
glDetachShader(id, vertexShaderId);
|
||||
// WARNING: Shader program linkage could fail and returned id is 0
|
||||
if (id > 0) glDetachShader(id, vertexShaderId);
|
||||
glDeleteShader(vertexShaderId);
|
||||
}
|
||||
if (fragmentShaderId != RLGL.State.defaultFShaderId)
|
||||
{
|
||||
glDetachShader(id, fragmentShaderId);
|
||||
// WARNING: Shader program linkage could fail and returned id is 0
|
||||
if (id > 0) glDetachShader(id, fragmentShaderId);
|
||||
glDeleteShader(fragmentShaderId);
|
||||
}
|
||||
|
||||
|
@ -3738,7 +3857,7 @@ unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId)
|
|||
glAttachShader(program, vShaderId);
|
||||
glAttachShader(program, fShaderId);
|
||||
|
||||
// NOTE: Default attribute shader locations must be binded before linking
|
||||
// NOTE: Default attribute shader locations must be Bound before linking
|
||||
glBindAttribLocation(program, 0, RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION);
|
||||
glBindAttribLocation(program, 1, RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD);
|
||||
glBindAttribLocation(program, 2, RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL);
|
||||
|
@ -4037,7 +4156,7 @@ void rlCopyShaderBuffer(unsigned int destId, unsigned int srcId, unsigned int de
|
|||
}
|
||||
|
||||
// Bind image texture
|
||||
void rlBindImageTexture(unsigned int id, unsigned int index, unsigned int format, int readonly)
|
||||
void rlBindImageTexture(unsigned int id, unsigned int index, int format, bool readonly)
|
||||
{
|
||||
#if defined(GRAPHICS_API_OPENGL_43)
|
||||
unsigned int glInternalFormat = 0, glFormat = 0, glType = 0;
|
||||
|
|
829
raylib/rmodels.c
829
raylib/rmodels.c
File diff suppressed because it is too large
Load diff
|
@ -97,17 +97,6 @@ func DrawCubeWiresV(position Vector3, size Vector3, col color.RGBA) {
|
|||
C.DrawCubeWiresV(*cposition, *csize, *ccolor)
|
||||
}
|
||||
|
||||
// DrawCubeTexture - Draw cube textured
|
||||
func DrawCubeTexture(texture Texture2D, position Vector3, width float32, height float32, length float32, col color.RGBA) {
|
||||
ctexture := texture.cptr()
|
||||
cposition := position.cptr()
|
||||
cwidth := (C.float)(width)
|
||||
cheight := (C.float)(height)
|
||||
clength := (C.float)(length)
|
||||
ccolor := colorCptr(col)
|
||||
C.DrawCubeTexture(*ctexture, *cposition, cwidth, cheight, clength, *ccolor)
|
||||
}
|
||||
|
||||
// DrawSphere - Draw sphere
|
||||
func DrawSphere(centerPos Vector3, radius float32, col color.RGBA) {
|
||||
ccenterPos := centerPos.cptr()
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
*
|
||||
* LICENSE: zlib/libpng
|
||||
*
|
||||
* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||
* will the authors be held liable for any damages arising from the use of this software.
|
||||
|
@ -58,6 +58,7 @@
|
|||
|
||||
#include <math.h> // Required for: sinf(), asinf(), cosf(), acosf(), sqrtf(), fabsf()
|
||||
#include <float.h> // Required for: FLT_EPSILON
|
||||
#include <stdlib.h> // Required for: RL_FREE
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Defines and Macros
|
||||
|
@ -104,7 +105,7 @@ void SetShapesTexture(Texture2D texture, Rectangle source)
|
|||
// Draw a pixel
|
||||
void DrawPixel(int posX, int posY, Color color)
|
||||
{
|
||||
DrawPixelV((Vector2){ posX, posY }, color);
|
||||
DrawPixelV((Vector2){ (float)posX, (float)posY }, color);
|
||||
}
|
||||
|
||||
// Draw a pixel (Vector version)
|
||||
|
@ -155,8 +156,8 @@ void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color colo
|
|||
{
|
||||
rlBegin(RL_LINES);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f(startPosX, startPosY);
|
||||
rlVertex2f(endPosX, endPosY);
|
||||
rlVertex2f((float)startPosX, (float)startPosY);
|
||||
rlVertex2f((float)endPosX, (float)endPosY);
|
||||
rlEnd();
|
||||
}
|
||||
|
||||
|
@ -197,6 +198,8 @@ void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color)
|
|||
Vector2 previous = startPos;
|
||||
Vector2 current = { 0 };
|
||||
|
||||
Vector2 points[2*BEZIER_LINE_DIVISIONS + 2] = { 0 };
|
||||
|
||||
for (int i = 1; i <= BEZIER_LINE_DIVISIONS; i++)
|
||||
{
|
||||
// Cubic easing in-out
|
||||
|
@ -204,12 +207,27 @@ void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color)
|
|||
current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)BEZIER_LINE_DIVISIONS);
|
||||
current.x = previous.x + (endPos.x - startPos.x)/ (float)BEZIER_LINE_DIVISIONS;
|
||||
|
||||
// TODO: Avoid drawing the line by pieces, it generates gaps for big thicks,
|
||||
// Custom "triangle-strip" implementation should be used, check DrawTriangleStrip() for reference
|
||||
DrawLineEx(previous, current, thick, color);
|
||||
float dy = current.y-previous.y;
|
||||
float dx = current.x-previous.x;
|
||||
float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
|
||||
|
||||
if (i==1)
|
||||
{
|
||||
points[0].x = previous.x+dy*size;
|
||||
points[0].y = previous.y-dx*size;
|
||||
points[1].x = previous.x-dy*size;
|
||||
points[1].y = previous.y+dx*size;
|
||||
}
|
||||
|
||||
points[2*i+1].x = current.x-dy*size;
|
||||
points[2*i+1].y = current.y+dx*size;
|
||||
points[2*i].x = current.x+dy*size;
|
||||
points[2*i].y = current.y-dx*size;
|
||||
|
||||
previous = current;
|
||||
}
|
||||
|
||||
DrawTriangleStrip(points, 2*BEZIER_LINE_DIVISIONS+2, color);
|
||||
}
|
||||
|
||||
// Draw line using quadratic bezier curves with a control point
|
||||
|
@ -221,6 +239,8 @@ void DrawLineBezierQuad(Vector2 startPos, Vector2 endPos, Vector2 controlPos, fl
|
|||
Vector2 current = { 0 };
|
||||
float t = 0.0f;
|
||||
|
||||
Vector2 points[2*BEZIER_LINE_DIVISIONS + 2] = { 0 };
|
||||
|
||||
for (int i = 0; i <= BEZIER_LINE_DIVISIONS; i++)
|
||||
{
|
||||
t = step*i;
|
||||
|
@ -232,12 +252,27 @@ void DrawLineBezierQuad(Vector2 startPos, Vector2 endPos, Vector2 controlPos, fl
|
|||
current.y = a*startPos.y + b*controlPos.y + c*endPos.y;
|
||||
current.x = a*startPos.x + b*controlPos.x + c*endPos.x;
|
||||
|
||||
// TODO: Avoid drawing the line by pieces, it generates gaps for big thicks,
|
||||
// Custom "triangle-strip" implementation should be used, check DrawTriangleStrip() for reference
|
||||
DrawLineEx(previous, current, thick, color);
|
||||
float dy = current.y-previous.y;
|
||||
float dx = current.x-previous.x;
|
||||
float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
|
||||
|
||||
if (i==1)
|
||||
{
|
||||
points[0].x = previous.x+dy*size;
|
||||
points[0].y = previous.y-dx*size;
|
||||
points[1].x = previous.x-dy*size;
|
||||
points[1].y = previous.y+dx*size;
|
||||
}
|
||||
|
||||
points[2*i+1].x = current.x-dy*size;
|
||||
points[2*i+1].y = current.y+dx*size;
|
||||
points[2*i].x = current.x+dy*size;
|
||||
points[2*i].y = current.y-dx*size;
|
||||
|
||||
previous = current;
|
||||
}
|
||||
|
||||
DrawTriangleStrip(points, 2*BEZIER_LINE_DIVISIONS+2, color);
|
||||
}
|
||||
|
||||
// Draw line using cubic bezier curves with 2 control points
|
||||
|
@ -249,6 +284,8 @@ void DrawLineBezierCubic(Vector2 startPos, Vector2 endPos, Vector2 startControlP
|
|||
Vector2 current = { 0 };
|
||||
float t = 0.0f;
|
||||
|
||||
Vector2 points[2*BEZIER_LINE_DIVISIONS + 2] = { 0 };
|
||||
|
||||
for (int i = 0; i <= BEZIER_LINE_DIVISIONS; i++)
|
||||
{
|
||||
t = step*i;
|
||||
|
@ -260,12 +297,27 @@ void DrawLineBezierCubic(Vector2 startPos, Vector2 endPos, Vector2 startControlP
|
|||
current.y = a*startPos.y + b*startControlPos.y + c*endControlPos.y + d*endPos.y;
|
||||
current.x = a*startPos.x + b*startControlPos.x + c*endControlPos.x + d*endPos.x;
|
||||
|
||||
// TODO: Avoid drawing the line by pieces, it generates gaps for big thicks,
|
||||
// Custom "triangle-strip" implementation should be used, check DrawTriangleStrip() for reference
|
||||
DrawLineEx(previous, current, thick, color);
|
||||
float dy = current.y-previous.y;
|
||||
float dx = current.x-previous.x;
|
||||
float size = 0.5f*thick/sqrtf(dx*dx+dy*dy);
|
||||
|
||||
if (i==1)
|
||||
{
|
||||
points[0].x = previous.x+dy*size;
|
||||
points[0].y = previous.y-dx*size;
|
||||
points[1].x = previous.x-dy*size;
|
||||
points[1].y = previous.y+dx*size;
|
||||
}
|
||||
|
||||
points[2*i+1].x = current.x-dy*size;
|
||||
points[2*i+1].y = current.y+dx*size;
|
||||
points[2*i].x = current.x+dy*size;
|
||||
points[2*i].y = current.y-dx*size;
|
||||
|
||||
previous = current;
|
||||
}
|
||||
|
||||
DrawTriangleStrip(points, 2*BEZIER_LINE_DIVISIONS+2, color);
|
||||
}
|
||||
|
||||
// Draw lines sequence
|
||||
|
@ -926,7 +978,7 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
|
|||
rlSetTexture(texShapes.id);
|
||||
|
||||
rlBegin(RL_QUADS);
|
||||
// Draw all of the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner
|
||||
// Draw all the 4 corners: [1] Upper Left Corner, [3] Upper Right Corner, [5] Lower Right Corner, [7] Lower Left Corner
|
||||
for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
|
||||
{
|
||||
float angle = angles[k];
|
||||
|
@ -1155,7 +1207,7 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, flo
|
|||
|
||||
rlBegin(RL_QUADS);
|
||||
|
||||
// Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
|
||||
// Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
|
||||
for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
|
||||
{
|
||||
float angle = angles[k];
|
||||
|
@ -1290,7 +1342,7 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, flo
|
|||
// Use LINES to draw the outline
|
||||
rlBegin(RL_LINES);
|
||||
|
||||
// Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
|
||||
// Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner
|
||||
for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop
|
||||
{
|
||||
float angle = angles[k];
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
*
|
||||
* LICENSE: zlib/libpng
|
||||
*
|
||||
* Copyright (c) 2013-2022 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||
* will the authors be held liable for any damages arising from the use of this software.
|
||||
|
@ -65,7 +65,7 @@
|
|||
#include <stdio.h> // Required for: vsprintf()
|
||||
#include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()]
|
||||
#include <stdarg.h> // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()]
|
||||
#include <ctype.h> // Requried for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
|
||||
#include <ctype.h> // Required for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
|
||||
|
||||
#if defined(SUPPORT_FILEFORMAT_TTF)
|
||||
#define STB_RECT_PACK_IMPLEMENTATION
|
||||
|
@ -199,11 +199,11 @@ extern void LoadFontDefault(void)
|
|||
// Re-construct image from defaultFontData and generate OpenGL texture
|
||||
//----------------------------------------------------------------------
|
||||
Image imFont = {
|
||||
.data = calloc(128*128, 2), // 2 bytes per pixel (gray + alpha)
|
||||
.data = RL_CALLOC(128*128, 2), // 2 bytes per pixel (gray + alpha)
|
||||
.width = 128,
|
||||
.height = 128,
|
||||
.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA,
|
||||
.mipmaps = 1
|
||||
.mipmaps = 1,
|
||||
.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA
|
||||
};
|
||||
|
||||
// Fill image.data with defaultFontData (convert from bit to pixel!)
|
||||
|
@ -336,7 +336,7 @@ Font LoadFont(const char *fileName)
|
|||
}
|
||||
else
|
||||
{
|
||||
SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default we set point filter (best performance)
|
||||
SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)
|
||||
TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", FONT_TTF_DEFAULT_SIZE, FONT_TTF_DEFAULT_NUMCHARS);
|
||||
}
|
||||
|
||||
|
@ -454,8 +454,8 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
|
|||
.data = pixels,
|
||||
.width = image.width,
|
||||
.height = image.height,
|
||||
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8,
|
||||
.mipmaps = 1
|
||||
.mipmaps = 1,
|
||||
.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
|
||||
};
|
||||
|
||||
// Set font with all data parsed from image
|
||||
|
@ -535,6 +535,19 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
|
|||
return font;
|
||||
}
|
||||
|
||||
// Check if a font is ready
|
||||
bool IsFontReady(Font font)
|
||||
{
|
||||
return ((font.texture.id > 0) && // Validate OpenGL id fot font texture atlas
|
||||
(font.baseSize > 0) && // Validate font size
|
||||
(font.glyphCount > 0) && // Validate font contains some glyph
|
||||
(font.recs != NULL) && // Validate font recs defining glyphs on texture atlas
|
||||
(font.glyphs != NULL)); // Validate glyph data is loaded
|
||||
|
||||
// NOTE: Further validations could be done to verify if recs count and glyphs count
|
||||
// match glyphCount and to verify that data contained is valid (glyphs values, metrics...)
|
||||
}
|
||||
|
||||
// Load font data for further use
|
||||
// NOTE: Requires TTF font memory data and can generate SDF data
|
||||
GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSize, int *fontChars, int glyphCount, int type)
|
||||
|
@ -578,7 +591,7 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
|
|||
glyphCount = (glyphCount > 0)? glyphCount : 95;
|
||||
|
||||
// Fill fontChars in case not provided externally
|
||||
// NOTE: By default we fill glyphCount consecutevely, starting at 32 (Space)
|
||||
// NOTE: By default we fill glyphCount consecutively, starting at 32 (Space)
|
||||
|
||||
if (fontChars == NULL)
|
||||
{
|
||||
|
@ -620,11 +633,11 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
|
|||
if (ch == 32)
|
||||
{
|
||||
Image imSpace = {
|
||||
.data = calloc(chars[i].advanceX*fontSize, 2),
|
||||
.data = RL_CALLOC(chars[i].advanceX*fontSize, 2),
|
||||
.width = chars[i].advanceX,
|
||||
.height = fontSize,
|
||||
.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE,
|
||||
.mipmaps = 1
|
||||
.mipmaps = 1,
|
||||
.format = PIXELFORMAT_UNCOMPRESSED_GRAYSCALE
|
||||
};
|
||||
|
||||
chars[i].image = imSpace;
|
||||
|
@ -641,7 +654,7 @@ GlyphInfo *LoadFontData(const unsigned char *fileData, int dataSize, int fontSiz
|
|||
}
|
||||
}
|
||||
|
||||
// Get bounding box for character (may be offset to account for chars that dip above or below the line)
|
||||
// Get bounding box for character (maybe offset to account for chars that dip above or below the line)
|
||||
/*
|
||||
int chX1, chY1, chX2, chY2;
|
||||
stbtt_GetCodepointBitmapBox(&fontInfo, ch, scaleFactor, scaleFactor, &chX1, &chY1, &chX2, &chY2);
|
||||
|
@ -669,7 +682,7 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int glyphC
|
|||
|
||||
if (chars == NULL)
|
||||
{
|
||||
TraceLog(LOG_WARNING, "FONT: Provided chars info not valid, returning empty image atlas");
|
||||
TRACELOG(LOG_WARNING, "FONT: Provided chars info not valid, returning empty image atlas");
|
||||
return atlas;
|
||||
}
|
||||
|
||||
|
@ -771,7 +784,7 @@ Image GenImageFontAtlas(const GlyphInfo *chars, Rectangle **charRecs, int glyphC
|
|||
|
||||
for (int i = 0; i < glyphCount; i++)
|
||||
{
|
||||
// It return char rectangles in atlas
|
||||
// It returns char rectangles in atlas
|
||||
recs[i].x = rects[i].x + (float)padding;
|
||||
recs[i].y = rects[i].y + (float)padding;
|
||||
recs[i].width = (float)chars[i].image.width;
|
||||
|
@ -867,7 +880,7 @@ bool ExportFontAsCode(Font font, const char *fileName)
|
|||
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, "// Copyright (c) 2018-2023 Ramon Santamaria (@raysan5) //\n");
|
||||
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||
byteCount += sprintf(txtData + byteCount, "// ---------------------------------------------------------------------------------- //\n");
|
||||
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||
|
@ -896,7 +909,7 @@ bool ExportFontAsCode(Font font, const char *fileName)
|
|||
|
||||
// Compress font image data
|
||||
int compDataSize = 0;
|
||||
unsigned char *compData = CompressData(image.data, imageDataSize, &compDataSize);
|
||||
unsigned char *compData = CompressData((const unsigned char *)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);
|
||||
|
@ -1034,7 +1047,7 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
|
|||
|
||||
int size = TextLength(text); // Total size in bytes of the text, scanned by codepoints in loop
|
||||
|
||||
int textOffsetY = 0; // Offset between lines (on line break '\n')
|
||||
int textOffsetY = 0; // Offset between lines (on linebreak '\n')
|
||||
float textOffsetX = 0.0f; // Offset X to next character to draw
|
||||
|
||||
float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor
|
||||
|
@ -1047,7 +1060,7 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
|
|||
int index = GetGlyphIndex(font, codepoint);
|
||||
|
||||
// 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 the bad bytes using the '?' symbol moving one byte
|
||||
if (codepoint == 0x3f) codepointByteCount = 1;
|
||||
|
||||
if (codepoint == '\n')
|
||||
|
@ -1113,7 +1126,7 @@ void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSiz
|
|||
// 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')
|
||||
int textOffsetY = 0; // Offset between lines (on linebreak '\n')
|
||||
float textOffsetX = 0.0f; // Offset X to next character to draw
|
||||
|
||||
float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor
|
||||
|
@ -1189,7 +1202,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
|
|||
index = GetGlyphIndex(font, letter);
|
||||
|
||||
// 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 so to not skip any we set next = 1
|
||||
// but we need to draw all the bad bytes using the '?' symbol so to not skip any we set next = 1
|
||||
if (letter == 0x3f) next = 1;
|
||||
i += next - 1;
|
||||
|
||||
|
@ -1333,7 +1346,7 @@ int TextCopy(char *dst, const char *src)
|
|||
{
|
||||
int bytes = 0;
|
||||
|
||||
if (dst != NULL)
|
||||
if ((src != NULL) && (dst != NULL))
|
||||
{
|
||||
while (*src != '\0')
|
||||
{
|
||||
|
@ -1404,7 +1417,7 @@ char *TextReplace(char *text, const char *replace, const char *by)
|
|||
char *insertPoint = NULL; // Next insert point
|
||||
char *temp = NULL; // Temp pointer
|
||||
int replaceLen = 0; // Replace string length of (the string to remove)
|
||||
int byLen = 0; // Replacement length (the string to replace replace by)
|
||||
int byLen = 0; // Replacement length (the string to replace by)
|
||||
int lastReplacePos = 0; // Distance between replace and end of last replace
|
||||
int count = 0; // Number of replacements
|
||||
|
||||
|
@ -1562,6 +1575,8 @@ const char *TextToUpper(const char *text)
|
|||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
|
||||
|
||||
if (text != NULL)
|
||||
{
|
||||
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
|
||||
{
|
||||
if (text[i] != '\0')
|
||||
|
@ -1574,6 +1589,7 @@ const char *TextToUpper(const char *text)
|
|||
}
|
||||
else { buffer[i] = '\0'; break; }
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
@ -1585,6 +1601,8 @@ const char *TextToLower(const char *text)
|
|||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
|
||||
|
||||
if (text != NULL)
|
||||
{
|
||||
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
|
||||
{
|
||||
if (text[i] != '\0')
|
||||
|
@ -1594,6 +1612,7 @@ const char *TextToLower(const char *text)
|
|||
}
|
||||
else { buffer[i] = '\0'; break; }
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
@ -1605,6 +1624,8 @@ const char *TextToPascal(const char *text)
|
|||
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
|
||||
|
||||
if (text != NULL)
|
||||
{
|
||||
buffer[0] = (char)toupper(text[0]);
|
||||
|
||||
for (int i = 1, j = 1; i < MAX_TEXT_BUFFER_LENGTH; i++, j++)
|
||||
|
@ -1620,6 +1641,7 @@ const char *TextToPascal(const char *text)
|
|||
}
|
||||
else { buffer[i] = '\0'; break; }
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
@ -1665,7 +1687,7 @@ int *LoadCodepoints(const char *text, int *count)
|
|||
int codepointCount = 0;
|
||||
|
||||
// Allocate a big enough buffer to store as many codepoints as text bytes
|
||||
int *codepoints = RL_CALLOC(textLength, sizeof(int));
|
||||
int *codepoints = (int *)RL_CALLOC(textLength, sizeof(int));
|
||||
|
||||
for (int i = 0; i < textLength; codepointCount++)
|
||||
{
|
||||
|
@ -1674,7 +1696,7 @@ int *LoadCodepoints(const char *text, int *count)
|
|||
}
|
||||
|
||||
// Re-allocate buffer to the actual number of codepoints loaded
|
||||
void *temp = RL_REALLOC(codepoints, codepointCount*sizeof(int));
|
||||
int *temp = (int *)RL_REALLOC(codepoints, codepointCount*sizeof(int));
|
||||
if (temp != NULL) codepoints = temp;
|
||||
|
||||
*count = codepointCount;
|
||||
|
@ -1750,7 +1772,7 @@ const char *CodepointToUTF8(int codepoint, int *utf8Size)
|
|||
#endif // SUPPORT_TEXT_MANIPULATION
|
||||
|
||||
// Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found
|
||||
// When a invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
|
||||
// When an invalid UTF-8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
|
||||
// Total number of bytes processed are returned as a parameter
|
||||
// NOTE: The standard says U+FFFD should be returned in case of errors
|
||||
// but that character is not supported by the default font in raylib
|
||||
|
@ -1992,7 +2014,7 @@ static Font LoadBMFont(const char *fileName)
|
|||
if (lastSlash != NULL)
|
||||
{
|
||||
// NOTE: We need some extra space to avoid memory corruption on next allocations!
|
||||
imPath = RL_CALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(imFileName) + 4, 1);
|
||||
imPath = (char *)RL_CALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(imFileName) + 4, 1);
|
||||
memcpy(imPath, fileName, TextLength(fileName) - TextLength(lastSlash) + 1);
|
||||
memcpy(imPath + TextLength(fileName) - TextLength(lastSlash) + 1, imFileName, TextLength(imFileName));
|
||||
}
|
||||
|
@ -2006,11 +2028,11 @@ static Font LoadBMFont(const char *fileName)
|
|||
{
|
||||
// Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
|
||||
Image imFontAlpha = {
|
||||
.data = calloc(imFont.width*imFont.height, 2),
|
||||
.data = RL_CALLOC(imFont.width*imFont.height, 2),
|
||||
.width = imFont.width,
|
||||
.height = imFont.height,
|
||||
.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA,
|
||||
.mipmaps = 1
|
||||
.mipmaps = 1,
|
||||
.format = PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA
|
||||
};
|
||||
|
||||
for (int p = 0, i = 0; p < (imFont.width*imFont.height*2); p += 2, i++)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -686,28 +686,6 @@ func DrawTextureRec(texture Texture2D, sourceRec Rectangle, position Vector2, ti
|
|||
C.DrawTextureRec(*ctexture, *csourceRec, *cposition, *ctint)
|
||||
}
|
||||
|
||||
// DrawTextureQuad - Draw texture quad with tiling and offset parameters
|
||||
func DrawTextureQuad(texture Texture2D, tiling, offset Vector2, rectangle Rectangle, tint color.RGBA) {
|
||||
ctexture := texture.cptr()
|
||||
ctiling := tiling.cptr()
|
||||
coffset := offset.cptr()
|
||||
crectangle := rectangle.cptr()
|
||||
ctint := colorCptr(tint)
|
||||
C.DrawTextureQuad(*ctexture, *ctiling, *coffset, *crectangle, *ctint)
|
||||
}
|
||||
|
||||
// DrawTextureTiled - Draw part of a texture (defined by a rectangle) with rotation and scale tiled into dest
|
||||
func DrawTextureTiled(texture Texture2D, sourceRec, destRec Rectangle, origin Vector2, rotation float32, scale float32, tint color.RGBA) {
|
||||
ctexture := texture.cptr()
|
||||
csourceRec := sourceRec.cptr()
|
||||
cdestRec := destRec.cptr()
|
||||
corigin := origin.cptr()
|
||||
crotation := (C.float)(rotation)
|
||||
cscale := (C.float)(scale)
|
||||
ctint := colorCptr(tint)
|
||||
C.DrawTextureTiled(*ctexture, *csourceRec, *cdestRec, *corigin, crotation, cscale, *ctint)
|
||||
}
|
||||
|
||||
// DrawTexturePro - Draw a part of a texture defined by a rectangle with 'pro' parameters
|
||||
func DrawTexturePro(texture Texture2D, sourceRec, destRec Rectangle, origin Vector2, rotation float32, tint color.RGBA) {
|
||||
ctexture := texture.cptr()
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*
|
||||
* LICENSE: zlib/libpng
|
||||
*
|
||||
* Copyright (c) 2014-2022 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||
* will the authors be held liable for any damages arising from the use of this software.
|
||||
|
@ -54,7 +54,7 @@
|
|||
// Defines and Macros
|
||||
//----------------------------------------------------------------------------------
|
||||
#ifndef MAX_TRACELOG_MSG_LENGTH
|
||||
#define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message
|
||||
#define MAX_TRACELOG_MSG_LENGTH 256 // Max length of one trace-log message
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
@ -63,10 +63,10 @@
|
|||
static int logTypeLevel = LOG_INFO; // Minimum log type level
|
||||
|
||||
static TraceLogCallback traceLog = NULL; // TraceLog callback function pointer
|
||||
static LoadFileDataCallback loadFileData = NULL; // LoadFileData callback funtion pointer
|
||||
static SaveFileDataCallback saveFileData = NULL; // SaveFileText callback funtion pointer
|
||||
static LoadFileTextCallback loadFileText = NULL; // LoadFileText callback funtion pointer
|
||||
static SaveFileTextCallback saveFileText = NULL; // SaveFileText callback funtion pointer
|
||||
static LoadFileDataCallback loadFileData = NULL; // LoadFileData callback function pointer
|
||||
static SaveFileDataCallback saveFileData = NULL; // SaveFileText callback function pointer
|
||||
static LoadFileTextCallback loadFileText = NULL; // LoadFileText callback function pointer
|
||||
static SaveFileTextCallback saveFileText = NULL; // SaveFileText callback function pointer
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Functions to set internal callbacks
|
||||
|
@ -145,7 +145,8 @@ void TraceLog(int logType, const char *text, ...)
|
|||
default: break;
|
||||
}
|
||||
|
||||
strcat(buffer, text);
|
||||
unsigned int textSize = strlen(text);
|
||||
memcpy(buffer + strlen(buffer), text, (textSize < (MAX_TRACELOG_MSG_LENGTH - 12))? textSize : (MAX_TRACELOG_MSG_LENGTH - 12));
|
||||
strcat(buffer, "\n");
|
||||
vprintf(buffer, args);
|
||||
fflush(stdout);
|
||||
|
@ -270,7 +271,7 @@ bool SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite)
|
|||
}
|
||||
|
||||
// Export data to code (.h), returns true on success
|
||||
bool ExportDataAsCode(const char *data, unsigned int size, const char *fileName)
|
||||
bool ExportDataAsCode(const unsigned char *data, unsigned int size, const char *fileName)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
|
@ -290,7 +291,7 @@ bool ExportDataAsCode(const char *data, unsigned int size, const char *fileName)
|
|||
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, "// Copyright (c) 2022-2023 Ramon Santamaria (@raysan5) //\n");
|
||||
byteCount += sprintf(txtData + byteCount, "// //\n");
|
||||
byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n");
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* LICENSE: zlib/libpng
|
||||
*
|
||||
* Copyright (c) 2014-2022 Ramon Santamaria (@raysan5)
|
||||
* Copyright (c) 2014-2023 Ramon Santamaria (@raysan5)
|
||||
*
|
||||
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||
* will the authors be held liable for any damages arising from the use of this software.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue