update raylib and deps
This commit is contained in:
parent
fd64d4172a
commit
3fcffd9168
31 changed files with 43817 additions and 12586 deletions
|
@ -1,8 +0,0 @@
|
||||||
#define NUM_RESOURCES 6
|
|
||||||
|
|
||||||
#define RES_coin.wav 0x00000000 // Embedded as WAVE
|
|
||||||
#define RES_raylib_logo.gif 0x00000001 // Embedded as IMAGE
|
|
||||||
#define RES_raylib_logo.jpg 0x00000002 // Embedded as IMAGE
|
|
||||||
#define RES_raylib_logo.png 0x00000003 // Embedded as IMAGE
|
|
||||||
#define RES_raylib_logo.tga 0x00000004 // Embedded as IMAGE
|
|
||||||
#define RES_tanatana.ogg 0x00000005 // Embedded as VORBIS
|
|
Binary file not shown.
|
@ -1,96 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
//"bytes"
|
|
||||||
|
|
||||||
"github.com/gen2brain/raylib-go/raylib"
|
|
||||||
"github.com/gen2brain/raylib-go/rres"
|
|
||||||
)
|
|
||||||
|
|
||||||
const numTextures = 4
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
screenWidth := int32(800)
|
|
||||||
screenHeight := int32(450)
|
|
||||||
|
|
||||||
rl.InitWindow(screenWidth, screenHeight, "raylib [core] example - resources loading")
|
|
||||||
|
|
||||||
rl.InitAudioDevice()
|
|
||||||
|
|
||||||
// OpenAsset() will also work on Android (reads files from assets/)
|
|
||||||
reader, err := rl.OpenAsset("data.rres")
|
|
||||||
if err != nil {
|
|
||||||
rl.TraceLog(rl.LogWarning, "[%s] rRES raylib resource file could not be opened: %v", "data.rres", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer reader.Close()
|
|
||||||
|
|
||||||
// bindata
|
|
||||||
//b := MustAsset("data.rres")
|
|
||||||
//reader := bytes.NewReader(b)
|
|
||||||
|
|
||||||
//res := rres.LoadResource(reader, 0, []byte("passwordpassword"))
|
|
||||||
//wav := rl.LoadWaveEx(res.Data, int32(res.Param1), int32(res.Param2), int32(res.Param3), int32(res.Param4))
|
|
||||||
//snd := rl.LoadSoundFromWave(wav)
|
|
||||||
//rl.UnloadWave(wav)
|
|
||||||
|
|
||||||
textures := make([]rl.Texture2D, numTextures)
|
|
||||||
for i := 0; i < numTextures; i++ {
|
|
||||||
r := rres.LoadResource(reader, i+1, []byte("passwordpassword"))
|
|
||||||
image := rl.LoadImagePro(r.Data, int32(r.Param1), int32(r.Param2), rl.PixelFormat(r.Param3))
|
|
||||||
textures[i] = rl.LoadTextureFromImage(image)
|
|
||||||
rl.UnloadImage(image)
|
|
||||||
}
|
|
||||||
|
|
||||||
currentTexture := 0
|
|
||||||
|
|
||||||
rl.SetTargetFPS(60)
|
|
||||||
|
|
||||||
for !rl.WindowShouldClose() {
|
|
||||||
if rl.IsKeyPressed(rl.KeySpace) {
|
|
||||||
//rl.PlaySound(snd)
|
|
||||||
}
|
|
||||||
|
|
||||||
if rl.IsMouseButtonPressed(rl.MouseLeftButton) {
|
|
||||||
currentTexture = (currentTexture + 1) % numTextures // Cycle between the textures
|
|
||||||
}
|
|
||||||
|
|
||||||
rl.BeginDrawing()
|
|
||||||
|
|
||||||
rl.ClearBackground(rl.RayWhite)
|
|
||||||
|
|
||||||
rl.DrawTexture(textures[currentTexture], screenWidth/2-textures[currentTexture].Width/2, screenHeight/2-textures[currentTexture].Height/2, rl.RayWhite)
|
|
||||||
|
|
||||||
rl.DrawText("MOUSE LEFT BUTTON to CYCLE TEXTURES", 40, 410, 10, rl.Gray)
|
|
||||||
rl.DrawText("SPACE to PLAY SOUND", 40, 430, 10, rl.Gray)
|
|
||||||
|
|
||||||
switch currentTexture {
|
|
||||||
case 0:
|
|
||||||
rl.DrawText("GIF", 272, 70, 20, rl.Gray)
|
|
||||||
break
|
|
||||||
case 1:
|
|
||||||
rl.DrawText("JPEG", 272, 70, 20, rl.Gray)
|
|
||||||
break
|
|
||||||
case 2:
|
|
||||||
rl.DrawText("PNG", 272, 70, 20, rl.Gray)
|
|
||||||
break
|
|
||||||
case 3:
|
|
||||||
rl.DrawText("TGA", 272, 70, 20, rl.Gray)
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
rl.EndDrawing()
|
|
||||||
}
|
|
||||||
|
|
||||||
//rl.UnloadSound(snd)
|
|
||||||
|
|
||||||
for _, t := range textures {
|
|
||||||
rl.UnloadTexture(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
rl.CloseAudioDevice()
|
|
||||||
|
|
||||||
rl.CloseWindow()
|
|
||||||
}
|
|
|
@ -135,6 +135,9 @@ void SetCameraMoveControls(int frontKey, int backKey,
|
||||||
|
|
||||||
#include <math.h> // Required for: sinf(), cosf(), sqrtf()
|
#include <math.h> // Required for: sinf(), cosf(), sqrtf()
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Defines and Macros
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
#ifndef PI
|
#ifndef PI
|
||||||
#define PI 3.14159265358979323846
|
#define PI 3.14159265358979323846
|
||||||
#endif
|
#endif
|
||||||
|
@ -145,9 +148,6 @@ void SetCameraMoveControls(int frontKey, int backKey,
|
||||||
#define RAD2DEG (180.0f/PI)
|
#define RAD2DEG (180.0f/PI)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
// Defines and Macros
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
// Camera mouse movement sensitivity
|
// Camera mouse movement sensitivity
|
||||||
#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f
|
#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f
|
||||||
#define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f
|
#define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f
|
||||||
|
@ -170,7 +170,7 @@ void SetCameraMoveControls(int frontKey, int backKey,
|
||||||
#define CAMERA_FIRST_PERSON_MIN_CLAMP 89.0f
|
#define CAMERA_FIRST_PERSON_MIN_CLAMP 89.0f
|
||||||
#define CAMERA_FIRST_PERSON_MAX_CLAMP -89.0f
|
#define CAMERA_FIRST_PERSON_MAX_CLAMP -89.0f
|
||||||
|
|
||||||
#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 5.0f
|
#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 8.0f
|
||||||
#define CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f
|
#define CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f
|
||||||
#define CAMERA_FIRST_PERSON_WAVING_DIVIDER 200.0f
|
#define CAMERA_FIRST_PERSON_WAVING_DIVIDER 200.0f
|
||||||
|
|
||||||
|
@ -197,17 +197,18 @@ typedef enum {
|
||||||
MOVE_DOWN
|
MOVE_DOWN
|
||||||
} CameraMove;
|
} CameraMove;
|
||||||
|
|
||||||
// Camera global state context data
|
// Camera global state context data [56 bytes]
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int mode; // Current camera mode
|
unsigned int mode; // Current camera mode
|
||||||
float targetDistance; // Camera distance from position to target
|
float targetDistance; // Camera distance from position to target
|
||||||
float playerEyesPosition; // Default player eyes position from ground (in meters)
|
float playerEyesPosition; // Player eyes position from ground (in meters)
|
||||||
Vector2 angle; // Camera angle in plane XZ
|
Vector2 angle; // Camera angle in plane XZ
|
||||||
|
|
||||||
int moveControl[6];
|
// Camera movement control keys
|
||||||
int smoothZoomControl; // raylib: KEY_LEFT_CONTROL
|
int moveControl[6]; // Move controls (CAMERA_FIRST_PERSON)
|
||||||
int altControl; // raylib: KEY_LEFT_ALT
|
int smoothZoomControl; // Smooth zoom control key
|
||||||
int panControl; // raylib: MOUSE_MIDDLE_BUTTON
|
int altControl; // Alternative control key
|
||||||
|
int panControl; // Pan view control key
|
||||||
} CameraData;
|
} CameraData;
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -219,9 +220,9 @@ static CameraData CAMERA = { // Global CAMERA state context
|
||||||
.playerEyesPosition = 1.85f,
|
.playerEyesPosition = 1.85f,
|
||||||
.angle = { 0 },
|
.angle = { 0 },
|
||||||
.moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' },
|
.moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' },
|
||||||
.smoothZoomControl = 341,
|
.smoothZoomControl = 341, // raylib: KEY_LEFT_CONTROL
|
||||||
.altControl = 342,
|
.altControl = 342, // raylib: KEY_LEFT_ALT
|
||||||
.panControl = 2
|
.panControl = 2 // raylib: MOUSE_MIDDLE_BUTTON
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -253,13 +254,13 @@ void SetCameraMode(Camera camera, int mode)
|
||||||
float dy = v2.y - v1.y;
|
float dy = v2.y - v1.y;
|
||||||
float dz = v2.z - v1.z;
|
float dz = v2.z - v1.z;
|
||||||
|
|
||||||
CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz);
|
CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance to target
|
||||||
|
|
||||||
// Camera angle calculation
|
// Camera angle calculation
|
||||||
CAMERA.angle.x = atan2f(dx, dz); // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
|
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.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;
|
CAMERA.playerEyesPosition = camera.position.y; // Init player eyes position to camera Y position
|
||||||
|
|
||||||
// Lock cursor for first person and third person cameras
|
// Lock cursor for first person and third person cameras
|
||||||
if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor();
|
if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor();
|
||||||
|
@ -287,6 +288,7 @@ void UpdateCamera(Camera *camera)
|
||||||
int mouseWheelMove = GetMouseWheelMove();
|
int mouseWheelMove = GetMouseWheelMove();
|
||||||
|
|
||||||
// Keys input detection
|
// Keys input detection
|
||||||
|
// TODO: Input detection is raylib-dependant, it could be moved outside the module
|
||||||
bool panKey = IsMouseButtonDown(CAMERA.panControl);
|
bool panKey = IsMouseButtonDown(CAMERA.panControl);
|
||||||
bool altKey = IsKeyDown(CAMERA.altControl);
|
bool altKey = IsKeyDown(CAMERA.altControl);
|
||||||
bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl);
|
bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl);
|
||||||
|
@ -297,8 +299,6 @@ void UpdateCamera(Camera *camera)
|
||||||
IsKeyDown(CAMERA.moveControl[MOVE_UP]),
|
IsKeyDown(CAMERA.moveControl[MOVE_UP]),
|
||||||
IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) };
|
IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) };
|
||||||
|
|
||||||
// TODO: Touch input detection (probably gestures system required)
|
|
||||||
|
|
||||||
if (CAMERA.mode != CAMERA_CUSTOM)
|
if (CAMERA.mode != CAMERA_CUSTOM)
|
||||||
{
|
{
|
||||||
mousePositionDelta.x = mousePosition.x - previousMousePosition.x;
|
mousePositionDelta.x = mousePosition.x - previousMousePosition.x;
|
||||||
|
@ -321,7 +321,6 @@ void UpdateCamera(Camera *camera)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Camera looking down
|
// Camera looking down
|
||||||
// TODO: Review, weird comparison of CAMERA.targetDistance == 120.0f?
|
|
||||||
else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
|
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.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
|
||||||
|
@ -342,7 +341,6 @@ void UpdateCamera(Camera *camera)
|
||||||
if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
|
if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
|
||||||
}
|
}
|
||||||
// Camera looking up
|
// Camera looking up
|
||||||
// TODO: Review, weird comparisson of CAMERA.targetDistance == 120.0f?
|
|
||||||
else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
|
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.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
|
||||||
|
@ -489,8 +487,10 @@ void UpdateCamera(Camera *camera)
|
||||||
|
|
||||||
// TODO: It seems camera->position is not correctly updated or some rounding issue makes the camera move straight to camera->target...
|
// TODO: It seems camera->position is not correctly updated or some rounding issue makes the camera move straight to camera->target...
|
||||||
camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
|
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;
|
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;
|
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;
|
camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
*
|
*
|
||||||
**********************************************************************************************/
|
**********************************************************************************************/
|
||||||
|
|
||||||
#define RAYLIB_VERSION "3.0"
|
#define RAYLIB_VERSION "3.1-dev"
|
||||||
|
|
||||||
// Edit to control what features Makefile'd raylib is compiled with
|
// Edit to control what features Makefile'd raylib is compiled with
|
||||||
#if defined(RAYLIB_CMAKE)
|
#if defined(RAYLIB_CMAKE)
|
||||||
|
@ -63,12 +63,56 @@
|
||||||
// Support saving binary data automatically to a generated storage.data file. This file is managed internally.
|
// Support saving binary data automatically to a generated storage.data file. This file is managed internally.
|
||||||
#define SUPPORT_DATA_STORAGE 1
|
#define SUPPORT_DATA_STORAGE 1
|
||||||
|
|
||||||
|
// core: Configuration values
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
#if defined(__linux__)
|
||||||
|
#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
|
||||||
|
#else
|
||||||
|
#define MAX_FILEPATH_LENGTH 512 // Maximum length supported for filepaths
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAX_GAMEPADS 4 // Max number of gamepads supported
|
||||||
|
#define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad)
|
||||||
|
#define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad)
|
||||||
|
#define MAX_TOUCH_POINTS 10 // Maximum number of touch points supported
|
||||||
|
#define MAX_KEY_PRESSED_QUEUE 16 // Max number of characters in the key input queue
|
||||||
|
|
||||||
|
#define STORAGE_DATA_FILE "storage.data" // Automatic storage filename
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: rlgl - Configuration Flags
|
// Module: rlgl - Configuration Flags
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Support VR simulation functionality (stereo rendering)
|
// Support VR simulation functionality (stereo rendering)
|
||||||
#define SUPPORT_VR_SIMULATOR 1
|
#define SUPPORT_VR_SIMULATOR 1
|
||||||
|
|
||||||
|
// rlgl: Configuration values
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
|
||||||
|
#define DEFAULT_BATCH_BUFFER_ELEMENTS 8192 // Default internal render batch limits
|
||||||
|
#elif defined(GRAPHICS_API_OPENGL_ES2)
|
||||||
|
#define DEFAULT_BATCH_BUFFER_ELEMENTS 2048 // Default internal render batch limits
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering)
|
||||||
|
#define DEFAULT_BATCH_DRAWCALLS 256 // Default number of batch draw calls (by state changes: mode, texture)
|
||||||
|
|
||||||
|
#define MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack
|
||||||
|
#define MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
|
||||||
|
#define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported
|
||||||
|
|
||||||
|
#define RL_CULL_DISTANCE_NEAR 0.01 // Default projection matrix near cull distance
|
||||||
|
#define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance
|
||||||
|
|
||||||
|
// Default shader vertex attribute names to set location points
|
||||||
|
#define DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Binded by default to shader location: 0
|
||||||
|
#define DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1
|
||||||
|
#define DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2
|
||||||
|
#define DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3
|
||||||
|
#define DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4
|
||||||
|
#define DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: shapes - Configuration Flags
|
// Module: shapes - Configuration Flags
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
|
@ -79,6 +123,7 @@
|
||||||
// Some lines-based shapes could still use lines
|
// Some lines-based shapes could still use lines
|
||||||
#define SUPPORT_QUADS_DRAW_MODE 1
|
#define SUPPORT_QUADS_DRAW_MODE 1
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: textures - Configuration Flags
|
// Module: textures - Configuration Flags
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
|
@ -86,7 +131,7 @@
|
||||||
#define SUPPORT_FILEFORMAT_PNG 1
|
#define SUPPORT_FILEFORMAT_PNG 1
|
||||||
#define SUPPORT_FILEFORMAT_BMP 1
|
#define SUPPORT_FILEFORMAT_BMP 1
|
||||||
#define SUPPORT_FILEFORMAT_TGA 1
|
#define SUPPORT_FILEFORMAT_TGA 1
|
||||||
#define SUPPORT_FILEFORMAT_JPG 1
|
//#define SUPPORT_FILEFORMAT_JPG 1
|
||||||
#define SUPPORT_FILEFORMAT_GIF 1
|
#define SUPPORT_FILEFORMAT_GIF 1
|
||||||
//#define SUPPORT_FILEFORMAT_PSD 1
|
//#define SUPPORT_FILEFORMAT_PSD 1
|
||||||
#define SUPPORT_FILEFORMAT_DDS 1
|
#define SUPPORT_FILEFORMAT_DDS 1
|
||||||
|
@ -98,11 +143,12 @@
|
||||||
|
|
||||||
// Support image export functionality (.png, .bmp, .tga, .jpg)
|
// Support image export functionality (.png, .bmp, .tga, .jpg)
|
||||||
#define SUPPORT_IMAGE_EXPORT 1
|
#define SUPPORT_IMAGE_EXPORT 1
|
||||||
// Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
|
|
||||||
// If not defined only three image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageToPOT()
|
|
||||||
#define SUPPORT_IMAGE_MANIPULATION 1
|
|
||||||
// Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
|
// Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
|
||||||
#define SUPPORT_IMAGE_GENERATION 1
|
#define SUPPORT_IMAGE_GENERATION 1
|
||||||
|
// Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
|
||||||
|
// If not defined, still some functions are supported: ImageFormat(), ImageCrop(), ImageToPOT()
|
||||||
|
#define SUPPORT_IMAGE_MANIPULATION 1
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: text - Configuration Flags
|
// Module: text - Configuration Flags
|
||||||
|
@ -114,6 +160,18 @@
|
||||||
#define SUPPORT_FILEFORMAT_FNT 1
|
#define SUPPORT_FILEFORMAT_FNT 1
|
||||||
#define SUPPORT_FILEFORMAT_TTF 1
|
#define SUPPORT_FILEFORMAT_TTF 1
|
||||||
|
|
||||||
|
// Support text management functions
|
||||||
|
// If not defined, still some functions are supported: TextLength(), TextFormat()
|
||||||
|
#define SUPPORT_TEXT_MANIPULATION 1
|
||||||
|
|
||||||
|
// text: Configuration values
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
|
||||||
|
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
|
||||||
|
#define MAX_TEXT_UNICODE_CHARS 512 // Maximum number of unicode codepoints: GetCodepoints()
|
||||||
|
#define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit()
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: models - Configuration Flags
|
// Module: models - Configuration Flags
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
|
@ -126,6 +184,7 @@
|
||||||
// NOTE: Some generated meshes DO NOT include generated texture coordinates
|
// NOTE: Some generated meshes DO NOT include generated texture coordinates
|
||||||
#define SUPPORT_MESH_GENERATION 1
|
#define SUPPORT_MESH_GENERATION 1
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: audio - Configuration Flags
|
// Module: audio - Configuration Flags
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
|
@ -137,6 +196,15 @@
|
||||||
//#define SUPPORT_FILEFORMAT_FLAC 1
|
//#define SUPPORT_FILEFORMAT_FLAC 1
|
||||||
#define SUPPORT_FILEFORMAT_MP3 1
|
#define SUPPORT_FILEFORMAT_MP3 1
|
||||||
|
|
||||||
|
// audio: Configuration values
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
#define AUDIO_DEVICE_FORMAT ma_format_f32 // Device output format (miniaudio: float-32bit)
|
||||||
|
#define AUDIO_DEVICE_CHANNELS 2 // Device output channels: stereo
|
||||||
|
#define AUDIO_DEVICE_SAMPLE_RATE 44100 // Device output sample rate
|
||||||
|
|
||||||
|
#define DEFAULT_AUDIO_BUFFER_SIZE 4096 // Default audio buffer size for streaming
|
||||||
|
#define MAX_AUDIO_BUFFER_POOL_CHANNELS 16 // Maximum number of audio pool channels
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Module: utils - Configuration Flags
|
// Module: utils - Configuration Flags
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
|
@ -145,4 +213,10 @@
|
||||||
#define SUPPORT_TRACELOG 1
|
#define SUPPORT_TRACELOG 1
|
||||||
//#define SUPPORT_TRACELOG_DEBUG 1
|
//#define SUPPORT_TRACELOG_DEBUG 1
|
||||||
|
|
||||||
|
// utils: Configuration values
|
||||||
|
//------------------------------------------------------------------------------------
|
||||||
|
#define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message
|
||||||
|
#define MAX_UWP_MESSAGES 512 // Max UWP messages to process
|
||||||
|
|
||||||
|
|
||||||
#endif //defined(RAYLIB_CMAKE)
|
#endif //defined(RAYLIB_CMAKE)
|
||||||
|
|
1243
raylib/core.c
1243
raylib/core.c
File diff suppressed because it is too large
Load diff
263
raylib/easings.h
Normal file
263
raylib/easings.h
Normal file
|
@ -0,0 +1,263 @@
|
||||||
|
/*******************************************************************************************
|
||||||
|
*
|
||||||
|
* raylib easings (header only file)
|
||||||
|
*
|
||||||
|
* Useful easing functions for values animation
|
||||||
|
*
|
||||||
|
* This header uses:
|
||||||
|
* #define EASINGS_STATIC_INLINE // Inlines all functions code, so it runs faster.
|
||||||
|
* // This requires lots of memory on system.
|
||||||
|
* How to use:
|
||||||
|
* The four inputs t,b,c,d are defined as follows:
|
||||||
|
* t = current time (in any unit measure, but same unit as duration)
|
||||||
|
* b = starting value to interpolate
|
||||||
|
* c = the total change in value of b that needs to occur
|
||||||
|
* d = total time it should take to complete (duration)
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* int currentTime = 0;
|
||||||
|
* int duration = 100;
|
||||||
|
* float startPositionX = 0.0f;
|
||||||
|
* float finalPositionX = 30.0f;
|
||||||
|
* float currentPositionX = startPositionX;
|
||||||
|
*
|
||||||
|
* while (currentPositionX < finalPositionX)
|
||||||
|
* {
|
||||||
|
* currentPositionX = EaseSineIn(currentTime, startPositionX, finalPositionX - startPositionX, duration);
|
||||||
|
* currentTime++;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* A port of Robert Penner's easing equations to C (http://robertpenner.com/easing/)
|
||||||
|
*
|
||||||
|
* Robert Penner License
|
||||||
|
* ---------------------------------------------------------------------------------
|
||||||
|
* Open source under the BSD License.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2001 Robert Penner. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* - Neither the name of the author nor the names of contributors may be used
|
||||||
|
* to endorse or promote products derived from this software without specific
|
||||||
|
* prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||||
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
* ---------------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Ramon Santamaria
|
||||||
|
*
|
||||||
|
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||||
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose, including commercial
|
||||||
|
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||||
|
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||||
|
* in the product documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||||
|
* as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*
|
||||||
|
**********************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef EASINGS_H
|
||||||
|
#define EASINGS_H
|
||||||
|
|
||||||
|
#define EASINGS_STATIC_INLINE // NOTE: By default, compile functions as static inline
|
||||||
|
|
||||||
|
#if defined(EASINGS_STATIC_INLINE)
|
||||||
|
#define EASEDEF static inline
|
||||||
|
#else
|
||||||
|
#define EASEDEF extern
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <math.h> // Required for: sinf(), cosf(), sqrtf(), powf()
|
||||||
|
|
||||||
|
#ifndef PI
|
||||||
|
#define PI 3.14159265358979323846f //Required as PI is not always defined in math.h
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" { // Prevents name mangling of functions
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Linear Easing functions
|
||||||
|
EASEDEF float EaseLinearNone(float t, float b, float c, float d) { return (c*t/d + b); }
|
||||||
|
EASEDEF float EaseLinearIn(float t, float b, float c, float d) { return (c*t/d + b); }
|
||||||
|
EASEDEF float EaseLinearOut(float t, float b, float c, float d) { return (c*t/d + b); }
|
||||||
|
EASEDEF float EaseLinearInOut(float t,float b, float c, float d) { return (c*t/d + b); }
|
||||||
|
|
||||||
|
// Sine Easing functions
|
||||||
|
EASEDEF float EaseSineIn(float t, float b, float c, float d) { return (-c*cosf(t/d*(PI/2.0f)) + c + b); }
|
||||||
|
EASEDEF float EaseSineOut(float t, float b, float c, float d) { return (c*sinf(t/d*(PI/2.0f)) + b); }
|
||||||
|
EASEDEF float EaseSineInOut(float t, float b, float c, float d) { return (-c/2.0f*(cosf(PI*t/d) - 1.0f) + b); }
|
||||||
|
|
||||||
|
// Circular Easing functions
|
||||||
|
EASEDEF float EaseCircIn(float t, float b, float c, float d) { t /= d; return (-c*(sqrtf(1.0f - t*t) - 1.0f) + b); }
|
||||||
|
EASEDEF float EaseCircOut(float t, float b, float c, float d) { t = t/d - 1.0f; return (c*sqrtf(1.0f - t*t) + b); }
|
||||||
|
EASEDEF float EaseCircInOut(float t, float b, float c, float d)
|
||||||
|
{
|
||||||
|
if ((t/=d/2.0f) < 1.0f) return (-c/2.0f*(sqrtf(1.0f - t*t) - 1.0f) + b);
|
||||||
|
t -= 2.0f; return (c/2.0f*(sqrtf(1.0f - t*t) + 1.0f) + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cubic Easing functions
|
||||||
|
EASEDEF float EaseCubicIn(float t, float b, float c, float d) { t /= d; return (c*t*t*t + b); }
|
||||||
|
EASEDEF float EaseCubicOut(float t, float b, float c, float d) { t = t/d - 1.0f; return (c*(t*t*t + 1.0f) + b); }
|
||||||
|
EASEDEF float EaseCubicInOut(float t, float b, float c, float d)
|
||||||
|
{
|
||||||
|
if ((t/=d/2.0f) < 1.0f) return (c/2.0f*t*t*t + b);
|
||||||
|
t -= 2.0f; return (c/2.0f*(t*t*t + 2.0f) + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quadratic Easing functions
|
||||||
|
EASEDEF float EaseQuadIn(float t, float b, float c, float d) { t /= d; return (c*t*t + b); }
|
||||||
|
EASEDEF float EaseQuadOut(float t, float b, float c, float d) { t /= d; return (-c*t*(t - 2.0f) + b); }
|
||||||
|
EASEDEF float EaseQuadInOut(float t, float b, float c, float d)
|
||||||
|
{
|
||||||
|
if ((t/=d/2) < 1) return (((c/2)*(t*t)) + b);
|
||||||
|
return (-c/2.0f*(((t - 1.0f)*(t - 3.0f)) - 1.0f) + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exponential Easing functions
|
||||||
|
EASEDEF float EaseExpoIn(float t, float b, float c, float d) { return (t == 0.0f) ? b : (c*powf(2.0f, 10.0f*(t/d - 1.0f)) + b); }
|
||||||
|
EASEDEF float EaseExpoOut(float t, float b, float c, float d) { return (t == d) ? (b + c) : (c*(-powf(2.0f, -10.0f*t/d) + 1.0f) + b); }
|
||||||
|
EASEDEF float EaseExpoInOut(float t, float b, float c, float d)
|
||||||
|
{
|
||||||
|
if (t == 0.0f) return b;
|
||||||
|
if (t == d) return (b + c);
|
||||||
|
if ((t/=d/2.0f) < 1.0f) return (c/2.0f*powf(2.0f, 10.0f*(t - 1.0f)) + b);
|
||||||
|
|
||||||
|
return (c/2.0f*(-powf(2.0f, -10.0f*(t - 1.0f)) + 2.0f) + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Back Easing functions
|
||||||
|
EASEDEF float EaseBackIn(float t, float b, float c, float d)
|
||||||
|
{
|
||||||
|
float s = 1.70158f;
|
||||||
|
float postFix = t/=d;
|
||||||
|
return (c*(postFix)*t*((s + 1.0f)*t - s) + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
EASEDEF float EaseBackOut(float t, float b, float c, float d)
|
||||||
|
{
|
||||||
|
float s = 1.70158f;
|
||||||
|
t = t/d - 1.0f;
|
||||||
|
return (c*(t*t*((s + 1.0f)*t + s) + 1.0f) + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
EASEDEF float EaseBackInOut(float t, float b, float c, float d)
|
||||||
|
{
|
||||||
|
float s = 1.70158f;
|
||||||
|
if ((t/=d/2.0f) < 1.0f)
|
||||||
|
{
|
||||||
|
s *= 1.525f;
|
||||||
|
return (c/2.0f*(t*t*((s + 1.0f)*t - s)) + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
float postFix = t-=2.0f;
|
||||||
|
s *= 1.525f;
|
||||||
|
return (c/2.0f*((postFix)*t*((s + 1.0f)*t + s) + 2.0f) + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bounce Easing functions
|
||||||
|
EASEDEF float EaseBounceOut(float t, float b, float c, float d)
|
||||||
|
{
|
||||||
|
if ((t/=d) < (1.0f/2.75f))
|
||||||
|
{
|
||||||
|
return (c*(7.5625f*t*t) + b);
|
||||||
|
}
|
||||||
|
else if (t < (2.0f/2.75f))
|
||||||
|
{
|
||||||
|
float postFix = t-=(1.5f/2.75f);
|
||||||
|
return (c*(7.5625f*(postFix)*t + 0.75f) + b);
|
||||||
|
}
|
||||||
|
else if (t < (2.5/2.75))
|
||||||
|
{
|
||||||
|
float postFix = t-=(2.25f/2.75f);
|
||||||
|
return (c*(7.5625f*(postFix)*t + 0.9375f) + b);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float postFix = t-=(2.625f/2.75f);
|
||||||
|
return (c*(7.5625f*(postFix)*t + 0.984375f) + b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EASEDEF float EaseBounceIn(float t, float b, float c, float d) { return (c - EaseBounceOut(d - t, 0.0f, c, d) + b); }
|
||||||
|
EASEDEF float EaseBounceInOut(float t, float b, float c, float d)
|
||||||
|
{
|
||||||
|
if (t < d/2.0f) return (EaseBounceIn(t*2.0f, 0.0f, c, d)*0.5f + b);
|
||||||
|
else return (EaseBounceOut(t*2.0f - d, 0.0f, c, d)*0.5f + c*0.5f + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Elastic Easing functions
|
||||||
|
EASEDEF float EaseElasticIn(float t, float b, float c, float d)
|
||||||
|
{
|
||||||
|
if (t == 0.0f) return b;
|
||||||
|
if ((t/=d) == 1.0f) return (b + c);
|
||||||
|
|
||||||
|
float p = d*0.3f;
|
||||||
|
float a = c;
|
||||||
|
float s = p/4.0f;
|
||||||
|
float postFix = a*powf(2.0f, 10.0f*(t-=1.0f));
|
||||||
|
|
||||||
|
return (-(postFix*sinf((t*d-s)*(2.0f*PI)/p )) + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
EASEDEF float EaseElasticOut(float t, float b, float c, float d)
|
||||||
|
{
|
||||||
|
if (t == 0.0f) return b;
|
||||||
|
if ((t/=d) == 1.0f) return (b + c);
|
||||||
|
|
||||||
|
float p = d*0.3f;
|
||||||
|
float a = c;
|
||||||
|
float s = p/4.0f;
|
||||||
|
|
||||||
|
return (a*powf(2.0f,-10.0f*t)*sinf((t*d-s)*(2.0f*PI)/p) + c + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
EASEDEF float EaseElasticInOut(float t, float b, float c, float d)
|
||||||
|
{
|
||||||
|
if (t == 0.0f) return b;
|
||||||
|
if ((t/=d/2.0f) == 2.0f) return (b + c);
|
||||||
|
|
||||||
|
float p = d*(0.3f*1.5f);
|
||||||
|
float a = c;
|
||||||
|
float s = p/4.0f;
|
||||||
|
|
||||||
|
if (t < 1.0f)
|
||||||
|
{
|
||||||
|
float postFix = a*powf(2.0f, 10.0f*(t-=1.0f));
|
||||||
|
return -0.5f*(postFix*sinf((t*d-s)*(2.0f*PI)/p)) + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
float postFix = a*powf(2.0f, -10.0f*(t-=1.0f));
|
||||||
|
|
||||||
|
return (postFix*sinf((t*d-s)*(2.0f*PI)/p)*0.5f + c + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // EASINGS_H
|
4893
raylib/external/dr_wav.h
vendored
4893
raylib/external/dr_wav.h
vendored
File diff suppressed because it is too large
Load diff
30
raylib/external/jar_mod.h
vendored
30
raylib/external/jar_mod.h
vendored
|
@ -81,15 +81,13 @@
|
||||||
#ifndef INCLUDE_JAR_MOD_H
|
#ifndef INCLUDE_JAR_MOD_H
|
||||||
#define INCLUDE_JAR_MOD_H
|
#define INCLUDE_JAR_MOD_H
|
||||||
|
|
||||||
#include <stdio.h>
|
// Allow custom memory allocators
|
||||||
#include <stdlib.h>
|
#ifndef JARMOD_MALLOC
|
||||||
//#include <stdbool.h>
|
#define JARMOD_MALLOC(sz) malloc(sz)
|
||||||
|
#endif
|
||||||
|
#ifndef JARMOD_FREE
|
||||||
#ifdef __cplusplus
|
#define JARMOD_FREE(p) free(p)
|
||||||
extern "C" {
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Basic type
|
// Basic type
|
||||||
|
@ -240,7 +238,9 @@ typedef struct jar_mod_tracker_buffer_state_
|
||||||
tracker_state * track_state_buf;
|
tracker_state * track_state_buf;
|
||||||
}jar_mod_tracker_buffer_state;
|
}jar_mod_tracker_buffer_state;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
bool jar_mod_init(jar_mod_context_t * modctx);
|
bool jar_mod_init(jar_mod_context_t * modctx);
|
||||||
bool jar_mod_setcfg(jar_mod_context_t * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter);
|
bool jar_mod_setcfg(jar_mod_context_t * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter);
|
||||||
|
@ -261,6 +261,10 @@ void jar_mod_seek_start(jar_mod_context_t * ctx);
|
||||||
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
||||||
#ifdef JAR_MOD_IMPLEMENTATION
|
#ifdef JAR_MOD_IMPLEMENTATION
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
//#include <stdbool.h>
|
||||||
|
|
||||||
// Effects list
|
// Effects list
|
||||||
#define EFFECT_ARPEGGIO 0x0 // Supported
|
#define EFFECT_ARPEGGIO 0x0 // Supported
|
||||||
#define EFFECT_PORTAMENTO_UP 0x1 // Supported
|
#define EFFECT_PORTAMENTO_UP 0x1 // Supported
|
||||||
|
@ -1504,7 +1508,7 @@ void jar_mod_unload( jar_mod_context_t * modctx)
|
||||||
{
|
{
|
||||||
if(modctx->modfile)
|
if(modctx->modfile)
|
||||||
{
|
{
|
||||||
free(modctx->modfile);
|
JARMOD_FREE(modctx->modfile);
|
||||||
modctx->modfile = 0;
|
modctx->modfile = 0;
|
||||||
modctx->modfilesize = 0;
|
modctx->modfilesize = 0;
|
||||||
modctx->loopcount = 0;
|
modctx->loopcount = 0;
|
||||||
|
@ -1513,14 +1517,12 @@ void jar_mod_unload( jar_mod_context_t * modctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename)
|
mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename)
|
||||||
{
|
{
|
||||||
mulong fsize = 0;
|
mulong fsize = 0;
|
||||||
if(modctx->modfile)
|
if(modctx->modfile)
|
||||||
{
|
{
|
||||||
free(modctx->modfile);
|
JARMOD_FREE(modctx->modfile);
|
||||||
modctx->modfile = 0;
|
modctx->modfile = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1533,7 +1535,7 @@ mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename)
|
||||||
|
|
||||||
if(fsize && fsize < 32*1024*1024)
|
if(fsize && fsize < 32*1024*1024)
|
||||||
{
|
{
|
||||||
modctx->modfile = malloc(fsize);
|
modctx->modfile = JARMOD_MALLOC(fsize);
|
||||||
modctx->modfilesize = fsize;
|
modctx->modfilesize = fsize;
|
||||||
memset(modctx->modfile, 0, fsize);
|
memset(modctx->modfile, 0, fsize);
|
||||||
fread(modctx->modfile, fsize, 1, f);
|
fread(modctx->modfile, fsize, 1, f);
|
||||||
|
|
53
raylib/external/jar_xm.h
vendored
53
raylib/external/jar_xm.h
vendored
|
@ -51,27 +51,29 @@
|
||||||
#ifndef INCLUDE_JAR_XM_H
|
#ifndef INCLUDE_JAR_XM_H
|
||||||
#define INCLUDE_JAR_XM_H
|
#define INCLUDE_JAR_XM_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#define JAR_XM_DEBUG 0
|
#define JAR_XM_DEBUG 0
|
||||||
#define JAR_XM_LINEAR_INTERPOLATION 1 // speed increase with decrease in quality
|
#define JAR_XM_LINEAR_INTERPOLATION 1 // speed increase with decrease in quality
|
||||||
#define JAR_XM_DEFENSIVE 1
|
#define JAR_XM_DEFENSIVE 1
|
||||||
#define JAR_XM_RAMPING 1
|
#define JAR_XM_RAMPING 1
|
||||||
|
|
||||||
#include <stdio.h>
|
// Allow custom memory allocators
|
||||||
#include <stdlib.h>
|
#ifndef JARXM_MALLOC
|
||||||
#include <stdint.h>
|
#define JARXM_MALLOC(sz) malloc(sz)
|
||||||
#include <limits.h>
|
#endif
|
||||||
#include <string.h>
|
#ifndef JARXM_FREE
|
||||||
|
#define JARXM_FREE(p) free(p)
|
||||||
|
#endif
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
||||||
|
struct jar_xm_context_s;
|
||||||
|
typedef struct jar_xm_context_s jar_xm_context_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct jar_xm_context_s;
|
|
||||||
typedef struct jar_xm_context_s jar_xm_context_t;
|
|
||||||
|
|
||||||
/** Create a XM context.
|
/** Create a XM context.
|
||||||
*
|
*
|
||||||
* @param moddata the contents of the module
|
* @param moddata the contents of the module
|
||||||
|
@ -133,7 +135,7 @@ void jar_xm_generate_samples(jar_xm_context_t* ctx, float* output, size_t numsam
|
||||||
*/
|
*/
|
||||||
void jar_xm_generate_samples_16bit(jar_xm_context_t* ctx, short* output, size_t numsamples)
|
void jar_xm_generate_samples_16bit(jar_xm_context_t* ctx, short* output, size_t numsamples)
|
||||||
{
|
{
|
||||||
float* musicBuffer = malloc((2*numsamples)*sizeof(float));
|
float* musicBuffer = JARXM_MALLOC((2*numsamples)*sizeof(float));
|
||||||
jar_xm_generate_samples(ctx, musicBuffer, numsamples);
|
jar_xm_generate_samples(ctx, musicBuffer, numsamples);
|
||||||
|
|
||||||
if(output){
|
if(output){
|
||||||
|
@ -142,7 +144,7 @@ void jar_xm_generate_samples_16bit(jar_xm_context_t* ctx, short* output, size_t
|
||||||
output[x] = musicBuffer[x] * SHRT_MAX;
|
output[x] = musicBuffer[x] * SHRT_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(musicBuffer);
|
JARXM_FREE(musicBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Play the module, resample from 32 bit to 8 bit, and put the sound samples in an output buffer.
|
/** Play the module, resample from 32 bit to 8 bit, and put the sound samples in an output buffer.
|
||||||
|
@ -152,7 +154,7 @@ void jar_xm_generate_samples_16bit(jar_xm_context_t* ctx, short* output, size_t
|
||||||
*/
|
*/
|
||||||
void jar_xm_generate_samples_8bit(jar_xm_context_t* ctx, char* output, size_t numsamples)
|
void jar_xm_generate_samples_8bit(jar_xm_context_t* ctx, char* output, size_t numsamples)
|
||||||
{
|
{
|
||||||
float* musicBuffer = malloc((2*numsamples)*sizeof(float));
|
float* musicBuffer = JARXM_MALLOC((2*numsamples)*sizeof(float));
|
||||||
jar_xm_generate_samples(ctx, musicBuffer, numsamples);
|
jar_xm_generate_samples(ctx, musicBuffer, numsamples);
|
||||||
|
|
||||||
if(output){
|
if(output){
|
||||||
|
@ -161,7 +163,7 @@ void jar_xm_generate_samples_8bit(jar_xm_context_t* ctx, char* output, size_t nu
|
||||||
output[x] = musicBuffer[x] * CHAR_MAX;
|
output[x] = musicBuffer[x] * CHAR_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(musicBuffer);
|
JARXM_FREE(musicBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -306,6 +308,9 @@ uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx);
|
||||||
#ifdef JAR_XM_IMPLEMENTATION
|
#ifdef JAR_XM_IMPLEMENTATION
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if JAR_XM_DEBUG //JAR_XM_DEBUG defined as 0
|
#if JAR_XM_DEBUG //JAR_XM_DEBUG defined as 0
|
||||||
|
@ -630,10 +635,10 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bytes_needed = jar_xm_get_memory_needed_for_context(moddata, moddata_length);
|
bytes_needed = jar_xm_get_memory_needed_for_context(moddata, moddata_length);
|
||||||
mempool = malloc(bytes_needed);
|
mempool = JARXM_MALLOC(bytes_needed);
|
||||||
if(mempool == NULL && bytes_needed > 0) {
|
if(mempool == NULL && bytes_needed > 0) {
|
||||||
/* malloc() failed, trouble ahead */
|
/* JARXM_MALLOC() failed, trouble ahead */
|
||||||
DEBUG("call to malloc() failed, returned %p", (void*)mempool);
|
DEBUG("call to JARXM_MALLOC() failed, returned %p", (void*)mempool);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -641,7 +646,7 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz
|
||||||
memset(mempool, 0, bytes_needed);
|
memset(mempool, 0, bytes_needed);
|
||||||
|
|
||||||
ctx = (*ctxp = (jar_xm_context_t *)mempool);
|
ctx = (*ctxp = (jar_xm_context_t *)mempool);
|
||||||
ctx->allocated_memory = mempool; /* Keep original pointer for free() */
|
ctx->allocated_memory = mempool; /* Keep original pointer for JARXM_FREE() */
|
||||||
mempool += sizeof(jar_xm_context_t);
|
mempool += sizeof(jar_xm_context_t);
|
||||||
|
|
||||||
ctx->rate = rate;
|
ctx->rate = rate;
|
||||||
|
@ -691,7 +696,7 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz
|
||||||
}
|
}
|
||||||
|
|
||||||
void jar_xm_free_context(jar_xm_context_t* ctx) {
|
void jar_xm_free_context(jar_xm_context_t* ctx) {
|
||||||
free(ctx->allocated_memory);
|
JARXM_FREE(ctx->allocated_memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
void jar_xm_set_max_loop_count(jar_xm_context_t* ctx, uint8_t loopcnt) {
|
void jar_xm_set_max_loop_count(jar_xm_context_t* ctx, uint8_t loopcnt) {
|
||||||
|
@ -2620,11 +2625,11 @@ int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* data = malloc(size + 1);
|
char* data = JARXM_MALLOC(size + 1);
|
||||||
if(!data || fread(data, 1, size, xmf) < size) {
|
if(!data || fread(data, 1, size, xmf) < size) {
|
||||||
fclose(xmf);
|
fclose(xmf);
|
||||||
DEBUG_ERR(data ? "fread() failed" : "malloc() failed");
|
DEBUG_ERR(data ? "fread() failed" : "JARXM_MALLOC() failed");
|
||||||
free(data);
|
JARXM_FREE(data);
|
||||||
*ctx = NULL;
|
*ctx = NULL;
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
@ -2632,7 +2637,7 @@ int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const
|
||||||
fclose(xmf);
|
fclose(xmf);
|
||||||
|
|
||||||
ret = jar_xm_create_context_safe(ctx, data, size, rate);
|
ret = jar_xm_create_context_safe(ctx, data, size, rate);
|
||||||
free(data);
|
JARXM_FREE(data);
|
||||||
|
|
||||||
switch(ret) {
|
switch(ret) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -2670,7 +2675,7 @@ void jar_xm_reset(jar_xm_context_t* ctx)
|
||||||
jar_xm_cut_note(&ctx->channels[i]);
|
jar_xm_cut_note(&ctx->channels[i]);
|
||||||
}
|
}
|
||||||
ctx->current_row = 0;
|
ctx->current_row = 0;
|
||||||
ctx->current_table_index = ctx->module.restart_position;
|
ctx->current_table_index = 0;
|
||||||
ctx->current_tick = 0;
|
ctx->current_tick = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
36832
raylib/external/miniaudio.h
vendored
36832
raylib/external/miniaudio.h
vendored
File diff suppressed because it is too large
Load diff
|
@ -154,7 +154,6 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang
|
||||||
|
|
||||||
#include <math.h> // Required for: sqrtf(), atan2f()
|
#include <math.h> // Required for: sqrtf(), atan2f()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__APPLE__) // macOS also defines __MACH__
|
#if defined(__APPLE__) // macOS also defines __MACH__
|
||||||
#include <mach/clock.h> // Required for: clock_get_time()
|
#include <mach/clock.h> // Required for: clock_get_time()
|
||||||
#include <mach/mach.h> // Required for: mach_timespec_t
|
#include <mach/mach.h> // Required for: mach_timespec_t
|
||||||
|
@ -163,19 +162,20 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Defines and Macros
|
// Defines and Macros
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
#define FORCE_TO_SWIPE 0.0005f // Measured in normalized screen units/time
|
#define FORCE_TO_SWIPE 0.0005f // Swipe force, measured in normalized screen units/time
|
||||||
#define MINIMUM_DRAG 0.015f // Measured in normalized screen units (0.0f to 1.0f)
|
#define MINIMUM_DRAG 0.015f // Drag minimum force, measured in normalized screen units (0.0f to 1.0f)
|
||||||
#define MINIMUM_PINCH 0.005f // Measured in normalized screen units (0.0f to 1.0f)
|
#define MINIMUM_PINCH 0.005f // Pinch minimum force, measured in normalized screen units (0.0f to 1.0f)
|
||||||
#define TAP_TIMEOUT 300 // Time in milliseconds
|
#define TAP_TIMEOUT 300 // Tap minimum time, measured in milliseconds
|
||||||
#define PINCH_TIMEOUT 300 // Time in milliseconds
|
#define PINCH_TIMEOUT 300 // Pinch minimum time, measured in milliseconds
|
||||||
#define DOUBLETAP_RANGE 0.03f // Measured in normalized screen units (0.0f to 1.0f)
|
#define DOUBLETAP_RANGE 0.03f // DoubleTap range, measured in normalized screen units (0.0f to 1.0f)
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Types and Structures Definition
|
// Types and Structures Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Gestures module state context [136 bytes]
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int current; // Current detected gesture
|
unsigned int current; // Current detected gesture
|
||||||
unsigned int enabledFlags; // Enabled gestures flags
|
unsigned int enabledFlags; // Enabled gestures flags
|
||||||
struct {
|
struct {
|
||||||
int firstId; // Touch id for first touch point
|
int firstId; // Touch id for first touch point
|
||||||
|
@ -215,8 +215,8 @@ typedef struct {
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
static GesturesData GESTURES = {
|
static GesturesData GESTURES = {
|
||||||
.Touch.firstId = -1,
|
.Touch.firstId = -1,
|
||||||
.current = GESTURE_NONE,
|
.current = GESTURE_NONE, // No current gesture detected
|
||||||
.enabledFlags = 0b0000001111111111 // All gestures enabled by default
|
.enabledFlags = 0b0000001111111111 // All gestures supported by default
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
661
raylib/models.c
661
raylib/models.c
File diff suppressed because it is too large
Load diff
2063
raylib/physac.h
Normal file
2063
raylib/physac.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -90,3 +90,59 @@ func OpenAsset(name string) (Asset, error) {
|
||||||
}
|
}
|
||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsWindowMaximized - Check if window has been maximized (only PLATFORM_DESKTOP)
|
||||||
|
func IsWindowMaximized() bool {
|
||||||
|
ret := C.IsWindowMaximized()
|
||||||
|
v := bool(ret)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsWindowFocused - Check if window has been focused
|
||||||
|
func IsWindowFocused() bool {
|
||||||
|
ret := C.IsWindowFocused()
|
||||||
|
v := bool(ret)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecorateWindow - Decorate the window (only PLATFORM_DESKTOP)
|
||||||
|
func DecorateWindow() {
|
||||||
|
C.DecorateWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UndecorateWindow - Undecorate the window (only PLATFORM_DESKTOP)
|
||||||
|
func UndecorateWindow() {
|
||||||
|
C.UndecorateWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaximizeWindow - Maximize the window, if resizable (only PLATFORM_DESKTOP)
|
||||||
|
func MaximizeWindow() {
|
||||||
|
C.MaximizeWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestoreWindow - Restore the window, if resizable (only PLATFORM_DESKTOP)
|
||||||
|
func RestoreWindow() {
|
||||||
|
C.RestoreWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMonitorRefreshRate - Get primary monitor refresh rate
|
||||||
|
func GetMonitorRefreshRate(monitor int) int {
|
||||||
|
cmonitor := (C.int)(monitor)
|
||||||
|
ret := C.GetMonitorRefreshRate(cmonitor)
|
||||||
|
v := (int)(ret)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWindowScaleDPI - Get window scale DPI factor
|
||||||
|
func GetWindowScaleDPI() Vector2 {
|
||||||
|
ret := C.GetWindowScaleDPI()
|
||||||
|
v := newVector2FromPointer(unsafe.Pointer(&ret))
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCursorOnScreen - Check if cursor is on the current screen.
|
||||||
|
func IsCursorOnScreen() bool {
|
||||||
|
ret := C.IsCursorOnScreen()
|
||||||
|
v := bool(ret)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
581
raylib/raudio.c
581
raylib/raudio.c
|
@ -1,5 +1,3 @@
|
||||||
// +build !noaudio
|
|
||||||
|
|
||||||
/**********************************************************************************************
|
/**********************************************************************************************
|
||||||
*
|
*
|
||||||
* raudio - A simple and easy-to-use audio library based on miniaudio
|
* raudio - A simple and easy-to-use audio library based on miniaudio
|
||||||
|
@ -161,6 +159,9 @@ typedef struct tagBITMAPINFOHEADER {
|
||||||
#define MA_FREE RL_FREE
|
#define MA_FREE RL_FREE
|
||||||
|
|
||||||
#define MA_NO_JACK
|
#define MA_NO_JACK
|
||||||
|
#define MA_NO_WAV
|
||||||
|
#define MA_NO_FLAC
|
||||||
|
#define MA_NO_MP3
|
||||||
#define MINIAUDIO_IMPLEMENTATION
|
#define MINIAUDIO_IMPLEMENTATION
|
||||||
#include "external/miniaudio.h" // miniaudio library
|
#include "external/miniaudio.h" // miniaudio library
|
||||||
#undef PlaySound // Win32 API: windows.h > mmsystem.h defines PlaySound macro
|
#undef PlaySound // Win32 API: windows.h > mmsystem.h defines PlaySound macro
|
||||||
|
@ -174,6 +175,20 @@ typedef struct tagBITMAPINFOHEADER {
|
||||||
#if !defined(TRACELOG)
|
#if !defined(TRACELOG)
|
||||||
#define TRACELOG(level, ...) (void)0
|
#define TRACELOG(level, ...) (void)0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Allow custom memory allocators
|
||||||
|
#ifndef RL_MALLOC
|
||||||
|
#define RL_MALLOC(sz) malloc(sz)
|
||||||
|
#endif
|
||||||
|
#ifndef RL_CALLOC
|
||||||
|
#define RL_CALLOC(n,sz) calloc(n,sz)
|
||||||
|
#endif
|
||||||
|
#ifndef RL_REALLOC
|
||||||
|
#define RL_REALLOC(ptr,sz) realloc(ptr,sz)
|
||||||
|
#endif
|
||||||
|
#ifndef RL_FREE
|
||||||
|
#define RL_FREE(ptr) free(ptr)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_OGG)
|
#if defined(SUPPORT_FILEFORMAT_OGG)
|
||||||
|
@ -199,14 +214,13 @@ typedef struct tagBITMAPINFOHEADER {
|
||||||
#include "external/jar_mod.h" // MOD loading functions
|
#include "external/jar_mod.h" // MOD loading functions
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_FLAC)
|
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||||
#define DRFLAC_MALLOC RL_MALLOC
|
#define DRWAV_MALLOC RL_MALLOC
|
||||||
#define DRFLAC_REALLOC RL_REALLOC
|
#define DRWAV_REALLOC RL_REALLOC
|
||||||
#define DRFLAC_FREE RL_FREE
|
#define DRWAV_FREE RL_FREE
|
||||||
|
|
||||||
#define DR_FLAC_IMPLEMENTATION
|
#define DR_WAV_IMPLEMENTATION
|
||||||
#define DR_FLAC_NO_WIN32_IO
|
#include "external/dr_wav.h" // WAV loading functions
|
||||||
#include "external/dr_flac.h" // FLAC loading functions
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_MP3)
|
#if defined(SUPPORT_FILEFORMAT_MP3)
|
||||||
|
@ -218,6 +232,16 @@ typedef struct tagBITMAPINFOHEADER {
|
||||||
#include "external/dr_mp3.h" // MP3 loading functions
|
#include "external/dr_mp3.h" // MP3 loading functions
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(SUPPORT_FILEFORMAT_FLAC)
|
||||||
|
#define DRFLAC_MALLOC RL_MALLOC
|
||||||
|
#define DRFLAC_REALLOC RL_REALLOC
|
||||||
|
#define DRFLAC_FREE RL_FREE
|
||||||
|
|
||||||
|
#define DR_FLAC_IMPLEMENTATION
|
||||||
|
#define DR_FLAC_NO_WIN32_IO
|
||||||
|
#include "external/dr_flac.h" // FLAC loading functions
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
#undef bool
|
#undef bool
|
||||||
#endif
|
#endif
|
||||||
|
@ -225,11 +249,22 @@ typedef struct tagBITMAPINFOHEADER {
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Defines and Macros
|
// Defines and Macros
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
#define AUDIO_DEVICE_FORMAT ma_format_f32
|
#ifndef AUDIO_DEVICE_FORMAT
|
||||||
#define AUDIO_DEVICE_CHANNELS 2
|
#define AUDIO_DEVICE_FORMAT ma_format_f32 // Device output format (float-32bit)
|
||||||
#define AUDIO_DEVICE_SAMPLE_RATE 44100
|
#endif
|
||||||
|
#ifndef AUDIO_DEVICE_CHANNELS
|
||||||
|
#define AUDIO_DEVICE_CHANNELS 2 // Device output channels: stereo
|
||||||
|
#endif
|
||||||
|
#ifndef AUDIO_DEVICE_SAMPLE_RATE
|
||||||
|
#define AUDIO_DEVICE_SAMPLE_RATE 44100 // Device output sample rate
|
||||||
|
#endif
|
||||||
|
#ifndef MAX_AUDIO_BUFFER_POOL_CHANNELS
|
||||||
|
#define MAX_AUDIO_BUFFER_POOL_CHANNELS 16 // Audio pool channels
|
||||||
|
#endif
|
||||||
|
#ifndef DEFAULT_AUDIO_BUFFER_SIZE
|
||||||
|
#define DEFAULT_AUDIO_BUFFER_SIZE 4096 // Default audio buffer size
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MAX_AUDIO_BUFFER_POOL_CHANNELS 16
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Types and Structures Definition
|
// Types and Structures Definition
|
||||||
|
@ -321,7 +356,7 @@ static AudioData AUDIO = { // Global AUDIO context
|
||||||
// After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds and a
|
// After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds and a
|
||||||
// standard double-buffering system, a 4096 samples buffer has been chosen, it should be enough
|
// standard double-buffering system, a 4096 samples buffer has been chosen, it should be enough
|
||||||
// In case of music-stalls, just increase this number
|
// In case of music-stalls, just increase this number
|
||||||
.Buffer.defaultSize = 4096
|
.Buffer.defaultSize = DEFAULT_AUDIO_BUFFER_SIZE
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -349,8 +384,10 @@ static Wave LoadMP3(const char *fileName); // Load MP3 file
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(RAUDIO_STANDALONE)
|
#if defined(RAUDIO_STANDALONE)
|
||||||
bool IsFileExtension(const char *fileName, const char *ext);// Check file extension
|
static bool IsFileExtension(const char *fileName, const char *ext); // Check file extension
|
||||||
void TraceLog(int msgType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
|
static unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead); // Load file data as byte array (read)
|
||||||
|
static void SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite); // Save data to file from byte array (write)
|
||||||
|
static void SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -393,14 +430,14 @@ void InitAudioDevice(void)
|
||||||
// NOTE: Using the default device. Format is floating point because it simplifies mixing.
|
// NOTE: Using the default device. Format is floating point because it simplifies mixing.
|
||||||
ma_device_config config = ma_device_config_init(ma_device_type_playback);
|
ma_device_config config = ma_device_config_init(ma_device_type_playback);
|
||||||
config.playback.pDeviceID = NULL; // NULL for the default playback AUDIO.System.device.
|
config.playback.pDeviceID = NULL; // NULL for the default playback AUDIO.System.device.
|
||||||
config.playback.format = AUDIO_DEVICE_FORMAT;
|
config.playback.format = AUDIO_DEVICE_FORMAT;
|
||||||
config.playback.channels = AUDIO_DEVICE_CHANNELS;
|
config.playback.channels = AUDIO_DEVICE_CHANNELS;
|
||||||
config.capture.pDeviceID = NULL; // NULL for the default capture AUDIO.System.device.
|
config.capture.pDeviceID = NULL; // NULL for the default capture AUDIO.System.device.
|
||||||
config.capture.format = ma_format_s16;
|
config.capture.format = ma_format_s16;
|
||||||
config.capture.channels = 1;
|
config.capture.channels = 1;
|
||||||
config.sampleRate = AUDIO_DEVICE_SAMPLE_RATE;
|
config.sampleRate = AUDIO_DEVICE_SAMPLE_RATE;
|
||||||
config.dataCallback = OnSendAudioDataToDevice;
|
config.dataCallback = OnSendAudioDataToDevice;
|
||||||
config.pUserData = NULL;
|
config.pUserData = NULL;
|
||||||
|
|
||||||
result = ma_device_init(&AUDIO.System.context, &config, &AUDIO.System.device);
|
result = ma_device_init(&AUDIO.System.context, &config, &AUDIO.System.device);
|
||||||
if (result != MA_SUCCESS)
|
if (result != MA_SUCCESS)
|
||||||
|
@ -423,7 +460,7 @@ void InitAudioDevice(void)
|
||||||
|
|
||||||
// Mixing happens on a seperate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may
|
// Mixing happens on a seperate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may
|
||||||
// want to look at something a bit smarter later on to keep everything real-time, if that's necessary.
|
// want to look at something a bit smarter later on to keep everything real-time, if that's necessary.
|
||||||
if (ma_mutex_init(&AUDIO.System.context, &AUDIO.System.lock) != MA_SUCCESS)
|
if (ma_mutex_init(&AUDIO.System.lock) != MA_SUCCESS)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_ERROR, "AUDIO: Failed to create mutex for mixing");
|
TRACELOG(LOG_ERROR, "AUDIO: Failed to create mutex for mixing");
|
||||||
ma_device_uninit(&AUDIO.System.device);
|
ma_device_uninit(&AUDIO.System.device);
|
||||||
|
@ -432,11 +469,11 @@ void InitAudioDevice(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACELOG(LOG_INFO, "AUDIO: Device initialized successfully");
|
TRACELOG(LOG_INFO, "AUDIO: Device initialized successfully");
|
||||||
TRACELOG(LOG_INFO, " > Backend: miniaudio / %s", ma_get_backend_name(AUDIO.System.context.backend));
|
TRACELOG(LOG_INFO, " > Backend: miniaudio / %s", ma_get_backend_name(AUDIO.System.context.backend));
|
||||||
TRACELOG(LOG_INFO, " > Format: %s -> %s", ma_get_format_name(AUDIO.System.device.playback.format), ma_get_format_name(AUDIO.System.device.playback.internalFormat));
|
TRACELOG(LOG_INFO, " > Format: %s -> %s", ma_get_format_name(AUDIO.System.device.playback.format), ma_get_format_name(AUDIO.System.device.playback.internalFormat));
|
||||||
TRACELOG(LOG_INFO, " > Channels: %d -> %d", AUDIO.System.device.playback.channels, AUDIO.System.device.playback.internalChannels);
|
TRACELOG(LOG_INFO, " > Channels: %d -> %d", AUDIO.System.device.playback.channels, AUDIO.System.device.playback.internalChannels);
|
||||||
TRACELOG(LOG_INFO, " > Sample rate: %d -> %d", AUDIO.System.device.sampleRate, AUDIO.System.device.playback.internalSampleRate);
|
TRACELOG(LOG_INFO, " > Sample rate: %d -> %d", AUDIO.System.device.sampleRate, AUDIO.System.device.playback.internalSampleRate);
|
||||||
TRACELOG(LOG_INFO, " > Periods size: %d", AUDIO.System.device.playback.internalPeriodSizeInFrames*AUDIO.System.device.playback.internalPeriods);
|
TRACELOG(LOG_INFO, " > Periods size: %d", AUDIO.System.device.playback.internalPeriodSizeInFrames*AUDIO.System.device.playback.internalPeriods);
|
||||||
|
|
||||||
InitAudioBufferPool();
|
InitAudioBufferPool();
|
||||||
|
|
||||||
|
@ -486,7 +523,7 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
audioBuffer->data = RL_CALLOC(sizeInFrames*channels*ma_get_bytes_per_sample(format), 1);
|
if (sizeInFrames > 0) audioBuffer->data = RL_CALLOC(sizeInFrames*channels*ma_get_bytes_per_sample(format), 1);
|
||||||
|
|
||||||
// Audio data runs through a format converter
|
// Audio data runs through a format converter
|
||||||
ma_data_converter_config converterConfig = ma_data_converter_config_init(format, AUDIO_DEVICE_FORMAT, channels, AUDIO_DEVICE_CHANNELS, sampleRate, AUDIO_DEVICE_SAMPLE_RATE);
|
ma_data_converter_config converterConfig = ma_data_converter_config_init(format, AUDIO_DEVICE_FORMAT, channels, AUDIO_DEVICE_CHANNELS, sampleRate, AUDIO_DEVICE_SAMPLE_RATE);
|
||||||
|
@ -775,47 +812,52 @@ void ExportWave(Wave wave, const char *fileName)
|
||||||
// Export wave sample data to code (.h)
|
// Export wave sample data to code (.h)
|
||||||
void ExportWaveAsCode(Wave wave, const char *fileName)
|
void ExportWaveAsCode(Wave wave, const char *fileName)
|
||||||
{
|
{
|
||||||
#define BYTES_TEXT_PER_LINE 20
|
#ifndef TEXT_BYTES_PER_LINE
|
||||||
|
#define TEXT_BYTES_PER_LINE 20
|
||||||
char varFileName[256] = { 0 };
|
|
||||||
int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
|
|
||||||
|
|
||||||
FILE *txtFile = fopen(fileName, "wt");
|
|
||||||
|
|
||||||
if (txtFile != NULL)
|
|
||||||
{
|
|
||||||
fprintf(txtFile, "\n//////////////////////////////////////////////////////////////////////////////////\n");
|
|
||||||
fprintf(txtFile, "// //\n");
|
|
||||||
fprintf(txtFile, "// WaveAsCode exporter v1.0 - Wave data exported as an array of bytes //\n");
|
|
||||||
fprintf(txtFile, "// //\n");
|
|
||||||
fprintf(txtFile, "// more info and bugs-report: github.com/raysan5/raylib //\n");
|
|
||||||
fprintf(txtFile, "// feedback and support: ray[at]raylib.com //\n");
|
|
||||||
fprintf(txtFile, "// //\n");
|
|
||||||
fprintf(txtFile, "// Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n");
|
|
||||||
fprintf(txtFile, "// //\n");
|
|
||||||
fprintf(txtFile, "//////////////////////////////////////////////////////////////////////////////////\n\n");
|
|
||||||
|
|
||||||
#if !defined(RAUDIO_STANDALONE)
|
|
||||||
// Get file name from path and convert variable name to uppercase
|
|
||||||
strcpy(varFileName, GetFileNameWithoutExt(fileName));
|
|
||||||
for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; }
|
|
||||||
#else
|
|
||||||
strcpy(varFileName, fileName);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fprintf(txtFile, "// Wave data information\n");
|
int waveDataSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
|
||||||
fprintf(txtFile, "#define %s_SAMPLE_COUNT %u\n", varFileName, wave.sampleCount);
|
|
||||||
fprintf(txtFile, "#define %s_SAMPLE_RATE %u\n", varFileName, wave.sampleRate);
|
|
||||||
fprintf(txtFile, "#define %s_SAMPLE_SIZE %u\n", varFileName, wave.sampleSize);
|
|
||||||
fprintf(txtFile, "#define %s_CHANNELS %u\n\n", varFileName, wave.channels);
|
|
||||||
|
|
||||||
// Write byte data as hexadecimal text
|
// NOTE: Text data buffer size is estimated considering wave data size in bytes
|
||||||
fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize);
|
// and requiring 6 char bytes for every byte: "0x00, "
|
||||||
for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]);
|
char *txtData = (char *)RL_CALLOC(6*waveDataSize + 2000, sizeof(char));
|
||||||
fprintf(txtFile, "0x%x };\n", ((unsigned char *)wave.data)[dataSize - 1]);
|
|
||||||
|
|
||||||
fclose(txtFile);
|
int bytesCount = 0;
|
||||||
}
|
bytesCount += sprintf(txtData + bytesCount, "\n//////////////////////////////////////////////////////////////////////////////////\n");
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "// //\n");
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "// WaveAsCode exporter v1.0 - Wave data exported as an array of bytes //\n");
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "// //\n");
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "// more info and bugs-report: github.com/raysan5/raylib //\n");
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "// feedback and support: ray[at]raylib.com //\n");
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "// //\n");
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "// Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n");
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "// //\n");
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "//////////////////////////////////////////////////////////////////////////////////\n\n");
|
||||||
|
|
||||||
|
char varFileName[256] = { 0 };
|
||||||
|
#if !defined(RAUDIO_STANDALONE)
|
||||||
|
// Get file name from path and convert variable name to uppercase
|
||||||
|
strcpy(varFileName, GetFileNameWithoutExt(fileName));
|
||||||
|
for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; }
|
||||||
|
#else
|
||||||
|
strcpy(varFileName, fileName);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "// Wave data information\n");
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_COUNT %u\n", varFileName, wave.sampleCount);
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_RATE %u\n", varFileName, wave.sampleRate);
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_SIZE %u\n", varFileName, wave.sampleSize);
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "#define %s_CHANNELS %u\n\n", varFileName, wave.channels);
|
||||||
|
|
||||||
|
// Write byte data as hexadecimal text
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "static unsigned char %s_DATA[%i] = { ", varFileName, waveDataSize);
|
||||||
|
for (int i = 0; i < waveDataSize - 1; i++) bytesCount += sprintf(txtData + bytesCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]);
|
||||||
|
bytesCount += sprintf(txtData + bytesCount, "0x%x };\n", ((unsigned char *)wave.data)[waveDataSize - 1]);
|
||||||
|
|
||||||
|
// NOTE: Text data length exported is determined by '\0' (NULL) character
|
||||||
|
SaveFileText(fileName, txtData);
|
||||||
|
|
||||||
|
RL_FREE(txtData);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Play a sound
|
// Play a sound
|
||||||
|
@ -1041,6 +1083,27 @@ Music LoadMusicStream(const char *fileName)
|
||||||
bool musicLoaded = false;
|
bool musicLoaded = false;
|
||||||
|
|
||||||
if (false) { }
|
if (false) { }
|
||||||
|
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||||
|
else if (IsFileExtension(fileName, ".wav"))
|
||||||
|
{
|
||||||
|
drwav *ctxWav = RL_MALLOC(sizeof(drwav));
|
||||||
|
bool success = drwav_init_file(ctxWav, fileName, NULL);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
music.ctxType = MUSIC_AUDIO_WAV;
|
||||||
|
music.ctxData = ctxWav;
|
||||||
|
|
||||||
|
int sampleSize = ctxWav->bitsPerSample;
|
||||||
|
if (ctxWav->bitsPerSample == 24) sampleSize = 16; // Forcing conversion to s16 on UpdateMusicStream()
|
||||||
|
|
||||||
|
music.stream = InitAudioStream(ctxWav->sampleRate, sampleSize, ctxWav->channels);
|
||||||
|
music.sampleCount = (unsigned int)ctxWav->totalPCMFrameCount*ctxWav->channels;
|
||||||
|
music.looping = true; // Looping enabled by default
|
||||||
|
musicLoaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_OGG)
|
#if defined(SUPPORT_FILEFORMAT_OGG)
|
||||||
else if (IsFileExtension(fileName, ".ogg"))
|
else if (IsFileExtension(fileName, ".ogg"))
|
||||||
{
|
{
|
||||||
|
@ -1055,7 +1118,7 @@ Music LoadMusicStream(const char *fileName)
|
||||||
// OGG bit rate defaults to 16 bit, it's enough for compressed format
|
// OGG bit rate defaults to 16 bit, it's enough for compressed format
|
||||||
music.stream = InitAudioStream(info.sample_rate, 16, info.channels);
|
music.stream = InitAudioStream(info.sample_rate, 16, info.channels);
|
||||||
music.sampleCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData)*info.channels;
|
music.sampleCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData)*info.channels;
|
||||||
music.loopCount = 0; // Infinite loop by default
|
music.looping = true; // Looping enabled by default
|
||||||
musicLoaded = true;
|
musicLoaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1072,7 +1135,7 @@ Music LoadMusicStream(const char *fileName)
|
||||||
|
|
||||||
music.stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels);
|
music.stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels);
|
||||||
music.sampleCount = (unsigned int)ctxFlac->totalSampleCount;
|
music.sampleCount = (unsigned int)ctxFlac->totalSampleCount;
|
||||||
music.loopCount = 0; // Infinite loop by default
|
music.looping = true; // Looping enabled by default
|
||||||
musicLoaded = true;
|
musicLoaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1091,7 +1154,7 @@ Music LoadMusicStream(const char *fileName)
|
||||||
|
|
||||||
music.stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels);
|
music.stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels);
|
||||||
music.sampleCount = (unsigned int)drmp3_get_pcm_frame_count(ctxMp3)*ctxMp3->channels;
|
music.sampleCount = (unsigned int)drmp3_get_pcm_frame_count(ctxMp3)*ctxMp3->channels;
|
||||||
music.loopCount = 0; // Infinite loop by default
|
music.looping = true; // Looping enabled by default
|
||||||
musicLoaded = true;
|
musicLoaded = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1111,7 +1174,7 @@ Music LoadMusicStream(const char *fileName)
|
||||||
// NOTE: Only stereo is supported for XM
|
// NOTE: Only stereo is supported for XM
|
||||||
music.stream = InitAudioStream(48000, 16, 2);
|
music.stream = InitAudioStream(48000, 16, 2);
|
||||||
music.sampleCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm)*2;
|
music.sampleCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm)*2;
|
||||||
music.loopCount = 0; // Infinite loop by default
|
music.looping = true; // Looping enabled by default
|
||||||
jar_xm_reset(ctxXm); // make sure we start at the beginning of the song
|
jar_xm_reset(ctxXm); // make sure we start at the beginning of the song
|
||||||
musicLoaded = true;
|
musicLoaded = true;
|
||||||
|
|
||||||
|
@ -1134,17 +1197,21 @@ Music LoadMusicStream(const char *fileName)
|
||||||
// NOTE: Only stereo is supported for MOD
|
// NOTE: Only stereo is supported for MOD
|
||||||
music.stream = InitAudioStream(48000, 16, 2);
|
music.stream = InitAudioStream(48000, 16, 2);
|
||||||
music.sampleCount = (unsigned int)jar_mod_max_samples(ctxMod)*2;
|
music.sampleCount = (unsigned int)jar_mod_max_samples(ctxMod)*2;
|
||||||
music.loopCount = 0; // Infinite loop by default
|
music.looping = true; // Looping enabled by default
|
||||||
musicLoaded = true;
|
musicLoaded = true;
|
||||||
|
|
||||||
music.ctxData = ctxMod;
|
music.ctxData = ctxMod;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
else TRACELOG(LOG_WARNING, "STREAM: [%s] Fileformat not supported", fileName);
|
||||||
|
|
||||||
if (!musicLoaded)
|
if (!musicLoaded)
|
||||||
{
|
{
|
||||||
if (false) { }
|
if (false) { }
|
||||||
|
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||||
|
else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData);
|
||||||
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_OGG)
|
#if defined(SUPPORT_FILEFORMAT_OGG)
|
||||||
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
|
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1182,6 +1249,9 @@ void UnloadMusicStream(Music music)
|
||||||
CloseAudioStream(music.stream);
|
CloseAudioStream(music.stream);
|
||||||
|
|
||||||
if (false) { }
|
if (false) { }
|
||||||
|
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||||
|
else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData);
|
||||||
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_OGG)
|
#if defined(SUPPORT_FILEFORMAT_OGG)
|
||||||
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
|
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1233,6 +1303,9 @@ void StopMusicStream(Music music)
|
||||||
|
|
||||||
switch (music.ctxType)
|
switch (music.ctxType)
|
||||||
{
|
{
|
||||||
|
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||||
|
case MUSIC_AUDIO_WAV: drwav_seek_to_pcm_frame((drwav *)music.ctxData, 0); break;
|
||||||
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_OGG)
|
#if defined(SUPPORT_FILEFORMAT_OGG)
|
||||||
case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break;
|
case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1277,6 +1350,15 @@ void UpdateMusicStream(Music music)
|
||||||
|
|
||||||
switch (music.ctxType)
|
switch (music.ctxType)
|
||||||
{
|
{
|
||||||
|
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||||
|
case MUSIC_AUDIO_WAV:
|
||||||
|
{
|
||||||
|
// NOTE: Returns the number of samples to process (not required)
|
||||||
|
if (music.stream.sampleSize == 16) drwav_read_pcm_frames_s16((drwav *)music.ctxData, samplesCount/music.stream.channels, (short *)pcm);
|
||||||
|
else if (music.stream.sampleSize == 32) drwav_read_pcm_frames_f32((drwav *)music.ctxData, samplesCount/music.stream.channels, (float *)pcm);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_OGG)
|
#if defined(SUPPORT_FILEFORMAT_OGG)
|
||||||
case MUSIC_AUDIO_OGG:
|
case MUSIC_AUDIO_OGG:
|
||||||
{
|
{
|
||||||
|
@ -1340,15 +1422,8 @@ void UpdateMusicStream(Music music)
|
||||||
// Reset audio stream for looping
|
// Reset audio stream for looping
|
||||||
if (streamEnding)
|
if (streamEnding)
|
||||||
{
|
{
|
||||||
StopMusicStream(music); // Stop music (and reset)
|
StopMusicStream(music); // Stop music (and reset)
|
||||||
|
if (music.looping) PlayMusicStream(music); // Play again
|
||||||
// Decrease loopCount to stop when required
|
|
||||||
if (music.loopCount > 1)
|
|
||||||
{
|
|
||||||
music.loopCount--; // Decrease loop count
|
|
||||||
PlayMusicStream(music); // Play again
|
|
||||||
}
|
|
||||||
else if (music.loopCount == 0) PlayMusicStream(music);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1376,13 +1451,6 @@ void SetMusicPitch(Music music, float pitch)
|
||||||
SetAudioStreamPitch(music.stream, pitch);
|
SetAudioStreamPitch(music.stream, pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set music loop count (loop repeats)
|
|
||||||
// NOTE: If set to 0, means infinite loop
|
|
||||||
void SetMusicLoopCount(Music music, int count)
|
|
||||||
{
|
|
||||||
music.loopCount = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get music time length (in seconds)
|
// Get music time length (in seconds)
|
||||||
float GetMusicTimeLength(Music music)
|
float GetMusicTimeLength(Music music)
|
||||||
{
|
{
|
||||||
|
@ -1663,7 +1731,7 @@ static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, f
|
||||||
// detail to remember here is that we never, ever attempt to read more input data than is required for the specified number of output
|
// detail to remember here is that we never, ever attempt to read more input data than is required for the specified number of output
|
||||||
// frames. This can be achieved with ma_data_converter_get_required_input_frame_count().
|
// frames. This can be achieved with ma_data_converter_get_required_input_frame_count().
|
||||||
ma_uint8 inputBuffer[4096];
|
ma_uint8 inputBuffer[4096];
|
||||||
ma_uint32 inputBufferFrameCap = sizeof(inputBuffer) / ma_get_bytes_per_frame(audioBuffer->converter.config.formatIn, audioBuffer->converter.config.channelsIn);
|
ma_uint32 inputBufferFrameCap = sizeof(inputBuffer)/ma_get_bytes_per_frame(audioBuffer->converter.config.formatIn, audioBuffer->converter.config.channelsIn);
|
||||||
|
|
||||||
ma_uint32 totalOutputFramesProcessed = 0;
|
ma_uint32 totalOutputFramesProcessed = 0;
|
||||||
while (totalOutputFramesProcessed < frameCount)
|
while (totalOutputFramesProcessed < frameCount)
|
||||||
|
@ -1806,6 +1874,7 @@ static void InitAudioBufferPool(void)
|
||||||
// Dummy buffers
|
// Dummy buffers
|
||||||
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
|
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
|
||||||
{
|
{
|
||||||
|
// WARNING: An empty audioBuffer is created (data = 0)
|
||||||
AUDIO.MultiChannel.pool[i] = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO_DEVICE_SAMPLE_RATE, 0, AUDIO_BUFFER_USAGE_STATIC);
|
AUDIO.MultiChannel.pool[i] = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO_DEVICE_SAMPLE_RATE, 0, AUDIO_BUFFER_USAGE_STATIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1816,133 +1885,36 @@ static void InitAudioBufferPool(void)
|
||||||
// Close the audio buffers pool
|
// Close the audio buffers pool
|
||||||
static void CloseAudioBufferPool(void)
|
static void CloseAudioBufferPool(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
|
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) RL_FREE(AUDIO.MultiChannel.pool[i]);
|
||||||
{
|
|
||||||
RL_FREE(AUDIO.MultiChannel.pool[i]->data);
|
|
||||||
RL_FREE(AUDIO.MultiChannel.pool[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_WAV)
|
#if defined(SUPPORT_FILEFORMAT_WAV)
|
||||||
// Load WAV file into Wave structure
|
// Load WAV file into Wave structure
|
||||||
static Wave LoadWAV(const char *fileName)
|
static Wave LoadWAV(const char *fileName)
|
||||||
{
|
{
|
||||||
// Basic WAV headers structs
|
|
||||||
typedef struct {
|
|
||||||
char chunkID[4];
|
|
||||||
int chunkSize;
|
|
||||||
char format[4];
|
|
||||||
} WAVRiffHeader;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char subChunkID[4];
|
|
||||||
int subChunkSize;
|
|
||||||
short audioFormat;
|
|
||||||
short numChannels;
|
|
||||||
int sampleRate;
|
|
||||||
int byteRate;
|
|
||||||
short blockAlign;
|
|
||||||
short bitsPerSample;
|
|
||||||
} WAVFormat;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char subChunkID[4];
|
|
||||||
int subChunkSize;
|
|
||||||
} WAVData;
|
|
||||||
|
|
||||||
WAVRiffHeader wavRiffHeader = { 0 };
|
|
||||||
WAVFormat wavFormat = { 0 };
|
|
||||||
WAVData wavData = { 0 };
|
|
||||||
|
|
||||||
Wave wave = { 0 };
|
Wave wave = { 0 };
|
||||||
FILE *wavFile = NULL;
|
|
||||||
|
|
||||||
wavFile = fopen(fileName, "rb");
|
// Loading WAV from memory to avoid FILE accesses
|
||||||
|
unsigned int fileSize = 0;
|
||||||
|
unsigned char *fileData = LoadFileData(fileName, &fileSize);
|
||||||
|
|
||||||
if (wavFile == NULL)
|
drwav wav = { 0 };
|
||||||
|
|
||||||
|
bool success = drwav_init_memory(&wav, fileData, fileSize, NULL);
|
||||||
|
|
||||||
|
if (success)
|
||||||
{
|
{
|
||||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open WAV file", fileName);
|
wave.sampleCount = wav.totalPCMFrameCount*wav.channels;
|
||||||
wave.data = NULL;
|
wave.sampleRate = wav.sampleRate;
|
||||||
|
wave.sampleSize = 16; // NOTE: We are forcing conversion to 16bit
|
||||||
|
wave.channels = wav.channels;
|
||||||
|
wave.data = (short *)RL_MALLOC(wave.sampleCount*sizeof(short));
|
||||||
|
drwav_read_pcm_frames_s16(&wav, wav.totalPCMFrameCount, wave.data);
|
||||||
}
|
}
|
||||||
else
|
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load WAV data", fileName);
|
||||||
{
|
|
||||||
// Read in the first chunk into the struct
|
|
||||||
fread(&wavRiffHeader, sizeof(WAVRiffHeader), 1, wavFile);
|
|
||||||
|
|
||||||
// Check for RIFF and WAVE tags
|
drwav_uninit(&wav);
|
||||||
if ((wavRiffHeader.chunkID[0] != 'R') ||
|
RL_FREE(fileData);
|
||||||
(wavRiffHeader.chunkID[1] != 'I') ||
|
|
||||||
(wavRiffHeader.chunkID[2] != 'F') ||
|
|
||||||
(wavRiffHeader.chunkID[3] != 'F') ||
|
|
||||||
(wavRiffHeader.format[0] != 'W') ||
|
|
||||||
(wavRiffHeader.format[1] != 'A') ||
|
|
||||||
(wavRiffHeader.format[2] != 'V') ||
|
|
||||||
(wavRiffHeader.format[3] != 'E'))
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_WARNING, "WAVE: [%s] RIFF or WAVE header are not valid", fileName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Read in the 2nd chunk for the wave info
|
|
||||||
fread(&wavFormat, sizeof(WAVFormat), 1, wavFile);
|
|
||||||
|
|
||||||
// Check for fmt tag
|
|
||||||
if ((wavFormat.subChunkID[0] != 'f') || (wavFormat.subChunkID[1] != 'm') ||
|
|
||||||
(wavFormat.subChunkID[2] != 't') || (wavFormat.subChunkID[3] != ' '))
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_WARNING, "WAVE: [%s] Wave format header is not valid", fileName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Check for extra parameters;
|
|
||||||
if (wavFormat.subChunkSize > 16) fseek(wavFile, sizeof(short), SEEK_CUR);
|
|
||||||
|
|
||||||
// Read in the the last byte of data before the sound file
|
|
||||||
fread(&wavData, sizeof(WAVData), 1, wavFile);
|
|
||||||
|
|
||||||
// Check for data tag
|
|
||||||
if ((wavData.subChunkID[0] != 'd') || (wavData.subChunkID[1] != 'a') ||
|
|
||||||
(wavData.subChunkID[2] != 't') || (wavData.subChunkID[3] != 'a'))
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_WARNING, "WAVE: [%s] Data header is not valid", fileName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Allocate memory for data
|
|
||||||
wave.data = RL_MALLOC(wavData.subChunkSize);
|
|
||||||
|
|
||||||
// Read in the sound data into the soundData variable
|
|
||||||
fread(wave.data, wavData.subChunkSize, 1, wavFile);
|
|
||||||
|
|
||||||
// Store wave parameters
|
|
||||||
wave.sampleRate = wavFormat.sampleRate;
|
|
||||||
wave.sampleSize = wavFormat.bitsPerSample;
|
|
||||||
wave.channels = wavFormat.numChannels;
|
|
||||||
|
|
||||||
// NOTE: Only support 8 bit, 16 bit and 32 bit sample sizes
|
|
||||||
if ((wave.sampleSize != 8) && (wave.sampleSize != 16) && (wave.sampleSize != 32))
|
|
||||||
{
|
|
||||||
TRACELOG(LOG_WARNING, "WAVE: [%s] Sample size (%ibit) not supported, converted to 16bit", fileName, wave.sampleSize);
|
|
||||||
WaveFormat(&wave, wave.sampleRate, 16, wave.channels);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Only support up to 2 channels (mono, stereo)
|
|
||||||
if (wave.channels > 2)
|
|
||||||
{
|
|
||||||
WaveFormat(&wave, wave.sampleRate, wave.sampleSize, 2);
|
|
||||||
TRACELOG(LOG_WARNING, "WAVE: [%s] Channels number (%i) not supported, converted to 2 channels", fileName, wave.channels);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: subChunkSize comes in bytes, we need to translate it to number of samples
|
|
||||||
wave.sampleCount = (wavData.subChunkSize/(wave.sampleSize/8))/wave.channels;
|
|
||||||
|
|
||||||
TRACELOG(LOG_INFO, "WAVE: [%s] File loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(wavFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
return wave;
|
return wave;
|
||||||
}
|
}
|
||||||
|
@ -1950,81 +1922,24 @@ static Wave LoadWAV(const char *fileName)
|
||||||
// Save wave data as WAV file
|
// Save wave data as WAV file
|
||||||
static int SaveWAV(Wave wave, const char *fileName)
|
static int SaveWAV(Wave wave, const char *fileName)
|
||||||
{
|
{
|
||||||
int success = 0;
|
drwav wav = { 0 };
|
||||||
int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
|
drwav_data_format format = { 0 };
|
||||||
|
format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
|
||||||
|
format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes.
|
||||||
|
format.channels = wave.channels;
|
||||||
|
format.sampleRate = wave.sampleRate;
|
||||||
|
format.bitsPerSample = wave.sampleSize;
|
||||||
|
|
||||||
// Basic WAV headers structs
|
drwav_init_file_write(&wav, fileName, &format, NULL);
|
||||||
typedef struct {
|
//drwav_init_memory_write(&wav, &fileData, &fileDataSize, &format, NULL); // TODO: Memory version
|
||||||
char chunkID[4];
|
drwav_write_pcm_frames(&wav, wave.sampleCount/wave.channels, wave.data);
|
||||||
int chunkSize;
|
|
||||||
char format[4];
|
|
||||||
} RiffHeader;
|
|
||||||
|
|
||||||
typedef struct {
|
drwav_uninit(&wav);
|
||||||
char subChunkID[4];
|
|
||||||
int subChunkSize;
|
|
||||||
short audioFormat;
|
|
||||||
short numChannels;
|
|
||||||
int sampleRate;
|
|
||||||
int byteRate;
|
|
||||||
short blockAlign;
|
|
||||||
short bitsPerSample;
|
|
||||||
} WaveFormat;
|
|
||||||
|
|
||||||
typedef struct {
|
// SaveFileData(fileName, fileData, fileDataSize);
|
||||||
char subChunkID[4];
|
//drwav_free(fileData, NULL);
|
||||||
int subChunkSize;
|
|
||||||
} WaveData;
|
|
||||||
|
|
||||||
FILE *wavFile = fopen(fileName, "wb");
|
return true;
|
||||||
|
|
||||||
if (wavFile == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open audio file", fileName);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RiffHeader riffHeader;
|
|
||||||
WaveFormat waveFormat;
|
|
||||||
WaveData waveData;
|
|
||||||
|
|
||||||
// Fill structs with data
|
|
||||||
riffHeader.chunkID[0] = 'R';
|
|
||||||
riffHeader.chunkID[1] = 'I';
|
|
||||||
riffHeader.chunkID[2] = 'F';
|
|
||||||
riffHeader.chunkID[3] = 'F';
|
|
||||||
riffHeader.chunkSize = 44 - 4 + wave.sampleCount*wave.sampleSize/8;
|
|
||||||
riffHeader.format[0] = 'W';
|
|
||||||
riffHeader.format[1] = 'A';
|
|
||||||
riffHeader.format[2] = 'V';
|
|
||||||
riffHeader.format[3] = 'E';
|
|
||||||
|
|
||||||
waveFormat.subChunkID[0] = 'f';
|
|
||||||
waveFormat.subChunkID[1] = 'm';
|
|
||||||
waveFormat.subChunkID[2] = 't';
|
|
||||||
waveFormat.subChunkID[3] = ' ';
|
|
||||||
waveFormat.subChunkSize = 16;
|
|
||||||
waveFormat.audioFormat = 1;
|
|
||||||
waveFormat.numChannels = wave.channels;
|
|
||||||
waveFormat.sampleRate = wave.sampleRate;
|
|
||||||
waveFormat.byteRate = wave.sampleRate*wave.sampleSize/8;
|
|
||||||
waveFormat.blockAlign = wave.sampleSize/8;
|
|
||||||
waveFormat.bitsPerSample = wave.sampleSize;
|
|
||||||
|
|
||||||
waveData.subChunkID[0] = 'd';
|
|
||||||
waveData.subChunkID[1] = 'a';
|
|
||||||
waveData.subChunkID[2] = 't';
|
|
||||||
waveData.subChunkID[3] = 'a';
|
|
||||||
waveData.subChunkSize = dataSize;
|
|
||||||
|
|
||||||
fwrite(&riffHeader, sizeof(RiffHeader), 1, wavFile);
|
|
||||||
fwrite(&waveFormat, sizeof(WaveFormat), 1, wavFile);
|
|
||||||
fwrite(&waveData, sizeof(WaveData), 1, wavFile);
|
|
||||||
|
|
||||||
success = fwrite(wave.data, dataSize, 1, wavFile);
|
|
||||||
|
|
||||||
fclose(wavFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If all data has been written correctly to file, success = 1
|
|
||||||
return success;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -2035,7 +1950,11 @@ static Wave LoadOGG(const char *fileName)
|
||||||
{
|
{
|
||||||
Wave wave = { 0 };
|
Wave wave = { 0 };
|
||||||
|
|
||||||
stb_vorbis *oggFile = stb_vorbis_open_filename(fileName, NULL, NULL);
|
// Loading OGG from memory to avoid FILE accesses
|
||||||
|
unsigned int fileSize = 0;
|
||||||
|
unsigned char *fileData = LoadFileData(fileName, &fileSize);
|
||||||
|
|
||||||
|
stb_vorbis *oggFile = stb_vorbis_open_memory(fileData, fileSize, NULL, NULL);
|
||||||
|
|
||||||
if (oggFile == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open OGG file", fileName);
|
if (oggFile == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open OGG file", fileName);
|
||||||
else
|
else
|
||||||
|
@ -2059,6 +1978,8 @@ static Wave LoadOGG(const char *fileName)
|
||||||
stb_vorbis_close(oggFile);
|
stb_vorbis_close(oggFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RL_FREE(fileData);
|
||||||
|
|
||||||
return wave;
|
return wave;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2070,9 +1991,13 @@ static Wave LoadFLAC(const char *fileName)
|
||||||
{
|
{
|
||||||
Wave wave = { 0 };
|
Wave wave = { 0 };
|
||||||
|
|
||||||
|
// Loading FLAC from memory to avoid FILE accesses
|
||||||
|
unsigned int fileSize = 0;
|
||||||
|
unsigned char *fileData = LoadFileData(fileName, &fileSize);
|
||||||
|
|
||||||
// Decode an entire FLAC file in one go
|
// Decode an entire FLAC file in one go
|
||||||
unsigned long long int totalSampleCount = 0;
|
unsigned long long int totalSampleCount = 0;
|
||||||
wave.data = drflac_open_file_and_read_pcm_frames_s16(fileName, &wave.channels, &wave.sampleRate, &totalSampleCount);
|
wave.data = drflac_open_memory_and_read_pcm_frames_s16(fileData, fileSize, &wave.channels, &wave.sampleRate, &totalSampleCount);
|
||||||
|
|
||||||
if (wave.data == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load FLAC data", fileName);
|
if (wave.data == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load FLAC data", fileName);
|
||||||
else
|
else
|
||||||
|
@ -2080,12 +2005,11 @@ static Wave LoadFLAC(const char *fileName)
|
||||||
wave.sampleCount = (unsigned int)totalSampleCount;
|
wave.sampleCount = (unsigned int)totalSampleCount;
|
||||||
wave.sampleSize = 16;
|
wave.sampleSize = 16;
|
||||||
|
|
||||||
// NOTE: Only support up to 2 channels (mono, stereo)
|
|
||||||
if (wave.channels > 2) TRACELOG(LOG_WARNING, "WAVE: [%s] FLAC channels number (%i) not supported", fileName, wave.channels);
|
|
||||||
|
|
||||||
TRACELOG(LOG_INFO, "WAVE: [%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
|
TRACELOG(LOG_INFO, "WAVE: [%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RL_FREE(fileData);
|
||||||
|
|
||||||
return wave;
|
return wave;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2097,10 +2021,14 @@ static Wave LoadMP3(const char *fileName)
|
||||||
{
|
{
|
||||||
Wave wave = { 0 };
|
Wave wave = { 0 };
|
||||||
|
|
||||||
|
// Loading MP3 from memory to avoid FILE accesses
|
||||||
|
unsigned int fileSize = 0;
|
||||||
|
unsigned char *fileData = LoadFileData(fileName, &fileSize);
|
||||||
|
|
||||||
// Decode an entire MP3 file in one go
|
// Decode an entire MP3 file in one go
|
||||||
unsigned long int totalFrameCount = 0;
|
unsigned long long int totalFrameCount = 0;
|
||||||
drmp3_config config = { 0 };
|
drmp3_config config = { 0 };
|
||||||
wave.data = drmp3_open_file_and_read_f32(fileName, &config, &totalFrameCount);
|
wave.data = drmp3_open_memory_and_read_f32(fileData, fileSize, &config, &totalFrameCount);
|
||||||
|
|
||||||
if (wave.data == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load MP3 data", fileName);
|
if (wave.data == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load MP3 data", fileName);
|
||||||
else
|
else
|
||||||
|
@ -2116,6 +2044,8 @@ static Wave LoadMP3(const char *fileName)
|
||||||
TRACELOG(LOG_INFO, "WAVE: [%s] MP3 file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
|
TRACELOG(LOG_INFO, "WAVE: [%s] MP3 file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RL_FREE(fileData);
|
||||||
|
|
||||||
return wave;
|
return wave;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2123,7 +2053,7 @@ static Wave LoadMP3(const char *fileName)
|
||||||
// Some required functions for audio standalone module version
|
// Some required functions for audio standalone module version
|
||||||
#if defined(RAUDIO_STANDALONE)
|
#if defined(RAUDIO_STANDALONE)
|
||||||
// Check file extension
|
// Check file extension
|
||||||
bool IsFileExtension(const char *fileName, const char *ext)
|
static bool IsFileExtension(const char *fileName, const char *ext)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
const char *fileExt;
|
const char *fileExt;
|
||||||
|
@ -2135,6 +2065,89 @@ bool IsFileExtension(const char *fileName, const char *ext)
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load data from file into a buffer
|
||||||
|
static unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead)
|
||||||
|
{
|
||||||
|
unsigned char *data = NULL;
|
||||||
|
*bytesRead = 0;
|
||||||
|
|
||||||
|
if (fileName != NULL)
|
||||||
|
{
|
||||||
|
FILE *file = fopen(fileName, "rb");
|
||||||
|
|
||||||
|
if (file != NULL)
|
||||||
|
{
|
||||||
|
// WARNING: On binary streams SEEK_END could not be found,
|
||||||
|
// using fseek() and ftell() could not work in some (rare) cases
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
int size = ftell(file);
|
||||||
|
fseek(file, 0, SEEK_SET);
|
||||||
|
|
||||||
|
if (size > 0)
|
||||||
|
{
|
||||||
|
data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char));
|
||||||
|
|
||||||
|
// NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements]
|
||||||
|
unsigned int count = (unsigned int)fread(data, sizeof(unsigned char), size, file);
|
||||||
|
*bytesRead = count;
|
||||||
|
|
||||||
|
if (count != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded", fileName);
|
||||||
|
else TRACELOG(LOG_INFO, "FILEIO: [%s] File loaded successfully", fileName);
|
||||||
|
}
|
||||||
|
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read file", fileName);
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
|
||||||
|
}
|
||||||
|
else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save data to file from buffer
|
||||||
|
static void SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite)
|
||||||
|
{
|
||||||
|
if (fileName != NULL)
|
||||||
|
{
|
||||||
|
FILE *file = fopen(fileName, "wb");
|
||||||
|
|
||||||
|
if (file != NULL)
|
||||||
|
{
|
||||||
|
unsigned int count = (unsigned int)fwrite(data, sizeof(unsigned char), bytesToWrite, file);
|
||||||
|
|
||||||
|
if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write file", fileName);
|
||||||
|
else if (count != bytesToWrite) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName);
|
||||||
|
else TRACELOG(LOG_INFO, "FILEIO: [%s] File saved successfully", fileName);
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
|
||||||
|
}
|
||||||
|
else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save text data to file (write), string must be '\0' terminated
|
||||||
|
static void SaveFileText(const char *fileName, char *text)
|
||||||
|
{
|
||||||
|
if (fileName != NULL)
|
||||||
|
{
|
||||||
|
FILE *file = fopen(fileName, "wt");
|
||||||
|
|
||||||
|
if (file != NULL)
|
||||||
|
{
|
||||||
|
int count = fprintf(file, "%s", text);
|
||||||
|
|
||||||
|
if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write text file", fileName);
|
||||||
|
else TRACELOG(LOG_INFO, "FILEIO: [%s] Text file saved successfully", fileName);
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
|
||||||
|
}
|
||||||
|
else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#undef AudioBuffer
|
#undef AudioBuffer
|
||||||
|
|
|
@ -255,14 +255,6 @@ func SetMusicPitch(music Music, pitch float32) {
|
||||||
C.SetMusicPitch(cmusic, cpitch)
|
C.SetMusicPitch(cmusic, cpitch)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMusicLoopCount - Set music loop count (loop repeats)
|
|
||||||
// NOTE: If set to -1, means infinite loop
|
|
||||||
func SetMusicLoopCount(music Music, count int32) {
|
|
||||||
cmusic := *(*C.Music)(unsafe.Pointer(&music))
|
|
||||||
ccount := (C.int)(count)
|
|
||||||
C.SetMusicLoopCount(cmusic, ccount)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMusicTimeLength - Get music time length (in seconds)
|
// GetMusicTimeLength - Get music time length (in seconds)
|
||||||
func GetMusicTimeLength(music Music) float32 {
|
func GetMusicTimeLength(music Music) float32 {
|
||||||
cmusic := *(*C.Music)(unsafe.Pointer(&music))
|
cmusic := *(*C.Music)(unsafe.Pointer(&music))
|
||||||
|
|
|
@ -111,8 +111,8 @@ typedef struct Music {
|
||||||
int ctxType; // Type of music context (audio filetype)
|
int ctxType; // Type of music context (audio filetype)
|
||||||
void *ctxData; // Audio context data, depends on type
|
void *ctxData; // Audio context data, depends on type
|
||||||
|
|
||||||
|
bool looping; // Music looping enable
|
||||||
unsigned int sampleCount; // Total number of samples
|
unsigned int sampleCount; // Total number of samples
|
||||||
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
|
|
||||||
|
|
||||||
AudioStream stream; // Audio stream
|
AudioStream stream; // Audio stream
|
||||||
} Music;
|
} Music;
|
||||||
|
@ -173,7 +173,6 @@ void ResumeMusicStream(Music music); // Resume playin
|
||||||
bool IsMusicPlaying(Music music); // Check if music is playing
|
bool IsMusicPlaying(Music music); // Check if music is playing
|
||||||
void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
|
void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
|
||||||
void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
|
void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
|
||||||
void SetMusicLoopCount(Music music, int count); // Set music loop count (loop repeats)
|
|
||||||
float GetMusicTimeLength(Music music); // Get music time length (in seconds)
|
float GetMusicTimeLength(Music music); // Get music time length (in seconds)
|
||||||
float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
|
float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,11 @@ Example:
|
||||||
*/
|
*/
|
||||||
package rl
|
package rl
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include "raylib.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
"io"
|
"io"
|
||||||
|
@ -108,7 +113,7 @@ type AudioStream struct {
|
||||||
// Number of channels (1-mono, 2-stereo)
|
// Number of channels (1-mono, 2-stereo)
|
||||||
Channels uint32
|
Channels uint32
|
||||||
// Buffer
|
// Buffer
|
||||||
Buffer *_Ctype_struct_rAudioBuffer
|
Buffer *C.rAudioBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// newAudioStreamFromPointer - Returns new AudioStream from pointer
|
// newAudioStreamFromPointer - Returns new AudioStream from pointer
|
||||||
|
@ -910,9 +915,12 @@ type BlendMode int32
|
||||||
|
|
||||||
// Color blending modes (pre-defined)
|
// Color blending modes (pre-defined)
|
||||||
const (
|
const (
|
||||||
BlendAlpha BlendMode = iota
|
BlendAlpha BlendMode = iota // Blend textures considering alpha (default)
|
||||||
BlendAdditive
|
BlendAdditive // Blend textures adding colors
|
||||||
BlendMultiplied
|
BlendMultiplied // Blend textures multiplying colors
|
||||||
|
BlendAddColors // Blend textures adding colors (alternative)
|
||||||
|
BlendSubtractColors // Blend textures subtracting colors (alternative)
|
||||||
|
BlendCustom // Blend textures using custom src/dst factors (use SetBlendModeCustom())
|
||||||
)
|
)
|
||||||
|
|
||||||
// Shader type (generic shader)
|
// Shader type (generic shader)
|
||||||
|
@ -1086,17 +1094,26 @@ func newImageFromPointer(ptr unsafe.Pointer) *Image {
|
||||||
// NewImageFromImage - Returns new Image from Go image.Image
|
// NewImageFromImage - Returns new Image from Go image.Image
|
||||||
func NewImageFromImage(img image.Image) *Image {
|
func NewImageFromImage(img image.Image) *Image {
|
||||||
size := img.Bounds().Size()
|
size := img.Bounds().Size()
|
||||||
pixels := make([]Color, size.X*size.Y)
|
|
||||||
|
cx := (C.int)(size.X)
|
||||||
|
cy := (C.int)(size.Y)
|
||||||
|
ccolor := White.cptr()
|
||||||
|
ret := C.GenImageColor(cx, cy, *ccolor)
|
||||||
|
|
||||||
for y := 0; y < size.Y; y++ {
|
for y := 0; y < size.Y; y++ {
|
||||||
for x := 0; x < size.X; x++ {
|
for x := 0; x < size.X; x++ {
|
||||||
color := img.At(x, y)
|
color := img.At(x, y)
|
||||||
r, g, b, a := color.RGBA()
|
r, g, b, a := color.RGBA()
|
||||||
pixels[x+y*size.X] = NewColor(uint8(r), uint8(g), uint8(b), uint8(a))
|
rcolor := NewColor(uint8(r), uint8(g), uint8(b), uint8(a))
|
||||||
|
ccolor = rcolor.cptr()
|
||||||
|
|
||||||
|
cx = (C.int)(x)
|
||||||
|
cy = (C.int)(y)
|
||||||
|
C.ImageDrawPixel(&ret, cx, cy, *ccolor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
v := newImageFromPointer(unsafe.Pointer(&ret))
|
||||||
return LoadImageEx(pixels, int32(size.X), int32(size.Y))
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Texture2D type, bpp always RGBA (32bit)
|
// Texture2D type, bpp always RGBA (32bit)
|
||||||
|
|
|
@ -99,8 +99,6 @@
|
||||||
#define DEG2RAD (PI/180.0f)
|
#define DEG2RAD (PI/180.0f)
|
||||||
#define RAD2DEG (180.0f/PI)
|
#define RAD2DEG (180.0f/PI)
|
||||||
|
|
||||||
#define MAX_TOUCH_POINTS 10 // Maximum number of touch points supported
|
|
||||||
|
|
||||||
// Allow custom memory allocators
|
// Allow custom memory allocators
|
||||||
#ifndef RL_MALLOC
|
#ifndef RL_MALLOC
|
||||||
#define RL_MALLOC(sz) malloc(sz)
|
#define RL_MALLOC(sz) malloc(sz)
|
||||||
|
@ -159,6 +157,7 @@
|
||||||
#define SubText TextSubtext
|
#define SubText TextSubtext
|
||||||
#define ShowWindow UnhideWindow
|
#define ShowWindow UnhideWindow
|
||||||
#define LoadText LoadFileText
|
#define LoadText LoadFileText
|
||||||
|
//#define Fade(c, a) ColorAlpha(c, a)
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Structures Definition
|
// Structures Definition
|
||||||
|
@ -442,8 +441,8 @@ typedef struct Music {
|
||||||
int ctxType; // Type of music context (audio filetype)
|
int ctxType; // Type of music context (audio filetype)
|
||||||
void *ctxData; // Audio context data, depends on type
|
void *ctxData; // Audio context data, depends on type
|
||||||
|
|
||||||
|
bool looping; // Music looping enable
|
||||||
unsigned int sampleCount; // Total number of samples
|
unsigned int sampleCount; // Total number of samples
|
||||||
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
|
|
||||||
|
|
||||||
AudioStream stream; // Audio stream
|
AudioStream stream; // Audio stream
|
||||||
} Music;
|
} Music;
|
||||||
|
@ -665,20 +664,17 @@ typedef enum {
|
||||||
} GamepadButton;
|
} GamepadButton;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
// This is here just for error checking
|
|
||||||
GAMEPAD_AXIS_UNKNOWN = 0,
|
|
||||||
|
|
||||||
// Left stick
|
// Left stick
|
||||||
GAMEPAD_AXIS_LEFT_X,
|
GAMEPAD_AXIS_LEFT_X = 0,
|
||||||
GAMEPAD_AXIS_LEFT_Y,
|
GAMEPAD_AXIS_LEFT_Y = 1,
|
||||||
|
|
||||||
// Right stick
|
// Right stick
|
||||||
GAMEPAD_AXIS_RIGHT_X,
|
GAMEPAD_AXIS_RIGHT_X = 2,
|
||||||
GAMEPAD_AXIS_RIGHT_Y,
|
GAMEPAD_AXIS_RIGHT_Y = 3,
|
||||||
|
|
||||||
// Pressure levels for the back triggers
|
// Pressure levels for the back triggers
|
||||||
GAMEPAD_AXIS_LEFT_TRIGGER, // [1..-1] (pressure-level)
|
GAMEPAD_AXIS_LEFT_TRIGGER = 4, // [1..-1] (pressure-level)
|
||||||
GAMEPAD_AXIS_RIGHT_TRIGGER // [1..-1] (pressure-level)
|
GAMEPAD_AXIS_RIGHT_TRIGGER = 5 // [1..-1] (pressure-level)
|
||||||
} GamepadAxis;
|
} GamepadAxis;
|
||||||
|
|
||||||
// Shader location point type
|
// Shader location point type
|
||||||
|
@ -811,7 +807,10 @@ typedef enum {
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BLEND_ALPHA = 0, // Blend textures considering alpha (default)
|
BLEND_ALPHA = 0, // Blend textures considering alpha (default)
|
||||||
BLEND_ADDITIVE, // Blend textures adding colors
|
BLEND_ADDITIVE, // Blend textures adding colors
|
||||||
BLEND_MULTIPLIED // Blend textures multiplying colors
|
BLEND_MULTIPLIED, // Blend textures multiplying colors
|
||||||
|
BLEND_ADD_COLORS, // Blend textures adding colors (alternative)
|
||||||
|
BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative)
|
||||||
|
BLEND_CUSTOM // Belnd textures using custom src/dst factors (use SetBlendModeCustom())
|
||||||
} BlendMode;
|
} BlendMode;
|
||||||
|
|
||||||
// Gestures type
|
// Gestures type
|
||||||
|
@ -873,13 +872,19 @@ RLAPI void InitWindow(int width, int height, const char *title); // Initialize
|
||||||
RLAPI bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed
|
RLAPI bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed
|
||||||
RLAPI void CloseWindow(void); // Close window and unload OpenGL context
|
RLAPI void CloseWindow(void); // Close window and unload OpenGL context
|
||||||
RLAPI bool IsWindowReady(void); // Check if window has been initialized successfully
|
RLAPI bool IsWindowReady(void); // Check if window has been initialized successfully
|
||||||
RLAPI bool IsWindowMinimized(void); // Check if window has been minimized (or lost focus)
|
RLAPI bool IsWindowMinimized(void); // Check if window has been minimized
|
||||||
|
RLAPI bool IsWindowMaximized(void); // Check if window has been maximized (only PLATFORM_DESKTOP)
|
||||||
|
RLAPI bool IsWindowFocused(void); // Check if window has been focused
|
||||||
RLAPI bool IsWindowResized(void); // Check if window has been resized
|
RLAPI bool IsWindowResized(void); // Check if window has been resized
|
||||||
RLAPI bool IsWindowHidden(void); // Check if window is currently hidden
|
RLAPI bool IsWindowHidden(void); // Check if window is currently hidden
|
||||||
RLAPI bool IsWindowFullscreen(void); // Check if window is currently fullscreen
|
RLAPI bool IsWindowFullscreen(void); // Check if window is currently fullscreen
|
||||||
RLAPI void ToggleFullscreen(void); // Toggle fullscreen mode (only PLATFORM_DESKTOP)
|
RLAPI void ToggleFullscreen(void); // Toggle fullscreen mode (only PLATFORM_DESKTOP)
|
||||||
RLAPI void UnhideWindow(void); // Show the window
|
RLAPI void UnhideWindow(void); // Show the window
|
||||||
RLAPI void HideWindow(void); // Hide the window
|
RLAPI void HideWindow(void); // Hide the window
|
||||||
|
RLAPI void DecorateWindow(void); // Decorate the window (only PLATFORM_DESKTOP)
|
||||||
|
RLAPI void UndecorateWindow(void); // Undecorate the window (only PLATFORM_DESKTOP)
|
||||||
|
RLAPI void MaximizeWindow(void); // Maximize the window, if resizable (only PLATFORM_DESKTOP)
|
||||||
|
RLAPI void RestoreWindow(void); // Restore the window, if resizable (only PLATFORM_DESKTOP)
|
||||||
RLAPI void SetWindowIcon(Image image); // Set icon for window (only PLATFORM_DESKTOP)
|
RLAPI void SetWindowIcon(Image image); // Set icon for window (only PLATFORM_DESKTOP)
|
||||||
RLAPI void SetWindowTitle(const char *title); // Set title for window (only PLATFORM_DESKTOP)
|
RLAPI void 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 SetWindowPosition(int x, int y); // Set window position on screen (only PLATFORM_DESKTOP)
|
||||||
|
@ -894,7 +899,9 @@ RLAPI int GetMonitorWidth(int monitor); // Get primary
|
||||||
RLAPI int GetMonitorHeight(int monitor); // Get primary monitor height
|
RLAPI int GetMonitorHeight(int monitor); // Get primary monitor height
|
||||||
RLAPI int GetMonitorPhysicalWidth(int monitor); // Get primary monitor physical width in millimetres
|
RLAPI int GetMonitorPhysicalWidth(int monitor); // Get primary monitor physical width in millimetres
|
||||||
RLAPI int GetMonitorPhysicalHeight(int monitor); // Get primary monitor physical height in millimetres
|
RLAPI int GetMonitorPhysicalHeight(int monitor); // Get primary monitor physical height in millimetres
|
||||||
|
RLAPI int GetMonitorRefreshRate(int monitor); // Get primary monitor refresh rate
|
||||||
RLAPI Vector2 GetWindowPosition(void); // Get window position XY on monitor
|
RLAPI Vector2 GetWindowPosition(void); // Get window position XY on monitor
|
||||||
|
RLAPI Vector2 GetWindowScaleDPI(void); // Get window scale DPI factor
|
||||||
RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the primary monitor
|
RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the primary monitor
|
||||||
RLAPI const char *GetClipboardText(void); // Get clipboard text content
|
RLAPI const char *GetClipboardText(void); // Get clipboard text content
|
||||||
RLAPI void SetClipboardText(const char *text); // Set clipboard text content
|
RLAPI void SetClipboardText(const char *text); // Set clipboard text content
|
||||||
|
@ -905,6 +912,7 @@ RLAPI void HideCursor(void); // Hides curso
|
||||||
RLAPI bool IsCursorHidden(void); // Check if cursor is not visible
|
RLAPI bool IsCursorHidden(void); // Check if cursor is not visible
|
||||||
RLAPI void EnableCursor(void); // Enables cursor (unlock cursor)
|
RLAPI void EnableCursor(void); // Enables cursor (unlock cursor)
|
||||||
RLAPI void DisableCursor(void); // Disables cursor (lock cursor)
|
RLAPI void DisableCursor(void); // Disables cursor (lock cursor)
|
||||||
|
RLAPI bool IsCursorOnScreen(void); // Check if cursor is on the current screen.
|
||||||
|
|
||||||
// Drawing-related functions
|
// Drawing-related functions
|
||||||
RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color)
|
RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color)
|
||||||
|
@ -934,15 +942,6 @@ RLAPI int GetFPS(void); // Returns cur
|
||||||
RLAPI float GetFrameTime(void); // Returns time in seconds for last frame drawn
|
RLAPI float GetFrameTime(void); // Returns time in seconds for last frame drawn
|
||||||
RLAPI double GetTime(void); // Returns elapsed time in seconds since InitWindow()
|
RLAPI double GetTime(void); // Returns elapsed time in seconds since InitWindow()
|
||||||
|
|
||||||
// Color-related functions
|
|
||||||
RLAPI int ColorToInt(Color color); // Returns hexadecimal value for a Color
|
|
||||||
RLAPI Vector4 ColorNormalize(Color color); // Returns color normalized as float [0..1]
|
|
||||||
RLAPI Color ColorFromNormalized(Vector4 normalized); // Returns color from normalized values [0..1]
|
|
||||||
RLAPI Vector3 ColorToHSV(Color color); // Returns HSV values for a Color
|
|
||||||
RLAPI Color ColorFromHSV(Vector3 hsv); // Returns a Color from HSV values
|
|
||||||
RLAPI Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value
|
|
||||||
RLAPI Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
|
|
||||||
|
|
||||||
// Misc. functions
|
// Misc. functions
|
||||||
RLAPI void SetConfigFlags(unsigned int flags); // Setup window configuration flags (view FLAGS)
|
RLAPI void SetConfigFlags(unsigned int flags); // Setup window configuration flags (view FLAGS)
|
||||||
RLAPI void SetTraceLogLevel(int logType); // Set the current threshold (minimum) log level
|
RLAPI void SetTraceLogLevel(int logType); // Set the current threshold (minimum) log level
|
||||||
|
@ -1105,14 +1104,11 @@ RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Ve
|
||||||
// Image loading functions
|
// Image loading functions
|
||||||
// NOTE: This functions do not require GPU access
|
// NOTE: This functions do not require GPU access
|
||||||
RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM)
|
RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM)
|
||||||
RLAPI Image LoadImageEx(Color *pixels, int width, int height); // Load image from Color array data (RGBA - 32bit)
|
|
||||||
RLAPI Image LoadImagePro(void *data, int width, int height, int format); // Load image from raw data with parameters
|
|
||||||
RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data
|
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 void UnloadImage(Image image); // Unload image from CPU memory (RAM)
|
RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM)
|
||||||
RLAPI void ExportImage(Image image, const char *fileName); // Export image data to file
|
RLAPI void ExportImage(Image image, const char *fileName); // Export image data to file
|
||||||
RLAPI void ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes
|
RLAPI void ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes
|
||||||
RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array
|
|
||||||
RLAPI Vector4 *GetImageDataNormalized(Image image); // Get pixel data from image as Vector4 array (float normalized)
|
|
||||||
|
|
||||||
// Image generation functions
|
// Image generation functions
|
||||||
RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color
|
RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color
|
||||||
|
@ -1129,16 +1125,16 @@ RLAPI Image ImageCopy(Image image);
|
||||||
RLAPI Image ImageFromImage(Image image, Rectangle rec); // Create an image from another image piece
|
RLAPI Image ImageFromImage(Image image, Rectangle rec); // Create an image from another image piece
|
||||||
RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font)
|
RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font)
|
||||||
RLAPI Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint); // Create an image from text (custom sprite font)
|
RLAPI Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint); // Create an image from text (custom sprite font)
|
||||||
RLAPI void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two)
|
|
||||||
RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format
|
RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format
|
||||||
RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image
|
RLAPI void ImageToPOT(Image *image, Color fill); // Convert image to POT (power-of-two)
|
||||||
RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color
|
|
||||||
RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value
|
|
||||||
RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel
|
|
||||||
RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle
|
RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle
|
||||||
|
RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value
|
||||||
|
RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color
|
||||||
|
RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image
|
||||||
|
RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel
|
||||||
RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (Bicubic scaling algorithm)
|
RLAPI void 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 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 color); // Resize canvas and fill with color
|
RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill); // Resize canvas and fill with color
|
||||||
RLAPI void ImageMipmaps(Image *image); // Generate all mipmap levels for a provided image
|
RLAPI void ImageMipmaps(Image *image); // Generate all mipmap levels for a provided image
|
||||||
RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
|
RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
|
||||||
RLAPI void ImageFlipVertical(Image *image); // Flip image vertically
|
RLAPI void ImageFlipVertical(Image *image); // Flip image vertically
|
||||||
|
@ -1151,7 +1147,10 @@ RLAPI void ImageColorGrayscale(Image *image);
|
||||||
RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100)
|
RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100)
|
||||||
RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255)
|
RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255)
|
||||||
RLAPI void ImageColorReplace(Image *image, Color color, Color replace); // Modify image color: replace color
|
RLAPI void ImageColorReplace(Image *image, Color color, Color replace); // Modify image color: replace color
|
||||||
RLAPI Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount); // Extract color palette from image to maximum size (memory should be freed)
|
|
||||||
|
RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array
|
||||||
|
RLAPI Color *GetImagePalette(Image image, int maxPaletteSize, int *extractCount); // Get color palette from image to maximum size (memory should be freed)
|
||||||
|
RLAPI Vector4 *GetImageDataNormalized(Image image); // Get pixel data from image as Vector4 array (float normalized)
|
||||||
RLAPI Rectangle GetImageAlphaBorder(Image image, float threshold); // Get image alpha border rectangle
|
RLAPI Rectangle GetImageAlphaBorder(Image image, float threshold); // Get image alpha border rectangle
|
||||||
|
|
||||||
// Image drawing functions
|
// Image drawing functions
|
||||||
|
@ -1168,8 +1167,8 @@ RLAPI void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color
|
||||||
RLAPI void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color); // Draw rectangle within an image
|
RLAPI void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color); // Draw rectangle within an image
|
||||||
RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color); // Draw rectangle lines within an image
|
RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color); // Draw rectangle lines within an image
|
||||||
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source)
|
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source)
|
||||||
RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (default font) within an image (destination)
|
RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination)
|
||||||
RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, Font font, const char *text, float fontSize, float spacing, Color color); // Draw text (custom sprite font) within an image (destination)
|
RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination)
|
||||||
|
|
||||||
// Texture loading functions
|
// Texture loading functions
|
||||||
// NOTE: These functions require GPU access
|
// NOTE: These functions require GPU access
|
||||||
|
@ -1180,6 +1179,7 @@ RLAPI RenderTexture2D LoadRenderTexture(int width, int height);
|
||||||
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
|
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
|
||||||
RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM)
|
RLAPI void 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 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
|
||||||
RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image
|
RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image
|
||||||
RLAPI Image GetScreenData(void); // Get pixel data from screen buffer and return an Image (screenshot)
|
RLAPI Image GetScreenData(void); // Get pixel data from screen buffer and return an Image (screenshot)
|
||||||
|
|
||||||
|
@ -1194,11 +1194,23 @@ RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint);
|
||||||
RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters
|
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 sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle
|
RLAPI void DrawTextureRec(Texture2D texture, Rectangle sourceRec, 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 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 sourceRec, Rectangle destRec, Vector2 origin, float rotation, float scale, Color tint); // Draw part of a texture (defined by a rectangle) with rotation and scale tiled into destRec.
|
||||||
RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters
|
RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, 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 destRec, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely
|
RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely
|
||||||
|
|
||||||
// Image/Texture misc functions
|
// Color/pixel related functions
|
||||||
RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture)
|
RLAPI Color Fade(Color color, float alpha); // Returns color with alpha applied, alpha goes from 0.0f to 1.0f
|
||||||
|
RLAPI int ColorToInt(Color color); // Returns hexadecimal value for a Color
|
||||||
|
RLAPI Vector4 ColorNormalize(Color color); // Returns Color normalized as float [0..1]
|
||||||
|
RLAPI Color ColorFromNormalized(Vector4 normalized); // Returns Color from normalized values [0..1]
|
||||||
|
RLAPI Vector3 ColorToHSV(Color color); // Returns HSV values for a Color
|
||||||
|
RLAPI Color ColorFromHSV(Vector3 hsv); // Returns a Color from HSV values
|
||||||
|
RLAPI Color ColorAlpha(Color color, float alpha); // Returns color with alpha applied, alpha goes from 0.0f to 1.0f
|
||||||
|
RLAPI Color ColorAlphaBlend(Color dst, Color src, Color tint); // Returns src alpha-blended into dst color with tint
|
||||||
|
RLAPI Color GetColor(int hexValue); // Get Color structure from hexadecimal value
|
||||||
|
RLAPI Color GetPixelColor(void *srcPtr, int format); // Get Color from a source pixel pointer of certain format
|
||||||
|
RLAPI void SetPixelColor(void *dstPtr, Color color, int format); // Set color formatted into destination pixel pointer
|
||||||
|
RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes for certain format
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Font Loading and Text Drawing Functions (Module: text)
|
// Font Loading and Text Drawing Functions (Module: text)
|
||||||
|
@ -1260,6 +1272,8 @@ RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength); // Encode
|
||||||
RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space
|
RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space
|
||||||
RLAPI void DrawPoint3D(Vector3 position, Color color); // Draw a point in 3D space, actually a small line
|
RLAPI void DrawPoint3D(Vector3 position, Color color); // Draw a point in 3D space, actually a small line
|
||||||
RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color); // Draw a circle in 3D world space
|
RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color); // Draw a circle in 3D world space
|
||||||
|
RLAPI void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color); // Draw a color-filled triangle (vertex in counter-clockwise order!)
|
||||||
|
RLAPI void DrawTriangleStrip3D(Vector3 *points, int pointsCount, Color color); // Draw a triangle strip defined by points
|
||||||
RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color); // Draw cube
|
RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color); // Draw cube
|
||||||
RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version)
|
RLAPI void 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 DrawCubeWires(Vector3 position, float width, float height, float length, Color color); // Draw cube wires
|
||||||
|
@ -1274,7 +1288,6 @@ RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color);
|
||||||
RLAPI void DrawRay(Ray ray, Color color); // Draw a ray line
|
RLAPI void DrawRay(Ray ray, Color color); // Draw a ray line
|
||||||
RLAPI void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0))
|
RLAPI void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0))
|
||||||
RLAPI void DrawGizmo(Vector3 position); // Draw simple gizmo
|
RLAPI void DrawGizmo(Vector3 position); // Draw simple gizmo
|
||||||
//DrawTorus(), DrawTeapot() could be useful?
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Model 3d Loading and Drawing Functions (Module: models)
|
// Model 3d Loading and Drawing Functions (Module: models)
|
||||||
|
@ -1319,6 +1332,7 @@ RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
|
||||||
RLAPI BoundingBox MeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits
|
RLAPI BoundingBox MeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits
|
||||||
RLAPI void MeshTangents(Mesh *mesh); // Compute mesh tangents
|
RLAPI void MeshTangents(Mesh *mesh); // Compute mesh tangents
|
||||||
RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals
|
RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals
|
||||||
|
RLAPI void MeshNormalsSmooth(Mesh *mesh); // Smooth (average) vertex normals
|
||||||
|
|
||||||
// Model drawing functions
|
// Model drawing functions
|
||||||
RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set)
|
RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set)
|
||||||
|
@ -1437,7 +1451,6 @@ RLAPI void ResumeMusicStream(Music music); // Resume
|
||||||
RLAPI bool IsMusicPlaying(Music music); // Check if music is playing
|
RLAPI bool IsMusicPlaying(Music music); // Check if music is playing
|
||||||
RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
|
RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
|
||||||
RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
|
RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
|
||||||
RLAPI void SetMusicLoopCount(Music music, int count); // Set music loop count (loop repeats)
|
|
||||||
RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds)
|
RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds)
|
||||||
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
|
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
|
||||||
|
|
||||||
|
|
397
raylib/raymath.h
397
raylib/raymath.h
|
@ -154,6 +154,18 @@ RMDEF float Lerp(float start, float end, float amount)
|
||||||
return start + amount*(end - start);
|
return start + amount*(end - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normalize input value within input range
|
||||||
|
RMDEF float Normalize(float value, float start, float end)
|
||||||
|
{
|
||||||
|
return (value - start) / (end - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remap input value within input range to output range
|
||||||
|
RMDEF float Remap(float value, float inputStart, float inputEnd, float outputStart, float outputEnd)
|
||||||
|
{
|
||||||
|
return (value - inputStart) / (inputEnd - inputStart) * (outputEnd - outputStart) + outputStart;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module Functions Definition - Vector2 math
|
// Module Functions Definition - Vector2 math
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -179,6 +191,13 @@ RMDEF Vector2 Vector2Add(Vector2 v1, Vector2 v2)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add vector and float value
|
||||||
|
RMDEF Vector2 Vector2AddValue(Vector2 v, float add)
|
||||||
|
{
|
||||||
|
Vector2 result = { v.x + add, v.y + add };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Subtract two vectors (v1 - v2)
|
// Subtract two vectors (v1 - v2)
|
||||||
RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)
|
RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)
|
||||||
{
|
{
|
||||||
|
@ -186,6 +205,13 @@ RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Subtract vector by float value
|
||||||
|
RMDEF Vector2 Vector2SubtractValue(Vector2 v, float sub)
|
||||||
|
{
|
||||||
|
Vector2 result = { v.x - sub, v.y - sub };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate vector length
|
// Calculate vector length
|
||||||
RMDEF float Vector2Length(Vector2 v)
|
RMDEF float Vector2Length(Vector2 v)
|
||||||
{
|
{
|
||||||
|
@ -193,6 +219,13 @@ RMDEF float Vector2Length(Vector2 v)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate vector square length
|
||||||
|
RMDEF float Vector2LengthSqr(Vector2 v)
|
||||||
|
{
|
||||||
|
float result = (v.x*v.x) + (v.y*v.y);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate two vectors dot product
|
// Calculate two vectors dot product
|
||||||
RMDEF float Vector2DotProduct(Vector2 v1, Vector2 v2)
|
RMDEF float Vector2DotProduct(Vector2 v1, Vector2 v2)
|
||||||
{
|
{
|
||||||
|
@ -223,7 +256,7 @@ RMDEF Vector2 Vector2Scale(Vector2 v, float scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiply vector by vector
|
// Multiply vector by vector
|
||||||
RMDEF Vector2 Vector2MultiplyV(Vector2 v1, Vector2 v2)
|
RMDEF Vector2 Vector2Multiply(Vector2 v1, Vector2 v2)
|
||||||
{
|
{
|
||||||
Vector2 result = { v1.x*v2.x, v1.y*v2.y };
|
Vector2 result = { v1.x*v2.x, v1.y*v2.y };
|
||||||
return result;
|
return result;
|
||||||
|
@ -236,15 +269,8 @@ RMDEF Vector2 Vector2Negate(Vector2 v)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Divide vector by a float value
|
|
||||||
RMDEF Vector2 Vector2Divide(Vector2 v, float div)
|
|
||||||
{
|
|
||||||
Vector2 result = { v.x/div, v.y/div };
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Divide vector by vector
|
// Divide vector by vector
|
||||||
RMDEF Vector2 Vector2DivideV(Vector2 v1, Vector2 v2)
|
RMDEF Vector2 Vector2Divide(Vector2 v1, Vector2 v2)
|
||||||
{
|
{
|
||||||
Vector2 result = { v1.x/v2.x, v1.y/v2.y };
|
Vector2 result = { v1.x/v2.x, v1.y/v2.y };
|
||||||
return result;
|
return result;
|
||||||
|
@ -253,7 +279,7 @@ RMDEF Vector2 Vector2DivideV(Vector2 v1, Vector2 v2)
|
||||||
// Normalize provided vector
|
// Normalize provided vector
|
||||||
RMDEF Vector2 Vector2Normalize(Vector2 v)
|
RMDEF Vector2 Vector2Normalize(Vector2 v)
|
||||||
{
|
{
|
||||||
Vector2 result = Vector2Divide(v, Vector2Length(v));
|
Vector2 result = Vector2Scale(v, 1/Vector2Length(v));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,6 +302,24 @@ RMDEF Vector2 Vector2Rotate(Vector2 v, float degs)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Move Vector towards target
|
||||||
|
RMDEF Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance)
|
||||||
|
{
|
||||||
|
Vector2 result = { 0 };
|
||||||
|
float dx = target.x - v.x;
|
||||||
|
float dy = target.y - v.y;
|
||||||
|
float value = (dx*dx) + (dy*dy);
|
||||||
|
|
||||||
|
if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) result = target;
|
||||||
|
|
||||||
|
float dist = sqrtf(value);
|
||||||
|
|
||||||
|
result.x = v.x + dx/dist*maxDistance;
|
||||||
|
result.y = v.y + dy/dist*maxDistance;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module Functions Definition - Vector3 math
|
// Module Functions Definition - Vector3 math
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -301,6 +345,13 @@ RMDEF Vector3 Vector3Add(Vector3 v1, Vector3 v2)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add vector and float value
|
||||||
|
RMDEF Vector3 Vector3AddValue(Vector3 v, float add)
|
||||||
|
{
|
||||||
|
Vector3 result = { v.x + add, v.y + add, v.z + add };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Subtract two vectors
|
// Subtract two vectors
|
||||||
RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
|
RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
|
||||||
{
|
{
|
||||||
|
@ -308,6 +359,13 @@ RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Subtract vector by float value
|
||||||
|
RMDEF Vector3 Vector3SubtractValue(Vector3 v, float sub)
|
||||||
|
{
|
||||||
|
Vector3 result = { v.x - sub, v.y - sub, v.z - sub };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Multiply vector by scalar
|
// Multiply vector by scalar
|
||||||
RMDEF Vector3 Vector3Scale(Vector3 v, float scalar)
|
RMDEF Vector3 Vector3Scale(Vector3 v, float scalar)
|
||||||
{
|
{
|
||||||
|
@ -362,6 +420,13 @@ RMDEF float Vector3Length(const Vector3 v)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate vector square length
|
||||||
|
RMDEF float Vector3LengthSqr(const Vector3 v)
|
||||||
|
{
|
||||||
|
float result = v.x*v.x + v.y*v.y + v.z*v.z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate two vectors dot product
|
// Calculate two vectors dot product
|
||||||
RMDEF float Vector3DotProduct(Vector3 v1, Vector3 v2)
|
RMDEF float Vector3DotProduct(Vector3 v1, Vector3 v2)
|
||||||
{
|
{
|
||||||
|
@ -386,15 +451,8 @@ RMDEF Vector3 Vector3Negate(Vector3 v)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Divide vector by a float value
|
|
||||||
RMDEF Vector3 Vector3Divide(Vector3 v, float div)
|
|
||||||
{
|
|
||||||
Vector3 result = { v.x / div, v.y / div, v.z / div };
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Divide vector by vector
|
// Divide vector by vector
|
||||||
RMDEF Vector3 Vector3DivideV(Vector3 v1, Vector3 v2)
|
RMDEF Vector3 Vector3Divide(Vector3 v1, Vector3 v2)
|
||||||
{
|
{
|
||||||
Vector3 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z };
|
Vector3 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z };
|
||||||
return result;
|
return result;
|
||||||
|
@ -737,6 +795,32 @@ RMDEF Matrix MatrixSubtract(Matrix left, Matrix right)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns two matrix multiplication
|
||||||
|
// NOTE: When multiplying matrices... the order matters!
|
||||||
|
RMDEF Matrix MatrixMultiply(Matrix left, Matrix right)
|
||||||
|
{
|
||||||
|
Matrix result = { 0 };
|
||||||
|
|
||||||
|
result.m0 = left.m0*right.m0 + left.m1*right.m4 + left.m2*right.m8 + left.m3*right.m12;
|
||||||
|
result.m1 = left.m0*right.m1 + left.m1*right.m5 + left.m2*right.m9 + left.m3*right.m13;
|
||||||
|
result.m2 = left.m0*right.m2 + left.m1*right.m6 + left.m2*right.m10 + left.m3*right.m14;
|
||||||
|
result.m3 = left.m0*right.m3 + left.m1*right.m7 + left.m2*right.m11 + left.m3*right.m15;
|
||||||
|
result.m4 = left.m4*right.m0 + left.m5*right.m4 + left.m6*right.m8 + left.m7*right.m12;
|
||||||
|
result.m5 = left.m4*right.m1 + left.m5*right.m5 + left.m6*right.m9 + left.m7*right.m13;
|
||||||
|
result.m6 = left.m4*right.m2 + left.m5*right.m6 + left.m6*right.m10 + left.m7*right.m14;
|
||||||
|
result.m7 = left.m4*right.m3 + left.m5*right.m7 + left.m6*right.m11 + left.m7*right.m15;
|
||||||
|
result.m8 = left.m8*right.m0 + left.m9*right.m4 + left.m10*right.m8 + left.m11*right.m12;
|
||||||
|
result.m9 = left.m8*right.m1 + left.m9*right.m5 + left.m10*right.m9 + left.m11*right.m13;
|
||||||
|
result.m10 = left.m8*right.m2 + left.m9*right.m6 + left.m10*right.m10 + left.m11*right.m14;
|
||||||
|
result.m11 = left.m8*right.m3 + left.m9*right.m7 + left.m10*right.m11 + left.m11*right.m15;
|
||||||
|
result.m12 = left.m12*right.m0 + left.m13*right.m4 + left.m14*right.m8 + left.m15*right.m12;
|
||||||
|
result.m13 = left.m12*right.m1 + left.m13*right.m5 + left.m14*right.m9 + left.m15*right.m13;
|
||||||
|
result.m14 = left.m12*right.m2 + left.m13*right.m6 + left.m14*right.m10 + left.m15*right.m14;
|
||||||
|
result.m15 = left.m12*right.m3 + left.m13*right.m7 + left.m14*right.m11 + left.m15*right.m15;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns translation matrix
|
// Returns translation matrix
|
||||||
RMDEF Matrix MatrixTranslate(float x, float y, float z)
|
RMDEF Matrix MatrixTranslate(float x, float y, float z)
|
||||||
{
|
{
|
||||||
|
@ -793,33 +877,6 @@ RMDEF Matrix MatrixRotate(Vector3 axis, float angle)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns xyz-rotation matrix (angles in radians)
|
|
||||||
RMDEF Matrix MatrixRotateXYZ(Vector3 ang)
|
|
||||||
{
|
|
||||||
Matrix result = MatrixIdentity();
|
|
||||||
|
|
||||||
float cosz = cosf(-ang.z);
|
|
||||||
float sinz = sinf(-ang.z);
|
|
||||||
float cosy = cosf(-ang.y);
|
|
||||||
float siny = sinf(-ang.y);
|
|
||||||
float cosx = cosf(-ang.x);
|
|
||||||
float sinx = sinf(-ang.x);
|
|
||||||
|
|
||||||
result.m0 = cosz * cosy;
|
|
||||||
result.m4 = (cosz * siny * sinx) - (sinz * cosx);
|
|
||||||
result.m8 = (cosz * siny * cosx) + (sinz * sinx);
|
|
||||||
|
|
||||||
result.m1 = sinz * cosy;
|
|
||||||
result.m5 = (sinz * siny * sinx) + (cosz * cosx);
|
|
||||||
result.m9 = (sinz * siny * cosx) - (cosz * sinx);
|
|
||||||
|
|
||||||
result.m2 = -siny;
|
|
||||||
result.m6 = cosy * sinx;
|
|
||||||
result.m10= cosy * cosx;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns x-rotation matrix (angle in radians)
|
// Returns x-rotation matrix (angle in radians)
|
||||||
RMDEF Matrix MatrixRotateX(float angle)
|
RMDEF Matrix MatrixRotateX(float angle)
|
||||||
{
|
{
|
||||||
|
@ -868,6 +925,46 @@ RMDEF Matrix MatrixRotateZ(float angle)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns xyz-rotation matrix (angles in radians)
|
||||||
|
RMDEF Matrix MatrixRotateXYZ(Vector3 ang)
|
||||||
|
{
|
||||||
|
Matrix result = MatrixIdentity();
|
||||||
|
|
||||||
|
float cosz = cosf(-ang.z);
|
||||||
|
float sinz = sinf(-ang.z);
|
||||||
|
float cosy = cosf(-ang.y);
|
||||||
|
float siny = sinf(-ang.y);
|
||||||
|
float cosx = cosf(-ang.x);
|
||||||
|
float sinx = sinf(-ang.x);
|
||||||
|
|
||||||
|
result.m0 = cosz * cosy;
|
||||||
|
result.m4 = (cosz * siny * sinx) - (sinz * cosx);
|
||||||
|
result.m8 = (cosz * siny * cosx) + (sinz * sinx);
|
||||||
|
|
||||||
|
result.m1 = sinz * cosy;
|
||||||
|
result.m5 = (sinz * siny * sinx) + (cosz * cosx);
|
||||||
|
result.m9 = (sinz * siny * cosx) - (cosz * sinx);
|
||||||
|
|
||||||
|
result.m2 = -siny;
|
||||||
|
result.m6 = cosy * sinx;
|
||||||
|
result.m10= cosy * cosx;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns zyx-rotation matrix (angles in radians)
|
||||||
|
// TODO: This solution is suboptimal, it should be possible to create this matrix in one go
|
||||||
|
// instead of using a 3 matrix multiplication
|
||||||
|
RMDEF Matrix MatrixRotateZYX(Vector3 ang)
|
||||||
|
{
|
||||||
|
Matrix result = MatrixRotateZ(ang.z);
|
||||||
|
result = MatrixMultiply(result, MatrixRotateY(ang.y));
|
||||||
|
result = MatrixMultiply(result, MatrixRotateX(ang.x));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns scaling matrix
|
// Returns scaling matrix
|
||||||
RMDEF Matrix MatrixScale(float x, float y, float z)
|
RMDEF Matrix MatrixScale(float x, float y, float z)
|
||||||
{
|
{
|
||||||
|
@ -879,32 +976,6 @@ RMDEF Matrix MatrixScale(float x, float y, float z)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns two matrix multiplication
|
|
||||||
// NOTE: When multiplying matrices... the order matters!
|
|
||||||
RMDEF Matrix MatrixMultiply(Matrix left, Matrix right)
|
|
||||||
{
|
|
||||||
Matrix result = { 0 };
|
|
||||||
|
|
||||||
result.m0 = left.m0*right.m0 + left.m1*right.m4 + left.m2*right.m8 + left.m3*right.m12;
|
|
||||||
result.m1 = left.m0*right.m1 + left.m1*right.m5 + left.m2*right.m9 + left.m3*right.m13;
|
|
||||||
result.m2 = left.m0*right.m2 + left.m1*right.m6 + left.m2*right.m10 + left.m3*right.m14;
|
|
||||||
result.m3 = left.m0*right.m3 + left.m1*right.m7 + left.m2*right.m11 + left.m3*right.m15;
|
|
||||||
result.m4 = left.m4*right.m0 + left.m5*right.m4 + left.m6*right.m8 + left.m7*right.m12;
|
|
||||||
result.m5 = left.m4*right.m1 + left.m5*right.m5 + left.m6*right.m9 + left.m7*right.m13;
|
|
||||||
result.m6 = left.m4*right.m2 + left.m5*right.m6 + left.m6*right.m10 + left.m7*right.m14;
|
|
||||||
result.m7 = left.m4*right.m3 + left.m5*right.m7 + left.m6*right.m11 + left.m7*right.m15;
|
|
||||||
result.m8 = left.m8*right.m0 + left.m9*right.m4 + left.m10*right.m8 + left.m11*right.m12;
|
|
||||||
result.m9 = left.m8*right.m1 + left.m9*right.m5 + left.m10*right.m9 + left.m11*right.m13;
|
|
||||||
result.m10 = left.m8*right.m2 + left.m9*right.m6 + left.m10*right.m10 + left.m11*right.m14;
|
|
||||||
result.m11 = left.m8*right.m3 + left.m9*right.m7 + left.m10*right.m11 + left.m11*right.m15;
|
|
||||||
result.m12 = left.m12*right.m0 + left.m13*right.m4 + left.m14*right.m8 + left.m15*right.m12;
|
|
||||||
result.m13 = left.m12*right.m1 + left.m13*right.m5 + left.m14*right.m9 + left.m15*right.m13;
|
|
||||||
result.m14 = left.m12*right.m2 + left.m13*right.m6 + left.m14*right.m10 + left.m15*right.m14;
|
|
||||||
result.m15 = left.m12*right.m3 + left.m13*right.m7 + left.m14*right.m11 + left.m15*right.m15;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns perspective projection matrix
|
// Returns perspective projection matrix
|
||||||
RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far)
|
RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far)
|
||||||
{
|
{
|
||||||
|
@ -1040,6 +1111,34 @@ RMDEF float16 MatrixToFloatV(Matrix mat)
|
||||||
// Module Functions Definition - Quaternion math
|
// Module Functions Definition - Quaternion math
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Add two quaternions
|
||||||
|
RMDEF Quaternion QuaternionAdd(Quaternion q1, Quaternion q2)
|
||||||
|
{
|
||||||
|
Quaternion result = {q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add quaternion and float value
|
||||||
|
RMDEF Quaternion QuaternionAddValue(Quaternion q, float add)
|
||||||
|
{
|
||||||
|
Quaternion result = {q.x + add, q.y + add, q.z + add, q.w + add};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtract two quaternions
|
||||||
|
RMDEF Quaternion QuaternionSubtract(Quaternion q1, Quaternion q2)
|
||||||
|
{
|
||||||
|
Quaternion result = {q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtract quaternion and float value
|
||||||
|
RMDEF Quaternion QuaternionSubtractValue(Quaternion q, float sub)
|
||||||
|
{
|
||||||
|
Quaternion result = {q.x - sub, q.y - sub, q.z - sub, q.w - sub};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns identity quaternion
|
// Returns identity quaternion
|
||||||
RMDEF Quaternion QuaternionIdentity(void)
|
RMDEF Quaternion QuaternionIdentity(void)
|
||||||
{
|
{
|
||||||
|
@ -1108,6 +1207,28 @@ RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scale quaternion by float value
|
||||||
|
RMDEF Quaternion QuaternionScale(Quaternion q, float mul)
|
||||||
|
{
|
||||||
|
Quaternion result = { 0 };
|
||||||
|
|
||||||
|
float qax = q.x, qay = q.y, qaz = q.z, qaw = q.w;
|
||||||
|
|
||||||
|
result.x = qax * mul + qaw * mul + qay * mul - qaz * mul;
|
||||||
|
result.y = qay * mul + qaw * mul + qaz * mul - qax * mul;
|
||||||
|
result.z = qaz * mul + qaw * mul + qax * mul - qay * mul;
|
||||||
|
result.w = qaw * mul - qax * mul - qay * mul - qaz * mul;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Divide two quaternions
|
||||||
|
RMDEF Quaternion QuaternionDivide(Quaternion q1, Quaternion q2)
|
||||||
|
{
|
||||||
|
Quaternion result = {q1.x / q2.x, q1.y / q2.y, q1.z / q2.z, q1.w / q2.w};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate linear interpolation between two quaternions
|
// Calculate linear interpolation between two quaternions
|
||||||
RMDEF Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount)
|
RMDEF Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount)
|
||||||
{
|
{
|
||||||
|
@ -1176,7 +1297,7 @@ RMDEF Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to)
|
||||||
|
|
||||||
result.x = cross.x;
|
result.x = cross.x;
|
||||||
result.y = cross.y;
|
result.y = cross.y;
|
||||||
result.z = cross.y;
|
result.z = cross.z;
|
||||||
result.w = 1.0f + cos2Theta; // NOTE: Added QuaternioIdentity()
|
result.w = 1.0f + cos2Theta; // NOTE: Added QuaternioIdentity()
|
||||||
|
|
||||||
// Normalize to essentially nlerp the original and identity to 0.5
|
// Normalize to essentially nlerp the original and identity to 0.5
|
||||||
|
@ -1191,54 +1312,32 @@ RMDEF Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to)
|
||||||
// Returns a quaternion for a given rotation matrix
|
// Returns a quaternion for a given rotation matrix
|
||||||
RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
|
RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
|
||||||
{
|
{
|
||||||
Quaternion result = { 0 };
|
Quaternion result = { 0.0f };
|
||||||
|
|
||||||
float trace = MatrixTrace(mat);
|
if ((mat.m0 > mat.m5) && (mat.m0 > mat.m10))
|
||||||
|
|
||||||
if (trace > 0.0f)
|
|
||||||
{
|
{
|
||||||
float s = sqrtf(trace + 1)*2.0f;
|
float s = sqrtf(1.0f + mat.m0 - mat.m5 - mat.m10)*2;
|
||||||
float invS = 1.0f/s;
|
|
||||||
|
|
||||||
result.w = s*0.25f;
|
result.x = 0.25f*s;
|
||||||
result.x = (mat.m6 - mat.m9)*invS;
|
result.y = (mat.m4 + mat.m1)/s;
|
||||||
result.y = (mat.m8 - mat.m2)*invS;
|
result.z = (mat.m2 + mat.m8)/s;
|
||||||
result.z = (mat.m1 - mat.m4)*invS;
|
result.w = (mat.m9 - mat.m6)/s;
|
||||||
|
}
|
||||||
|
else if (mat.m5 > mat.m10)
|
||||||
|
{
|
||||||
|
float s = sqrtf(1.0f + mat.m5 - mat.m0 - mat.m10)*2;
|
||||||
|
result.x = (mat.m4 + mat.m1)/s;
|
||||||
|
result.y = 0.25f*s;
|
||||||
|
result.z = (mat.m9 + mat.m6)/s;
|
||||||
|
result.w = (mat.m2 - mat.m8)/s;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float m00 = mat.m0, m11 = mat.m5, m22 = mat.m10;
|
float s = sqrtf(1.0f + mat.m10 - mat.m0 - mat.m5)*2;
|
||||||
|
result.x = (mat.m2 + mat.m8)/s;
|
||||||
if (m00 > m11 && m00 > m22)
|
result.y = (mat.m9 + mat.m6)/s;
|
||||||
{
|
result.z = 0.25f*s;
|
||||||
float s = (float)sqrt(1.0f + m00 - m11 - m22)*2.0f;
|
result.w = (mat.m4 - mat.m1)/s;
|
||||||
float invS = 1.0f/s;
|
|
||||||
|
|
||||||
result.w = (mat.m6 - mat.m9)*invS;
|
|
||||||
result.x = s*0.25f;
|
|
||||||
result.y = (mat.m4 + mat.m1)*invS;
|
|
||||||
result.z = (mat.m8 + mat.m2)*invS;
|
|
||||||
}
|
|
||||||
else if (m11 > m22)
|
|
||||||
{
|
|
||||||
float s = sqrtf(1.0f + m11 - m00 - m22)*2.0f;
|
|
||||||
float invS = 1.0f/s;
|
|
||||||
|
|
||||||
result.w = (mat.m8 - mat.m2)*invS;
|
|
||||||
result.x = (mat.m4 + mat.m1)*invS;
|
|
||||||
result.y = s*0.25f;
|
|
||||||
result.z = (mat.m9 + mat.m6)*invS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
float s = sqrtf(1.0f + m22 - m00 - m11)*2.0f;
|
|
||||||
float invS = 1.0f/s;
|
|
||||||
|
|
||||||
result.w = (mat.m1 - mat.m4)*invS;
|
|
||||||
result.x = (mat.m8 + mat.m2)*invS;
|
|
||||||
result.y = (mat.m9 + mat.m6)*invS;
|
|
||||||
result.z = s*0.25f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -1247,45 +1346,24 @@ RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
|
||||||
// Returns a matrix for a given quaternion
|
// Returns a matrix for a given quaternion
|
||||||
RMDEF Matrix QuaternionToMatrix(Quaternion q)
|
RMDEF Matrix QuaternionToMatrix(Quaternion q)
|
||||||
{
|
{
|
||||||
Matrix result = { 0 };
|
Matrix result = MatrixIdentity();
|
||||||
|
|
||||||
float x = q.x, y = q.y, z = q.z, w = q.w;
|
float a2 = 2*(q.x*q.x), b2=2*(q.y*q.y), c2=2*(q.z*q.z); //, d2=2*(q.w*q.w);
|
||||||
|
|
||||||
float x2 = x + x;
|
float ab = 2*(q.x*q.y), ac=2*(q.x*q.z), bc=2*(q.y*q.z);
|
||||||
float y2 = y + y;
|
float ad = 2*(q.x*q.w), bd=2*(q.y*q.w), cd=2*(q.z*q.w);
|
||||||
float z2 = z + z;
|
|
||||||
|
|
||||||
float length = QuaternionLength(q);
|
result.m0 = 1 - b2 - c2;
|
||||||
float lengthSquared = length*length;
|
result.m1 = ab - cd;
|
||||||
|
result.m2 = ac + bd;
|
||||||
|
|
||||||
float xx = x*x2/lengthSquared;
|
result.m4 = ab + cd;
|
||||||
float xy = x*y2/lengthSquared;
|
result.m5 = 1 - a2 - c2;
|
||||||
float xz = x*z2/lengthSquared;
|
result.m6 = bc - ad;
|
||||||
|
|
||||||
float yy = y*y2/lengthSquared;
|
result.m8 = ac - bd;
|
||||||
float yz = y*z2/lengthSquared;
|
result.m9 = bc + ad;
|
||||||
float zz = z*z2/lengthSquared;
|
result.m10 = 1 - a2 - b2;
|
||||||
|
|
||||||
float wx = w*x2/lengthSquared;
|
|
||||||
float wy = w*y2/lengthSquared;
|
|
||||||
float wz = w*z2/lengthSquared;
|
|
||||||
|
|
||||||
result.m0 = 1.0f - (yy + zz);
|
|
||||||
result.m1 = xy - wz;
|
|
||||||
result.m2 = xz + wy;
|
|
||||||
result.m3 = 0.0f;
|
|
||||||
result.m4 = xy + wz;
|
|
||||||
result.m5 = 1.0f - (xx + zz);
|
|
||||||
result.m6 = yz - wx;
|
|
||||||
result.m7 = 0.0f;
|
|
||||||
result.m8 = xz - wy;
|
|
||||||
result.m9 = yz + wx;
|
|
||||||
result.m10 = 1.0f - (xx + yy);
|
|
||||||
result.m11 = 0.0f;
|
|
||||||
result.m12 = 0.0f;
|
|
||||||
result.m13 = 0.0f;
|
|
||||||
result.m14 = 0.0f;
|
|
||||||
result.m15 = 1.0f;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1399,4 +1477,27 @@ RMDEF Quaternion QuaternionTransform(Quaternion q, Matrix mat)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Projects a Vector3 from screen space into object space
|
||||||
|
RMDEF Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view)
|
||||||
|
{
|
||||||
|
Vector3 result = { 0.0f, 0.0f, 0.0f };
|
||||||
|
|
||||||
|
// Calculate unproject matrix (multiply view patrix by projection matrix) and invert it
|
||||||
|
Matrix matViewProj = MatrixMultiply(view, projection);
|
||||||
|
matViewProj = MatrixInvert(matViewProj);
|
||||||
|
|
||||||
|
// Create quaternion from source point
|
||||||
|
Quaternion quat = { source.x, source.y, source.z, 1.0f };
|
||||||
|
|
||||||
|
// Multiply quat point by unproject matrix
|
||||||
|
quat = QuaternionTransform(quat, matViewProj);
|
||||||
|
|
||||||
|
// Normalized world points in vectors
|
||||||
|
result.x = quat.x/quat.w;
|
||||||
|
result.y = quat.y/quat.w;
|
||||||
|
result.z = quat.z/quat.w;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // RAYMATH_H
|
#endif // RAYMATH_H
|
||||||
|
|
869
raylib/rlgl.h
869
raylib/rlgl.h
File diff suppressed because it is too large
Load diff
732
raylib/rmem.h
732
raylib/rmem.h
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* rmem - raylib memory pool and objects pool
|
* rmem - raylib memory pool and objects pool
|
||||||
*
|
*
|
||||||
* A quick, efficient, and minimal free list and stack-based allocator
|
* A quick, efficient, and minimal free list and arena-based allocator
|
||||||
*
|
*
|
||||||
* PURPOSE:
|
* PURPOSE:
|
||||||
* - A quicker, efficient memory allocator alternative to 'malloc' and friends.
|
* - A quicker, efficient memory allocator alternative to 'malloc' and friends.
|
||||||
|
@ -55,6 +55,8 @@
|
||||||
#define RMEMAPI // We are building or using library as a static library (or Linux shared library)
|
#define RMEMAPI // We are building or using library as a static library (or Linux shared library)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define RMEM_VERSION "v1.3" // changelog at bottom of header.
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Types and Structures Definition
|
// Types and Structures Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -66,39 +68,45 @@ struct MemNode {
|
||||||
MemNode *next, *prev;
|
MemNode *next, *prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Freelist implementation
|
||||||
typedef struct AllocList {
|
typedef struct AllocList {
|
||||||
MemNode *head, *tail;
|
MemNode *head, *tail;
|
||||||
size_t len, maxNodes;
|
size_t len;
|
||||||
bool autoDefrag : 1;
|
|
||||||
} AllocList;
|
} AllocList;
|
||||||
|
|
||||||
typedef struct Stack {
|
// Arena allocator.
|
||||||
uint8_t *mem, *base;
|
typedef struct Arena {
|
||||||
|
uintptr_t mem, offs;
|
||||||
size_t size;
|
size_t size;
|
||||||
} Stack;
|
} Arena;
|
||||||
|
|
||||||
#define MEMPOOL_BUCKET_SIZE 8
|
|
||||||
#define MEMPOOL_BUCKET_BITS 3
|
enum {
|
||||||
|
MEMPOOL_BUCKET_SIZE = 8,
|
||||||
|
MEMPOOL_BUCKET_BITS = (sizeof(uintptr_t) >> 1) + 1,
|
||||||
|
MEM_SPLIT_THRESHOLD = sizeof(uintptr_t) * 4
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct MemPool {
|
typedef struct MemPool {
|
||||||
AllocList freeList;
|
AllocList large, buckets[MEMPOOL_BUCKET_SIZE];
|
||||||
Stack stack;
|
Arena arena;
|
||||||
MemNode *buckets[MEMPOOL_BUCKET_SIZE];
|
|
||||||
} MemPool;
|
} MemPool;
|
||||||
|
|
||||||
|
|
||||||
// Object Pool
|
// Object Pool
|
||||||
typedef struct ObjPool {
|
typedef struct ObjPool {
|
||||||
Stack stack;
|
uintptr_t mem, offs;
|
||||||
size_t objSize, freeBlocks;
|
size_t objSize, freeBlocks, memSize;
|
||||||
} ObjPool;
|
} ObjPool;
|
||||||
|
|
||||||
|
|
||||||
// Double-Ended Stack aka Deque
|
// Double-Ended Stack aka Deque
|
||||||
typedef struct BiStack {
|
typedef struct BiStack {
|
||||||
uint8_t *mem, *front, *back;
|
uintptr_t mem, front, back;
|
||||||
size_t size;
|
size_t size;
|
||||||
} BiStack;
|
} BiStack;
|
||||||
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
extern "C" { // Prevents name mangling of functions
|
extern "C" { // Prevents name mangling of functions
|
||||||
#endif
|
#endif
|
||||||
|
@ -115,10 +123,7 @@ RMEMAPI void *MemPoolRealloc(MemPool *mempool, void *ptr, size_t bytes);
|
||||||
RMEMAPI void MemPoolFree(MemPool *mempool, void *ptr);
|
RMEMAPI void MemPoolFree(MemPool *mempool, void *ptr);
|
||||||
RMEMAPI void MemPoolCleanUp(MemPool *mempool, void **ptrref);
|
RMEMAPI void MemPoolCleanUp(MemPool *mempool, void **ptrref);
|
||||||
RMEMAPI void MemPoolReset(MemPool *mempool);
|
RMEMAPI void MemPoolReset(MemPool *mempool);
|
||||||
RMEMAPI bool MemPoolDefrag(MemPool *mempool);
|
|
||||||
|
|
||||||
RMEMAPI size_t GetMemPoolFreeMemory(const MemPool mempool);
|
RMEMAPI size_t GetMemPoolFreeMemory(const MemPool mempool);
|
||||||
RMEMAPI void ToggleMemPoolAutoDefrag(MemPool *mempool);
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------
|
||||||
// Functions Declaration - Object Pool
|
// Functions Declaration - Object Pool
|
||||||
|
@ -161,7 +166,9 @@ RMEMAPI intptr_t BiStackMargins(BiStack destack);
|
||||||
|
|
||||||
#if defined(RMEM_IMPLEMENTATION)
|
#if defined(RMEM_IMPLEMENTATION)
|
||||||
|
|
||||||
#include <stdio.h> // Required for: malloc(), calloc(), free()
|
#include <stdio.h> // Required for:
|
||||||
|
#include <stdlib.h> // Required for:
|
||||||
|
#include <string.h> // Required for:
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Defines and Macros
|
// Defines and Macros
|
||||||
|
@ -188,6 +195,145 @@ static inline size_t __AlignSize(const size_t size, const size_t align)
|
||||||
return (size + (align - 1)) & -align;
|
return (size + (align - 1)) & -align;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MemNode *__SplitMemNode(MemNode *const node, const size_t bytes)
|
||||||
|
{
|
||||||
|
uintptr_t n = ( uintptr_t )node;
|
||||||
|
MemNode *const r = ( MemNode* )(n + (node->size - bytes));
|
||||||
|
node->size -= bytes;
|
||||||
|
r->size = bytes;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __InsertMemNodeBefore(AllocList *const list, MemNode *const insert, MemNode *const curr)
|
||||||
|
{
|
||||||
|
insert->next = curr;
|
||||||
|
if (curr->prev==NULL) list->head = insert;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
insert->prev = curr->prev;
|
||||||
|
curr->prev->next = insert;
|
||||||
|
}
|
||||||
|
curr->prev = insert;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __ReplaceMemNode(MemNode *const old, MemNode *const replace)
|
||||||
|
{
|
||||||
|
replace->prev = old->prev;
|
||||||
|
replace->next = old->next;
|
||||||
|
if( old->prev != NULL )
|
||||||
|
old->prev->next = replace;
|
||||||
|
if( old->next != NULL )
|
||||||
|
old->next->prev = replace;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static MemNode *__RemoveMemNode(AllocList *const list, MemNode *const node)
|
||||||
|
{
|
||||||
|
if (node->prev != NULL) node->prev->next = node->next;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
list->head = node->next;
|
||||||
|
if (list->head != NULL) list->head->prev = NULL;
|
||||||
|
else list->tail = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->next != NULL) node->next->prev = node->prev;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
list->tail = node->prev;
|
||||||
|
if (list->tail != NULL) list->tail->next = NULL;
|
||||||
|
else list->head = NULL;
|
||||||
|
}
|
||||||
|
list->len--;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemNode *__FindMemNode(AllocList *const list, const size_t bytes)
|
||||||
|
{
|
||||||
|
for (MemNode *node = list->head; node != NULL; node = node->next)
|
||||||
|
{
|
||||||
|
if (node->size < bytes) continue;
|
||||||
|
// close in size - reduce fragmentation by not splitting.
|
||||||
|
else if (node->size <= bytes + MEM_SPLIT_THRESHOLD) return __RemoveMemNode(list, node);
|
||||||
|
else return __SplitMemNode(node, bytes);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __InsertMemNode(MemPool *const mempool, AllocList *const list, MemNode *const node, const bool is_bucket)
|
||||||
|
{
|
||||||
|
if (list->head == NULL)
|
||||||
|
{
|
||||||
|
list->head = node;
|
||||||
|
list->len++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (MemNode *iter = list->head; iter != NULL; iter = iter->next)
|
||||||
|
{
|
||||||
|
if (( uintptr_t )iter == mempool->arena.offs)
|
||||||
|
{
|
||||||
|
mempool->arena.offs += iter->size;
|
||||||
|
__RemoveMemNode(list, iter);
|
||||||
|
iter = list->head;
|
||||||
|
}
|
||||||
|
const uintptr_t inode = ( uintptr_t )node;
|
||||||
|
const uintptr_t iiter = ( uintptr_t )iter;
|
||||||
|
const uintptr_t iter_end = iiter + iter->size;
|
||||||
|
const uintptr_t node_end = inode + node->size;
|
||||||
|
if (iter==node) return;
|
||||||
|
else if (iter < node)
|
||||||
|
{
|
||||||
|
// node was coalesced prior.
|
||||||
|
if (iter_end > inode) return;
|
||||||
|
else if (iter_end==inode && !is_bucket)
|
||||||
|
{
|
||||||
|
// if we can coalesce, do so.
|
||||||
|
iter->size += node->size;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (iter > node)
|
||||||
|
{
|
||||||
|
// Address sort, lowest to highest aka ascending order.
|
||||||
|
if (iiter < node_end) return;
|
||||||
|
else if (iter==list->head && !is_bucket)
|
||||||
|
{
|
||||||
|
if (iter_end==inode) iter->size += node->size;
|
||||||
|
else if (node_end==iiter)
|
||||||
|
{
|
||||||
|
node->size += list->head->size;
|
||||||
|
node->next = list->head->next;
|
||||||
|
node->prev = NULL;
|
||||||
|
list->head = node;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node->next = iter;
|
||||||
|
node->prev = NULL;
|
||||||
|
iter->prev = node;
|
||||||
|
list->head = node;
|
||||||
|
list->len++;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (iter_end==inode && !is_bucket)
|
||||||
|
{
|
||||||
|
// if we can coalesce, do so.
|
||||||
|
iter->size += node->size;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
__InsertMemNodeBefore(list, iter, node);
|
||||||
|
list->len++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module Functions Definition - Memory Pool
|
// Module Functions Definition - Memory Pool
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -196,114 +342,77 @@ MemPool CreateMemPool(const size_t size)
|
||||||
{
|
{
|
||||||
MemPool mempool = { 0 };
|
MemPool mempool = { 0 };
|
||||||
|
|
||||||
if (size == 0UL) return mempool;
|
if (size == 0) return mempool;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Align the mempool size to at least the size of an alloc node.
|
// Align the mempool size to at least the size of an alloc node.
|
||||||
mempool.stack.size = size;
|
uint8_t *const restrict buf = malloc(size*sizeof *buf);
|
||||||
mempool.stack.mem = malloc(mempool.stack.size*sizeof *mempool.stack.mem);
|
if (buf==NULL) return mempool;
|
||||||
|
|
||||||
if (mempool.stack.mem == NULL)
|
|
||||||
{
|
|
||||||
mempool.stack.size = 0UL;
|
|
||||||
return mempool;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mempool.stack.base = mempool.stack.mem + mempool.stack.size;
|
mempool.arena.size = size;
|
||||||
|
mempool.arena.mem = ( uintptr_t )buf;
|
||||||
|
mempool.arena.offs = mempool.arena.mem + mempool.arena.size;
|
||||||
return mempool;
|
return mempool;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MemPool CreateMemPoolFromBuffer(void *buf, const size_t size)
|
MemPool CreateMemPoolFromBuffer(void *const restrict buf, const size_t size)
|
||||||
{
|
{
|
||||||
MemPool mempool = { 0 };
|
MemPool mempool = { 0 };
|
||||||
|
if ((size == 0) || (buf == NULL) || (size <= sizeof(MemNode))) return mempool;
|
||||||
if ((size == 0UL) || (buf == NULL) || (size <= sizeof(MemNode))) return mempool;
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mempool.stack.size = size;
|
mempool.arena.size = size;
|
||||||
mempool.stack.mem = buf;
|
mempool.arena.mem = ( uintptr_t )buf;
|
||||||
mempool.stack.base = mempool.stack.mem + mempool.stack.size;
|
mempool.arena.offs = mempool.arena.mem + mempool.arena.size;
|
||||||
return mempool;
|
return mempool;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyMemPool(MemPool *const mempool)
|
void DestroyMemPool(MemPool *const restrict mempool)
|
||||||
{
|
{
|
||||||
if ((mempool == NULL) || (mempool->stack.mem == NULL)) return;
|
if (mempool->arena.mem == 0) return;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
free(mempool->stack.mem);
|
void *const restrict ptr = ( void* )mempool->arena.mem;
|
||||||
|
free(ptr);
|
||||||
*mempool = (MemPool){ 0 };
|
*mempool = (MemPool){ 0 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *MemPoolAlloc(MemPool *const mempool, const size_t size)
|
void *MemPoolAlloc(MemPool *const mempool, const size_t size)
|
||||||
{
|
{
|
||||||
if ((mempool == NULL) || (size == 0UL) || (size > mempool->stack.size)) return NULL;
|
if ((size == 0) || (size > mempool->arena.size)) return NULL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MemNode *new_mem = NULL;
|
MemNode *new_mem = NULL;
|
||||||
const size_t ALLOC_SIZE = __AlignSize(size + sizeof *new_mem, sizeof(intptr_t));
|
const size_t ALLOC_SIZE = __AlignSize(size + sizeof *new_mem, sizeof(intptr_t));
|
||||||
const size_t BUCKET_INDEX = (ALLOC_SIZE >> MEMPOOL_BUCKET_BITS) - 1;
|
const size_t BUCKET_SLOT = (ALLOC_SIZE >> MEMPOOL_BUCKET_BITS) - 1;
|
||||||
|
|
||||||
// If the size is small enough, let's check if our buckets has a fitting memory block.
|
// If the size is small enough, let's check if our buckets has a fitting memory block.
|
||||||
if ((BUCKET_INDEX < MEMPOOL_BUCKET_SIZE) &&
|
if (BUCKET_SLOT < MEMPOOL_BUCKET_SIZE)
|
||||||
(mempool->buckets[BUCKET_INDEX] != NULL) &&
|
|
||||||
(mempool->buckets[BUCKET_INDEX]->size >= ALLOC_SIZE))
|
|
||||||
{
|
{
|
||||||
new_mem = mempool->buckets[BUCKET_INDEX];
|
new_mem = __FindMemNode(&mempool->buckets[BUCKET_SLOT], ALLOC_SIZE);
|
||||||
mempool->buckets[BUCKET_INDEX] = mempool->buckets[BUCKET_INDEX]->next;
|
|
||||||
if( mempool->buckets[BUCKET_INDEX] != NULL )
|
|
||||||
mempool->buckets[BUCKET_INDEX]->prev = NULL;
|
|
||||||
}
|
}
|
||||||
else if (mempool->freeList.head != NULL)
|
else if (mempool->large.head != NULL)
|
||||||
{
|
{
|
||||||
const size_t MEM_SPLIT_THRESHOLD = 16;
|
new_mem = __FindMemNode(&mempool->large, ALLOC_SIZE);
|
||||||
|
|
||||||
// If the freelist is valid, let's allocate FROM the freelist then!
|
|
||||||
for (MemNode *inode = mempool->freeList.head; inode != NULL; inode = inode->next)
|
|
||||||
{
|
|
||||||
if (inode->size < ALLOC_SIZE) continue;
|
|
||||||
else if (inode->size <= (ALLOC_SIZE + MEM_SPLIT_THRESHOLD))
|
|
||||||
{
|
|
||||||
// Close in size - reduce fragmentation by not splitting.
|
|
||||||
new_mem = inode;
|
|
||||||
(inode->prev != NULL)? (inode->prev->next = inode->next) : (mempool->freeList.head = inode->next);
|
|
||||||
(inode->next != NULL)? (inode->next->prev = inode->prev) : (mempool->freeList.tail = inode->prev);
|
|
||||||
|
|
||||||
if (mempool->freeList.head != NULL) mempool->freeList.head->prev = NULL;
|
|
||||||
else mempool->freeList.tail = NULL;
|
|
||||||
|
|
||||||
if (mempool->freeList.tail != NULL) mempool->freeList.tail->next = NULL;
|
|
||||||
mempool->freeList.len--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Split the memory chunk.
|
|
||||||
new_mem = (MemNode *)((uint8_t *)inode + (inode->size - ALLOC_SIZE));
|
|
||||||
inode->size -= ALLOC_SIZE;
|
|
||||||
new_mem->size = ALLOC_SIZE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_mem == NULL)
|
if (new_mem == NULL)
|
||||||
{
|
{
|
||||||
// not enough memory to support the size!
|
// not enough memory to support the size!
|
||||||
if ((mempool->stack.base - ALLOC_SIZE) < mempool->stack.mem) return NULL;
|
if ((mempool->arena.offs - ALLOC_SIZE) < mempool->arena.mem) return NULL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Couldn't allocate from a freelist, allocate from available mempool.
|
// Couldn't allocate from a freelist, allocate from available mempool.
|
||||||
// Subtract allocation size from the mempool.
|
// Subtract allocation size from the mempool.
|
||||||
mempool->stack.base -= ALLOC_SIZE;
|
mempool->arena.offs -= ALLOC_SIZE;
|
||||||
|
|
||||||
// Use the available mempool space as the new node.
|
// Use the available mempool space as the new node.
|
||||||
new_mem = (MemNode *)mempool->stack.base;
|
new_mem = ( MemNode* )mempool->arena.offs;
|
||||||
new_mem->size = ALLOC_SIZE;
|
new_mem->size = ALLOC_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,33 +422,32 @@ void *MemPoolAlloc(MemPool *const mempool, const size_t size)
|
||||||
// | mem size | lowest addr of block
|
// | mem size | lowest addr of block
|
||||||
// | next node | 12 byte (32-bit) header
|
// | next node | 12 byte (32-bit) header
|
||||||
// | prev node | 24 byte (64-bit) header
|
// | prev node | 24 byte (64-bit) header
|
||||||
// --------------
|
// |------------|
|
||||||
// | alloc'd |
|
// | alloc'd |
|
||||||
// | memory |
|
// | memory |
|
||||||
// | space | highest addr of block
|
// | space | highest addr of block
|
||||||
// --------------
|
// --------------
|
||||||
new_mem->next = new_mem->prev = NULL;
|
new_mem->next = new_mem->prev = NULL;
|
||||||
uint8_t *const final_mem = (uint8_t *)new_mem + sizeof *new_mem;
|
uint8_t *const restrict final_mem = ( uint8_t* )new_mem + sizeof *new_mem;
|
||||||
return memset(final_mem, 0, new_mem->size - sizeof *new_mem);
|
return memset(final_mem, 0, new_mem->size - sizeof *new_mem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *MemPoolRealloc(MemPool *const restrict mempool, void *ptr, const size_t size)
|
void *MemPoolRealloc(MemPool *const restrict mempool, void *const ptr, const size_t size)
|
||||||
{
|
{
|
||||||
if ((mempool == NULL) || (size > mempool->stack.size)) return NULL;
|
if (size > mempool->arena.size) return NULL;
|
||||||
// NULL ptr should make this work like regular Allocation.
|
// NULL ptr should make this work like regular Allocation.
|
||||||
else if (ptr == NULL) return MemPoolAlloc(mempool, size);
|
else if (ptr == NULL) return MemPoolAlloc(mempool, size);
|
||||||
else if ((uintptr_t)ptr - sizeof(MemNode) < (uintptr_t)mempool->stack.mem) return NULL;
|
else if ((uintptr_t)ptr - sizeof(MemNode) < mempool->arena.mem) return NULL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MemNode *const node = (MemNode *)((uint8_t *)ptr - sizeof *node);
|
MemNode *const node = ( MemNode* )(( uint8_t* )ptr - sizeof *node);
|
||||||
const size_t NODE_SIZE = sizeof *node;
|
const size_t NODE_SIZE = sizeof *node;
|
||||||
uint8_t *const resized_block = MemPoolAlloc(mempool, size);
|
uint8_t *const resized_block = MemPoolAlloc(mempool, size);
|
||||||
|
|
||||||
if (resized_block == NULL) return NULL;
|
if (resized_block == NULL) return NULL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MemNode *const resized = (MemNode *)(resized_block - sizeof *resized);
|
MemNode *const resized = ( MemNode* )(resized_block - sizeof *resized);
|
||||||
memmove(resized_block, ptr, (node->size > resized->size)? (resized->size - NODE_SIZE) : (node->size - NODE_SIZE));
|
memmove(resized_block, ptr, (node->size > resized->size)? (resized->size - NODE_SIZE) : (node->size - NODE_SIZE));
|
||||||
MemPoolFree(mempool, ptr);
|
MemPoolFree(mempool, ptr);
|
||||||
return resized_block;
|
return resized_block;
|
||||||
|
@ -347,72 +455,39 @@ void *MemPoolRealloc(MemPool *const restrict mempool, void *ptr, const size_t si
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemPoolFree(MemPool *const restrict mempool, void *ptr)
|
void MemPoolFree(MemPool *const restrict mempool, void *const ptr)
|
||||||
{
|
{
|
||||||
if ((mempool == NULL) || (ptr == NULL) || ((uintptr_t)ptr - sizeof(MemNode) < (uintptr_t)mempool->stack.mem)) return;
|
const uintptr_t p = ( uintptr_t )ptr;
|
||||||
|
if ((ptr == NULL) || (p - sizeof(MemNode) < mempool->arena.mem)) return;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Behind the actual pointer data is the allocation info.
|
// Behind the actual pointer data is the allocation info.
|
||||||
MemNode *const mem_node = (MemNode *)((uint8_t *)ptr - sizeof *mem_node);
|
const uintptr_t block = p - sizeof(MemNode);
|
||||||
const size_t BUCKET_INDEX = (mem_node->size >> MEMPOOL_BUCKET_BITS) - 1;
|
MemNode *const mem_node = ( MemNode* )block;
|
||||||
|
const size_t BUCKET_SLOT = (mem_node->size >> MEMPOOL_BUCKET_BITS) - 1;
|
||||||
|
|
||||||
// Make sure the pointer data is valid.
|
// Make sure the pointer data is valid.
|
||||||
if (((uintptr_t)mem_node < (uintptr_t)mempool->stack.base) ||
|
if ((block < mempool->arena.offs) ||
|
||||||
(((uintptr_t)mem_node - (uintptr_t)mempool->stack.mem) > mempool->stack.size) ||
|
((block - mempool->arena.mem) > mempool->arena.size) ||
|
||||||
(mem_node->size == 0UL) ||
|
(mem_node->size == 0) ||
|
||||||
(mem_node->size > mempool->stack.size)) return;
|
(mem_node->size > mempool->arena.size)) return;
|
||||||
// If the mem_node is right at the stack base ptr, then add it to the stack.
|
// If the mem_node is right at the arena offs, then merge it back to the arena.
|
||||||
else if ((uintptr_t)mem_node == (uintptr_t)mempool->stack.base)
|
else if (block == mempool->arena.offs)
|
||||||
{
|
{
|
||||||
mempool->stack.base += mem_node->size;
|
mempool->arena.offs += mem_node->size;
|
||||||
}
|
}
|
||||||
// attempted stack merge failed, try to place it into the memnode buckets
|
else
|
||||||
else if (BUCKET_INDEX < MEMPOOL_BUCKET_SIZE)
|
|
||||||
{
|
{
|
||||||
if (mempool->buckets[BUCKET_INDEX] == NULL) mempool->buckets[BUCKET_INDEX] = mem_node;
|
// try to place it into bucket or large freelist.
|
||||||
else
|
struct AllocList *const l = (BUCKET_SLOT < MEMPOOL_BUCKET_SIZE) ? &mempool->buckets[BUCKET_SLOT] : &mempool->large;
|
||||||
{
|
__InsertMemNode(mempool, l, mem_node, (BUCKET_SLOT < MEMPOOL_BUCKET_SIZE));
|
||||||
for (MemNode *n = mempool->buckets[BUCKET_INDEX]; n != NULL; n = n->next) if( n==mem_node ) return;
|
|
||||||
mempool->buckets[BUCKET_INDEX]->prev = mem_node;
|
|
||||||
mem_node->next = mempool->buckets[BUCKET_INDEX];
|
|
||||||
mempool->buckets[BUCKET_INDEX] = mem_node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Otherwise, we add it to the free list.
|
|
||||||
// We also check if the freelist already has the pointer so we can prevent double frees.
|
|
||||||
else /*if ((mempool->freeList.len == 0UL) || ((uintptr_t)mempool->freeList.head >= (uintptr_t)mempool->stack.mem && (uintptr_t)mempool->freeList.head - (uintptr_t)mempool->stack.mem < mempool->stack.size))*/
|
|
||||||
{
|
|
||||||
for (MemNode *n = mempool->freeList.head; n != NULL; n = n->next) if (n == mem_node) return;
|
|
||||||
|
|
||||||
// This code insertion sorts where largest size is last.
|
|
||||||
if (mempool->freeList.head == NULL)
|
|
||||||
{
|
|
||||||
mempool->freeList.head = mempool->freeList.tail = mem_node;
|
|
||||||
mempool->freeList.len++;
|
|
||||||
}
|
|
||||||
else if (mempool->freeList.head->size >= mem_node->size)
|
|
||||||
{
|
|
||||||
mem_node->next = mempool->freeList.head;
|
|
||||||
mem_node->next->prev = mem_node;
|
|
||||||
mempool->freeList.head = mem_node;
|
|
||||||
mempool->freeList.len++;
|
|
||||||
}
|
|
||||||
else //if (mempool->freeList.tail->size <= mem_node->size)
|
|
||||||
{
|
|
||||||
mem_node->prev = mempool->freeList.tail;
|
|
||||||
mempool->freeList.tail->next = mem_node;
|
|
||||||
mempool->freeList.tail = mem_node;
|
|
||||||
mempool->freeList.len++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mempool->freeList.autoDefrag && (mempool->freeList.maxNodes != 0UL) && (mempool->freeList.len > mempool->freeList.maxNodes)) MemPoolDefrag(mempool);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemPoolCleanUp(MemPool *const restrict mempool, void **ptrref)
|
void MemPoolCleanUp(MemPool *const restrict mempool, void **const ptrref)
|
||||||
{
|
{
|
||||||
if ((mempool == NULL) || (ptrref == NULL) || (*ptrref == NULL)) return;
|
if ((ptrref == NULL) || (*ptrref == NULL)) return;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MemPoolFree(mempool, *ptrref);
|
MemPoolFree(mempool, *ptrref);
|
||||||
|
@ -422,264 +497,127 @@ void MemPoolCleanUp(MemPool *const restrict mempool, void **ptrref)
|
||||||
|
|
||||||
size_t GetMemPoolFreeMemory(const MemPool mempool)
|
size_t GetMemPoolFreeMemory(const MemPool mempool)
|
||||||
{
|
{
|
||||||
size_t total_remaining = (uintptr_t)mempool.stack.base - (uintptr_t)mempool.stack.mem;
|
size_t total_remaining = mempool.arena.offs - mempool.arena.mem;
|
||||||
|
|
||||||
for (MemNode *n = mempool.freeList.head; n != NULL; n = n->next) total_remaining += n->size;
|
for (MemNode *n=mempool.large.head; n != NULL; n = n->next) total_remaining += n->size;
|
||||||
|
|
||||||
for (int i = 0; i < MEMPOOL_BUCKET_SIZE; i++) for (MemNode *n = mempool.buckets[i]; n != NULL; n = n->next) total_remaining += n->size;
|
for (size_t i=0; i<MEMPOOL_BUCKET_SIZE; i++) for (MemNode *n = mempool.buckets[i].head; n != NULL; n = n->next) total_remaining += n->size;
|
||||||
|
|
||||||
return total_remaining;
|
return total_remaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemPoolReset(MemPool *const mempool)
|
void MemPoolReset(MemPool *const mempool)
|
||||||
{
|
{
|
||||||
if (mempool == NULL) return;
|
mempool->large.head = mempool->large.tail = NULL;
|
||||||
mempool->freeList.head = mempool->freeList.tail = NULL;
|
mempool->large.len = 0;
|
||||||
mempool->freeList.len = 0;
|
for (size_t i = 0; i < MEMPOOL_BUCKET_SIZE; i++)
|
||||||
for (int i = 0; i < MEMPOOL_BUCKET_SIZE; i++) mempool->buckets[i] = NULL;
|
|
||||||
mempool->stack.base = mempool->stack.mem + mempool->stack.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MemPoolDefrag(MemPool *const mempool)
|
|
||||||
{
|
|
||||||
if (mempool == NULL) return false;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// If the memory pool has been entirely released, fully defrag it.
|
mempool->buckets[i].head = mempool->buckets[i].tail = NULL;
|
||||||
if (mempool->stack.size == GetMemPoolFreeMemory(*mempool))
|
mempool->buckets[i].len = 0;
|
||||||
{
|
|
||||||
MemPoolReset(mempool);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < MEMPOOL_BUCKET_SIZE; i++)
|
|
||||||
{
|
|
||||||
while (mempool->buckets[i] != NULL)
|
|
||||||
{
|
|
||||||
if ((uintptr_t)mempool->buckets[i] == (uintptr_t)mempool->stack.base)
|
|
||||||
{
|
|
||||||
mempool->stack.base += mempool->buckets[i]->size;
|
|
||||||
mempool->buckets[i]->size = 0;
|
|
||||||
mempool->buckets[i] = mempool->buckets[i]->next;
|
|
||||||
if (mempool->buckets[i] != NULL) mempool->buckets[i]->prev = NULL;
|
|
||||||
}
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t PRE_DEFRAG_LEN = mempool->freeList.len;
|
|
||||||
MemNode **node = &mempool->freeList.head;
|
|
||||||
|
|
||||||
while (*node != NULL)
|
|
||||||
{
|
|
||||||
if ((uintptr_t)*node == (uintptr_t)mempool->stack.base)
|
|
||||||
{
|
|
||||||
// If node is right at the stack, merge it back into the stack.
|
|
||||||
mempool->stack.base += (*node)->size;
|
|
||||||
(*node)->size = 0UL;
|
|
||||||
((*node)->prev != NULL)? ((*node)->prev->next = (*node)->next) : (mempool->freeList.head = (*node)->next);
|
|
||||||
((*node)->next != NULL)? ((*node)->next->prev = (*node)->prev) : (mempool->freeList.tail = (*node)->prev);
|
|
||||||
|
|
||||||
if (mempool->freeList.head != NULL) mempool->freeList.head->prev = NULL;
|
|
||||||
else mempool->freeList.tail = NULL;
|
|
||||||
|
|
||||||
if (mempool->freeList.tail != NULL) mempool->freeList.tail->next = NULL;
|
|
||||||
mempool->freeList.len--;
|
|
||||||
node = &mempool->freeList.head;
|
|
||||||
}
|
|
||||||
else if (((uintptr_t)*node + (*node)->size) == (uintptr_t)(*node)->next)
|
|
||||||
{
|
|
||||||
// Next node is at a higher address.
|
|
||||||
(*node)->size += (*node)->next->size;
|
|
||||||
(*node)->next->size = 0UL;
|
|
||||||
|
|
||||||
// <-[P Curr N]-> <-[P Next N]-> <-[P NextNext N]->
|
|
||||||
//
|
|
||||||
// |--------------------|
|
|
||||||
// <-[P Curr N]-> <-[P Next N]-> [P NextNext N]->
|
|
||||||
if ((*node)->next->next != NULL) (*node)->next->next->prev = *node;
|
|
||||||
|
|
||||||
// <-[P Curr N]-> <-[P NextNext N]->
|
|
||||||
(*node)->next = (*node)->next->next;
|
|
||||||
|
|
||||||
mempool->freeList.len--;
|
|
||||||
node = &mempool->freeList.head;
|
|
||||||
}
|
|
||||||
else if ((((uintptr_t)*node + (*node)->size) == (uintptr_t)(*node)->prev) && ((*node)->prev->prev != NULL))
|
|
||||||
{
|
|
||||||
// Prev node is at a higher address.
|
|
||||||
(*node)->size += (*node)->prev->size;
|
|
||||||
(*node)->prev->size = 0UL;
|
|
||||||
|
|
||||||
// <-[P PrevPrev N]-> <-[P Prev N]-> <-[P Curr N]->
|
|
||||||
//
|
|
||||||
// |--------------------|
|
|
||||||
// <-[P PrevPrev N] <-[P Prev N]-> <-[P Curr N]->
|
|
||||||
(*node)->prev->prev->next = *node;
|
|
||||||
|
|
||||||
// <-[P PrevPrev N]-> <-[P Curr N]->
|
|
||||||
(*node)->prev = (*node)->prev->prev;
|
|
||||||
|
|
||||||
mempool->freeList.len--;
|
|
||||||
node = &mempool->freeList.head;
|
|
||||||
}
|
|
||||||
else if ((*node)->prev != NULL && (*node)->next != NULL && (uintptr_t)*node - (*node)->next->size == (uintptr_t)(*node)->next)
|
|
||||||
{
|
|
||||||
// Next node is at a lower address.
|
|
||||||
(*node)->next->size += (*node)->size;
|
|
||||||
|
|
||||||
(*node)->size = 0UL;
|
|
||||||
(*node)->next->prev = (*node)->prev;
|
|
||||||
(*node)->prev->next = (*node)->next;
|
|
||||||
*node = (*node)->next;
|
|
||||||
|
|
||||||
mempool->freeList.len--;
|
|
||||||
node = &mempool->freeList.head;
|
|
||||||
}
|
|
||||||
else if ((*node)->prev != NULL && (*node)->next != NULL && (uintptr_t)*node - (*node)->prev->size == (uintptr_t)(*node)->prev)
|
|
||||||
{
|
|
||||||
// Prev node is at a lower address.
|
|
||||||
(*node)->prev->size += (*node)->size;
|
|
||||||
|
|
||||||
(*node)->size = 0UL;
|
|
||||||
(*node)->next->prev = (*node)->prev;
|
|
||||||
(*node)->prev->next = (*node)->next;
|
|
||||||
*node = (*node)->prev;
|
|
||||||
|
|
||||||
mempool->freeList.len--;
|
|
||||||
node = &mempool->freeList.head;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = &(*node)->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PRE_DEFRAG_LEN > mempool->freeList.len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
mempool->arena.offs = mempool->arena.mem + mempool->arena.size;
|
||||||
|
|
||||||
void ToggleMemPoolAutoDefrag(MemPool *const mempool)
|
|
||||||
{
|
|
||||||
if (mempool == NULL) return;
|
|
||||||
else mempool->freeList.autoDefrag ^= true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module Functions Definition - Object Pool
|
// Module Functions Definition - Object Pool
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
union ObjInfo {
|
|
||||||
uint8_t *const byte;
|
|
||||||
size_t *const index;
|
|
||||||
};
|
|
||||||
|
|
||||||
ObjPool CreateObjPool(const size_t objsize, const size_t len)
|
ObjPool CreateObjPool(const size_t objsize, const size_t len)
|
||||||
{
|
{
|
||||||
ObjPool objpool = { 0 };
|
ObjPool objpool = { 0 };
|
||||||
|
if ((len == 0) || (objsize == 0)) return objpool;
|
||||||
if ((len == 0UL) || (objsize == 0UL)) return objpool;
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
objpool.objSize = __AlignSize(objsize, sizeof(size_t));
|
const size_t aligned_size = __AlignSize(objsize, sizeof(size_t));
|
||||||
objpool.stack.size = objpool.freeBlocks = len;
|
uint8_t *const restrict buf = calloc(len, aligned_size);
|
||||||
objpool.stack.mem = calloc(objpool.stack.size, objpool.objSize);
|
if (buf == NULL) return objpool;
|
||||||
|
objpool.objSize = aligned_size;
|
||||||
|
objpool.memSize = objpool.freeBlocks = len;
|
||||||
|
objpool.mem = ( uintptr_t )buf;
|
||||||
|
|
||||||
if (objpool.stack.mem == NULL)
|
for (size_t i=0; i<objpool.freeBlocks; i++)
|
||||||
{
|
{
|
||||||
objpool.stack.size = 0UL;
|
size_t *const restrict index = ( size_t* )(objpool.mem + (i*aligned_size));
|
||||||
return objpool;
|
*index = i + 1;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < objpool.freeBlocks; i++)
|
|
||||||
{
|
|
||||||
union ObjInfo block = { .byte = &objpool.stack.mem[i*objpool.objSize] };
|
|
||||||
*block.index = i + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
objpool.stack.base = objpool.stack.mem;
|
|
||||||
return objpool;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjPool CreateObjPoolFromBuffer(void *const buf, const size_t objsize, const size_t len)
|
|
||||||
{
|
|
||||||
ObjPool objpool = { 0 };
|
|
||||||
|
|
||||||
// If the object size isn't large enough to align to a size_t, then we can't use it.
|
|
||||||
if ((buf == NULL) || (len == 0UL) || (objsize < sizeof(size_t)) || (objsize*len != __AlignSize(objsize, sizeof(size_t))*len)) return objpool;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
objpool.objSize = __AlignSize(objsize, sizeof(size_t));
|
|
||||||
objpool.stack.size = objpool.freeBlocks = len;
|
|
||||||
objpool.stack.mem = buf;
|
|
||||||
|
|
||||||
for (int i = 0; i < objpool.freeBlocks; i++)
|
|
||||||
{
|
|
||||||
union ObjInfo block = { .byte = &objpool.stack.mem[i*objpool.objSize] };
|
|
||||||
*block.index = i + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
objpool.stack.base = objpool.stack.mem;
|
objpool.offs = objpool.mem;
|
||||||
return objpool;
|
return objpool;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyObjPool(ObjPool *const objpool)
|
ObjPool CreateObjPoolFromBuffer(void *const restrict buf, const size_t objsize, const size_t len)
|
||||||
{
|
{
|
||||||
if ((objpool == NULL) || (objpool->stack.mem == NULL)) return;
|
ObjPool objpool = { 0 };
|
||||||
|
|
||||||
|
// If the object size isn't large enough to align to a size_t, then we can't use it.
|
||||||
|
const size_t aligned_size = __AlignSize(objsize, sizeof(size_t));
|
||||||
|
if ((buf == NULL) || (len == 0) || (objsize < sizeof(size_t)) || (objsize*len != aligned_size*len)) return objpool;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
free(objpool->stack.mem);
|
objpool.objSize = aligned_size;
|
||||||
|
objpool.memSize = objpool.freeBlocks = len;
|
||||||
|
objpool.mem = (uintptr_t)buf;
|
||||||
|
|
||||||
|
for (size_t i=0; i<objpool.freeBlocks; i++)
|
||||||
|
{
|
||||||
|
size_t *const restrict index = ( size_t* )(objpool.mem + (i*aligned_size));
|
||||||
|
*index = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
objpool.offs = objpool.mem;
|
||||||
|
return objpool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyObjPool(ObjPool *const restrict objpool)
|
||||||
|
{
|
||||||
|
if (objpool->mem == 0) return;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
void *const restrict ptr = ( void* )objpool->mem;
|
||||||
|
free(ptr);
|
||||||
*objpool = (ObjPool){0};
|
*objpool = (ObjPool){0};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *ObjPoolAlloc(ObjPool *const objpool)
|
void *ObjPoolAlloc(ObjPool *const objpool)
|
||||||
{
|
{
|
||||||
if (objpool == NULL) return NULL;
|
if (objpool->freeBlocks > 0)
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if (objpool->freeBlocks > 0UL)
|
// For first allocation, head points to the very first index.
|
||||||
{
|
// Head = &pool[0];
|
||||||
// For first allocation, head points to the very first index.
|
// ret = Head == ret = &pool[0];
|
||||||
// Head = &pool[0];
|
size_t *const restrict block = ( size_t* )objpool->offs;
|
||||||
// ret = Head == ret = &pool[0];
|
objpool->freeBlocks--;
|
||||||
union ObjInfo ret = { .byte = objpool->stack.base };
|
|
||||||
objpool->freeBlocks--;
|
|
||||||
|
|
||||||
// after allocating, we set head to the address of the index that *Head holds.
|
// after allocating, we set head to the address of the index that *Head holds.
|
||||||
// Head = &pool[*Head * pool.objsize];
|
// Head = &pool[*Head * pool.objsize];
|
||||||
objpool->stack.base = (objpool->freeBlocks != 0UL)? objpool->stack.mem + (*ret.index*objpool->objSize) : NULL;
|
objpool->offs = (objpool->freeBlocks != 0)? objpool->mem + (*block*objpool->objSize) : 0;
|
||||||
memset(ret.byte, 0, objpool->objSize);
|
return memset(block, 0, objpool->objSize);
|
||||||
|
|
||||||
return ret.byte;
|
|
||||||
}
|
|
||||||
else return NULL;
|
|
||||||
}
|
}
|
||||||
|
else return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjPoolFree(ObjPool *const restrict objpool, void *ptr)
|
void ObjPoolFree(ObjPool *const restrict objpool, void *const ptr)
|
||||||
{
|
{
|
||||||
union ObjInfo p = { .byte = ptr };
|
uintptr_t block = (uintptr_t)ptr;
|
||||||
if ((objpool == NULL) || (ptr == NULL) || (p.byte < objpool->stack.mem) || (p.byte > objpool->stack.mem + objpool->stack.size*objpool->objSize)) return;
|
if ((ptr == NULL) || (block < objpool->mem) || (block > objpool->mem + objpool->memSize*objpool->objSize)) return;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// When we free our pointer, we recycle the pointer space to store the previous index and then we push it as our new head.
|
// When we free our pointer, we recycle the pointer space to store the previous index and then we push it as our new head.
|
||||||
// *p = index of Head in relation to the buffer;
|
// *p = index of Head in relation to the buffer;
|
||||||
// Head = p;
|
// Head = p;
|
||||||
*p.index = (objpool->stack.base != NULL)? (objpool->stack.base - objpool->stack.mem)/objpool->objSize : objpool->stack.size;
|
size_t *const restrict index = ( size_t* )block;
|
||||||
objpool->stack.base = p.byte;
|
*index = (objpool->offs != 0)? (objpool->offs - objpool->mem)/objpool->objSize : objpool->memSize;
|
||||||
|
objpool->offs = block;
|
||||||
objpool->freeBlocks++;
|
objpool->freeBlocks++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjPoolCleanUp(ObjPool *const restrict objpool, void **ptrref)
|
void ObjPoolCleanUp(ObjPool *const restrict objpool, void **const restrict ptrref)
|
||||||
{
|
{
|
||||||
if ((objpool == NULL) || (ptrref == NULL) || (*ptrref == NULL)) return;
|
if (ptrref == NULL) return;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ObjPoolFree(objpool, *ptrref);
|
ObjPoolFree(objpool, *ptrref);
|
||||||
|
@ -694,71 +632,85 @@ void ObjPoolCleanUp(ObjPool *const restrict objpool, void **ptrref)
|
||||||
BiStack CreateBiStack(const size_t len)
|
BiStack CreateBiStack(const size_t len)
|
||||||
{
|
{
|
||||||
BiStack destack = { 0 };
|
BiStack destack = { 0 };
|
||||||
if (len == 0UL) return destack;
|
if (len == 0) return destack;
|
||||||
|
|
||||||
|
uint8_t *const buf = malloc(len*sizeof *buf);
|
||||||
|
if (buf==NULL) return destack;
|
||||||
destack.size = len;
|
destack.size = len;
|
||||||
destack.mem = malloc(len*sizeof *destack.mem);
|
destack.mem = ( uintptr_t )buf;
|
||||||
if (destack.mem==NULL) destack.size = 0UL;
|
destack.front = destack.mem;
|
||||||
else
|
destack.back = destack.mem + len;
|
||||||
{
|
|
||||||
destack.front = destack.mem;
|
|
||||||
destack.back = destack.mem + len;
|
|
||||||
}
|
|
||||||
return destack;
|
return destack;
|
||||||
}
|
}
|
||||||
|
|
||||||
BiStack CreateBiStackFromBuffer(void *const buf, const size_t len)
|
BiStack CreateBiStackFromBuffer(void *const buf, const size_t len)
|
||||||
{
|
{
|
||||||
BiStack destack = { 0 };
|
BiStack destack = { 0 };
|
||||||
if (len == 0UL || buf == NULL) return destack;
|
if (len == 0 || buf == NULL) return destack;
|
||||||
destack.size = len;
|
else
|
||||||
destack.mem = destack.front = buf;
|
{
|
||||||
destack.back = destack.mem + len;
|
destack.size = len;
|
||||||
return destack;
|
destack.mem = destack.front = ( uintptr_t )buf;
|
||||||
|
destack.back = destack.mem + len;
|
||||||
|
return destack;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyBiStack(BiStack *const destack)
|
void DestroyBiStack(BiStack *const restrict destack)
|
||||||
{
|
{
|
||||||
if ((destack == NULL) || (destack->mem == NULL)) return;
|
if (destack->mem == 0) return;
|
||||||
free(destack->mem);
|
else
|
||||||
*destack = (BiStack){0};
|
{
|
||||||
|
uint8_t *const restrict buf = ( uint8_t* )destack->mem;
|
||||||
|
free(buf);
|
||||||
|
*destack = (BiStack){0};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *BiStackAllocFront(BiStack *const destack, const size_t len)
|
void *BiStackAllocFront(BiStack *const restrict destack, const size_t len)
|
||||||
{
|
{
|
||||||
if ((destack == NULL) || (destack->mem == NULL)) return NULL;
|
if (destack->mem == 0) return NULL;
|
||||||
|
else
|
||||||
const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t));
|
{
|
||||||
// front end stack is too high!
|
const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t));
|
||||||
if (destack->front + ALIGNED_LEN >= destack->back) return NULL;
|
// front end arena is too high!
|
||||||
|
if (destack->front + ALIGNED_LEN >= destack->back) return NULL;
|
||||||
uint8_t *ptr = destack->front;
|
else
|
||||||
destack->front += ALIGNED_LEN;
|
{
|
||||||
return ptr;
|
uint8_t *const restrict ptr = ( uint8_t* )destack->front;
|
||||||
|
destack->front += ALIGNED_LEN;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *BiStackAllocBack(BiStack *const destack, const size_t len)
|
void *BiStackAllocBack(BiStack *const restrict destack, const size_t len)
|
||||||
{
|
{
|
||||||
if ((destack == NULL) || (destack->mem == NULL)) return NULL;
|
if (destack->mem == 0) return NULL;
|
||||||
|
else
|
||||||
const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t));
|
{
|
||||||
// back end stack is too low
|
const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t));
|
||||||
if (destack->back - ALIGNED_LEN <= destack->front) return NULL;
|
// back end arena is too low
|
||||||
|
if (destack->back - ALIGNED_LEN <= destack->front) return NULL;
|
||||||
destack->back -= ALIGNED_LEN;
|
else
|
||||||
return destack->back;
|
{
|
||||||
|
destack->back -= ALIGNED_LEN;
|
||||||
|
uint8_t *const restrict ptr = ( uint8_t* )destack->back;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BiStackResetFront(BiStack *const destack)
|
void BiStackResetFront(BiStack *const destack)
|
||||||
{
|
{
|
||||||
if ((destack == NULL) || (destack->mem == NULL)) return;
|
if (destack->mem == 0) return;
|
||||||
destack->front = destack->mem;
|
else destack->front = destack->mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BiStackResetBack(BiStack *const destack)
|
void BiStackResetBack(BiStack *const destack)
|
||||||
{
|
{
|
||||||
if ((destack == NULL) || (destack->mem == NULL)) return;
|
if (destack->mem == 0) return;
|
||||||
destack->back = destack->mem + destack->size;
|
else destack->back = destack->mem + destack->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BiStackResetAll(BiStack *const destack)
|
void BiStackResetAll(BiStack *const destack)
|
||||||
|
@ -767,9 +719,21 @@ void BiStackResetAll(BiStack *const destack)
|
||||||
BiStackResetFront(destack);
|
BiStackResetFront(destack);
|
||||||
}
|
}
|
||||||
|
|
||||||
intptr_t BiStackMargins(const BiStack destack)
|
inline intptr_t BiStackMargins(const BiStack destack)
|
||||||
{
|
{
|
||||||
return destack.back - destack.front;
|
return destack.back - destack.front;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // RMEM_IMPLEMENTATION
|
#endif // RMEM_IMPLEMENTATION
|
||||||
|
|
||||||
|
/*******
|
||||||
|
* Changelog
|
||||||
|
* v1.0: First Creation.
|
||||||
|
* v1.1: bug patches for the mempool and addition of object pool.
|
||||||
|
* v1.2: addition of bidirectional arena.
|
||||||
|
* v1.3:
|
||||||
|
* optimizations of allocators.
|
||||||
|
* renamed 'Stack' to 'Arena'.
|
||||||
|
* replaced certain define constants with an anonymous enum.
|
||||||
|
* refactored MemPool to no longer require active or deferred defragging.
|
||||||
|
********/
|
||||||
|
|
2252
raylib/rnet.h
Normal file
2252
raylib/rnet.h
Normal file
File diff suppressed because it is too large
Load diff
104
raylib/shapes.c
104
raylib/shapes.c
|
@ -47,7 +47,12 @@
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Defines and Macros
|
// Defines and Macros
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Nop...
|
|
||||||
|
// Error rate to calculate how many segments we need to draw a smooth circle,
|
||||||
|
// taken from https://stackoverflow.com/a/2244088
|
||||||
|
#ifndef SMOOTH_CIRCLE_ERROR_RATE
|
||||||
|
#define SMOOTH_CIRCLE_ERROR_RATE 0.5f
|
||||||
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Types and Structures Definition
|
// Types and Structures Definition
|
||||||
|
@ -155,17 +160,19 @@ void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
|
||||||
// Draw line using cubic-bezier curves in-out
|
// Draw line using cubic-bezier curves in-out
|
||||||
void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color)
|
void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color)
|
||||||
{
|
{
|
||||||
#define LINE_DIVISIONS 24 // Bezier line divisions
|
#ifndef BEZIER_LINE_DIVISIONS
|
||||||
|
#define BEZIER_LINE_DIVISIONS 24 // Bezier line divisions
|
||||||
|
#endif
|
||||||
|
|
||||||
Vector2 previous = startPos;
|
Vector2 previous = startPos;
|
||||||
Vector2 current;
|
Vector2 current;
|
||||||
|
|
||||||
for (int i = 1; i <= LINE_DIVISIONS; i++)
|
for (int i = 1; i <= BEZIER_LINE_DIVISIONS; i++)
|
||||||
{
|
{
|
||||||
// Cubic easing in-out
|
// Cubic easing in-out
|
||||||
// NOTE: Easing is calculated only for y position value
|
// NOTE: Easing is calculated only for y position value
|
||||||
current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)LINE_DIVISIONS);
|
current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)BEZIER_LINE_DIVISIONS);
|
||||||
current.x = previous.x + (endPos.x - startPos.x)/ (float)LINE_DIVISIONS;
|
current.x = previous.x + (endPos.x - startPos.x)/ (float)BEZIER_LINE_DIVISIONS;
|
||||||
|
|
||||||
DrawLineEx(previous, current, thick, color);
|
DrawLineEx(previous, current, thick, color);
|
||||||
|
|
||||||
|
@ -214,18 +221,15 @@ void DrawCircleSector(Vector2 center, float radius, int startAngle, int endAngle
|
||||||
|
|
||||||
if (segments < 4)
|
if (segments < 4)
|
||||||
{
|
{
|
||||||
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
|
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
|
||||||
#define CIRCLE_ERROR_RATE 0.5f
|
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
|
||||||
|
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
|
||||||
// Calculate the maximum angle between segments based on the error rate.
|
|
||||||
float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/radius, 2) - 1);
|
|
||||||
segments = (endAngle - startAngle)*ceilf(2*PI/th)/360;
|
|
||||||
|
|
||||||
if (segments <= 0) segments = 4;
|
if (segments <= 0) segments = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
float stepLength = (float)(endAngle - startAngle)/(float)segments;
|
float stepLength = (float)(endAngle - startAngle)/(float)segments;
|
||||||
float angle = startAngle;
|
float angle = (float)startAngle;
|
||||||
|
|
||||||
#if defined(SUPPORT_QUADS_DRAW_MODE)
|
#if defined(SUPPORT_QUADS_DRAW_MODE)
|
||||||
if (rlCheckBufferLimit(4*segments/2)) rlglDraw();
|
if (rlCheckBufferLimit(4*segments/2)) rlglDraw();
|
||||||
|
@ -306,20 +310,15 @@ void DrawCircleSectorLines(Vector2 center, float radius, int startAngle, int end
|
||||||
|
|
||||||
if (segments < 4)
|
if (segments < 4)
|
||||||
{
|
{
|
||||||
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
|
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
|
||||||
#ifndef CIRCLE_ERROR_RATE
|
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
|
||||||
#define CIRCLE_ERROR_RATE 0.5f
|
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
|
||||||
#endif
|
|
||||||
|
|
||||||
// Calculate the maximum angle between segments based on the error rate.
|
|
||||||
float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/radius, 2) - 1);
|
|
||||||
segments = (endAngle - startAngle)*ceilf(2*PI/th)/360;
|
|
||||||
|
|
||||||
if (segments <= 0) segments = 4;
|
if (segments <= 0) segments = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
float stepLength = (float)(endAngle - startAngle)/(float)segments;
|
float stepLength = (float)(endAngle - startAngle)/(float)segments;
|
||||||
float angle = startAngle;
|
float angle = (float)startAngle;
|
||||||
|
|
||||||
// Hide the cap lines when the circle is full
|
// Hide the cap lines when the circle is full
|
||||||
bool showCapLines = true;
|
bool showCapLines = true;
|
||||||
|
@ -365,11 +364,11 @@ void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Co
|
||||||
for (int i = 0; i < 360; i += 10)
|
for (int i = 0; i < 360; i += 10)
|
||||||
{
|
{
|
||||||
rlColor4ub(color1.r, color1.g, color1.b, color1.a);
|
rlColor4ub(color1.r, color1.g, color1.b, color1.a);
|
||||||
rlVertex2f(centerX, centerY);
|
rlVertex2f((float)centerX, (float)centerY);
|
||||||
rlColor4ub(color2.r, color2.g, color2.b, color2.a);
|
rlColor4ub(color2.r, color2.g, color2.b, color2.a);
|
||||||
rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius);
|
rlVertex2f((float)centerX + sinf(DEG2RAD*i)*radius, (float)centerY + cosf(DEG2RAD*i)*radius);
|
||||||
rlColor4ub(color2.r, color2.g, color2.b, color2.a);
|
rlColor4ub(color2.r, color2.g, color2.b, color2.a);
|
||||||
rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius);
|
rlVertex2f((float)centerX + sinf(DEG2RAD*(i + 10))*radius, (float)centerY + cosf(DEG2RAD*(i + 10))*radius);
|
||||||
}
|
}
|
||||||
rlEnd();
|
rlEnd();
|
||||||
}
|
}
|
||||||
|
@ -407,9 +406,9 @@ void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color c
|
||||||
for (int i = 0; i < 360; i += 10)
|
for (int i = 0; i < 360; i += 10)
|
||||||
{
|
{
|
||||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||||
rlVertex2f(centerX, centerY);
|
rlVertex2f((float)centerX, (float)centerY);
|
||||||
rlVertex2f(centerX + sinf(DEG2RAD*i)*radiusH, centerY + cosf(DEG2RAD*i)*radiusV);
|
rlVertex2f((float)centerX + sinf(DEG2RAD*i)*radiusH, (float)centerY + cosf(DEG2RAD*i)*radiusV);
|
||||||
rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radiusH, centerY + cosf(DEG2RAD*(i + 10))*radiusV);
|
rlVertex2f((float)centerX + sinf(DEG2RAD*(i + 10))*radiusH, (float)centerY + cosf(DEG2RAD*(i + 10))*radiusV);
|
||||||
}
|
}
|
||||||
rlEnd();
|
rlEnd();
|
||||||
}
|
}
|
||||||
|
@ -454,14 +453,9 @@ void DrawRing(Vector2 center, float innerRadius, float outerRadius, int startAng
|
||||||
|
|
||||||
if (segments < 4)
|
if (segments < 4)
|
||||||
{
|
{
|
||||||
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
|
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
|
||||||
#ifndef CIRCLE_ERROR_RATE
|
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
|
||||||
#define CIRCLE_ERROR_RATE 0.5f
|
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
|
||||||
#endif
|
|
||||||
|
|
||||||
// Calculate the maximum angle between segments based on the error rate.
|
|
||||||
float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
|
|
||||||
segments = (endAngle - startAngle)*ceilf(2*PI/th)/360;
|
|
||||||
|
|
||||||
if (segments <= 0) segments = 4;
|
if (segments <= 0) segments = 4;
|
||||||
}
|
}
|
||||||
|
@ -474,7 +468,7 @@ void DrawRing(Vector2 center, float innerRadius, float outerRadius, int startAng
|
||||||
}
|
}
|
||||||
|
|
||||||
float stepLength = (float)(endAngle - startAngle)/(float)segments;
|
float stepLength = (float)(endAngle - startAngle)/(float)segments;
|
||||||
float angle = startAngle;
|
float angle = (float)startAngle;
|
||||||
|
|
||||||
#if defined(SUPPORT_QUADS_DRAW_MODE)
|
#if defined(SUPPORT_QUADS_DRAW_MODE)
|
||||||
if (rlCheckBufferLimit(4*segments)) rlglDraw();
|
if (rlCheckBufferLimit(4*segments)) rlglDraw();
|
||||||
|
@ -550,14 +544,9 @@ void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, int sta
|
||||||
|
|
||||||
if (segments < 4)
|
if (segments < 4)
|
||||||
{
|
{
|
||||||
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
|
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
|
||||||
#ifndef CIRCLE_ERROR_RATE
|
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
|
||||||
#define CIRCLE_ERROR_RATE 0.5f
|
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
|
||||||
#endif
|
|
||||||
|
|
||||||
// Calculate the maximum angle between segments based on the error rate.
|
|
||||||
float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
|
|
||||||
segments = (endAngle - startAngle)*ceilf(2*PI/th)/360;
|
|
||||||
|
|
||||||
if (segments <= 0) segments = 4;
|
if (segments <= 0) segments = 4;
|
||||||
}
|
}
|
||||||
|
@ -569,7 +558,7 @@ void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, int sta
|
||||||
}
|
}
|
||||||
|
|
||||||
float stepLength = (float)(endAngle - startAngle)/(float)segments;
|
float stepLength = (float)(endAngle - startAngle)/(float)segments;
|
||||||
float angle = startAngle;
|
float angle = (float)startAngle;
|
||||||
|
|
||||||
bool showCapLines = true;
|
bool showCapLines = true;
|
||||||
int limit = 4*(segments + 1);
|
int limit = 4*(segments + 1);
|
||||||
|
@ -629,6 +618,8 @@ void DrawRectangleRec(Rectangle rec, Color color)
|
||||||
// Draw a color-filled rectangle with pro parameters
|
// Draw a color-filled rectangle with pro parameters
|
||||||
void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color)
|
void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color)
|
||||||
{
|
{
|
||||||
|
if (rlCheckBufferLimit(4)) rlglDraw();
|
||||||
|
|
||||||
rlEnableTexture(GetShapesTexture().id);
|
rlEnableTexture(GetShapesTexture().id);
|
||||||
|
|
||||||
rlPushMatrix();
|
rlPushMatrix();
|
||||||
|
@ -764,13 +755,9 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
|
||||||
// Calculate number of segments to use for the corners
|
// Calculate number of segments to use for the corners
|
||||||
if (segments < 4)
|
if (segments < 4)
|
||||||
{
|
{
|
||||||
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
|
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
|
||||||
#ifndef CIRCLE_ERROR_RATE
|
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
|
||||||
#define CIRCLE_ERROR_RATE 0.5f
|
segments = (int)(ceilf(2*PI/th)/4.0f);
|
||||||
#endif
|
|
||||||
// Calculate the maximum angle between segments based on the error rate.
|
|
||||||
float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/radius, 2) - 1);
|
|
||||||
segments = ceilf(2*PI/th)/4;
|
|
||||||
if (segments <= 0) segments = 4;
|
if (segments <= 0) segments = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -988,13 +975,9 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, int
|
||||||
// Calculate number of segments to use for the corners
|
// Calculate number of segments to use for the corners
|
||||||
if (segments < 4)
|
if (segments < 4)
|
||||||
{
|
{
|
||||||
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
|
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
|
||||||
#ifndef CIRCLE_ERROR_RATE
|
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
|
||||||
#define CIRCLE_ERROR_RATE 0.5f
|
segments = (int)(ceilf(2*PI/th)/2.0f);
|
||||||
#endif
|
|
||||||
// Calculate the maximum angle between segments based on the error rate.
|
|
||||||
float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/radius, 2) - 1);
|
|
||||||
segments = ceilf(2*PI/th)/2;
|
|
||||||
if (segments <= 0) segments = 4;
|
if (segments <= 0) segments = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1263,6 +1246,7 @@ void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
|
||||||
|
|
||||||
// Draw a triangle fan defined by points
|
// Draw a triangle fan defined by points
|
||||||
// NOTE: First vertex provided is the center, shared by all triangles
|
// NOTE: First vertex provided is the center, shared by all triangles
|
||||||
|
// By default, following vertex should be provided in counter-clockwise order
|
||||||
void DrawTriangleFan(Vector2 *points, int pointsCount, Color color)
|
void DrawTriangleFan(Vector2 *points, int pointsCount, Color color)
|
||||||
{
|
{
|
||||||
if (pointsCount >= 3)
|
if (pointsCount >= 3)
|
||||||
|
@ -1298,7 +1282,7 @@ void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color)
|
||||||
{
|
{
|
||||||
if (pointsCount >= 3)
|
if (pointsCount >= 3)
|
||||||
{
|
{
|
||||||
if (rlCheckBufferLimit(pointsCount)) rlglDraw();
|
if (rlCheckBufferLimit(3*(pointsCount - 2))) rlglDraw();
|
||||||
|
|
||||||
rlBegin(RL_TRIANGLES);
|
rlBegin(RL_TRIANGLES);
|
||||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||||
|
|
501
raylib/text.c
501
raylib/text.c
|
@ -16,7 +16,7 @@
|
||||||
* #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
|
* #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
|
||||||
* TextSplit() function static buffer max size
|
* TextSplit() function static buffer max size
|
||||||
*
|
*
|
||||||
* #define TEXTSPLIT_MAX_SUBSTRINGS_COUNT
|
* #define MAX_TEXTSPLIT_COUNT
|
||||||
* TextSplit() function static substrings pointers array (pointing to static buffer)
|
* TextSplit() function static substrings pointers array (pointing to static buffer)
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
|
@ -54,12 +54,12 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h> // Required for: malloc(), free()
|
#include <stdlib.h> // Required for: malloc(), free()
|
||||||
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fgets()
|
#include <stdio.h> // Required for: vsprintf()
|
||||||
#include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy(), strcat(), strncat(), sscanf()
|
#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 <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> // Requried for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
|
||||||
|
|
||||||
#include "utils.h" // Required for: fopen() Android mapping
|
#include "utils.h" // Required for: LoadFileText()
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_TTF)
|
#if defined(SUPPORT_FILEFORMAT_TTF)
|
||||||
#define STB_RECT_PACK_IMPLEMENTATION
|
#define STB_RECT_PACK_IMPLEMENTATION
|
||||||
|
@ -73,17 +73,15 @@
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Defines and Macros
|
// Defines and Macros
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
|
#ifndef MAX_TEXT_BUFFER_LENGTH
|
||||||
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal()
|
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
|
||||||
|
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
|
||||||
#define MAX_TEXT_UNICODE_CHARS 512 // Maximum number of unicode codepoints
|
|
||||||
|
|
||||||
#if !defined(TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH)
|
|
||||||
#define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH 1024 // Size of static buffer: TextSplit()
|
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef MAX_TEXT_UNICODE_CHARS
|
||||||
#if !defined(TEXTSPLIT_MAX_SUBSTRINGS_COUNT)
|
#define MAX_TEXT_UNICODE_CHARS 512 // Maximum number of unicode codepoints: GetCodepoints()
|
||||||
#define TEXTSPLIT_MAX_SUBSTRINGS_COUNT 128 // Size of static pointers array: TextSplit()
|
#endif
|
||||||
|
#ifndef MAX_TEXTSPLIT_COUNT
|
||||||
|
#define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -95,8 +93,9 @@
|
||||||
// Global variables
|
// Global variables
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
#if defined(SUPPORT_DEFAULT_FONT)
|
#if defined(SUPPORT_DEFAULT_FONT)
|
||||||
static Font defaultFont = { 0 }; // Default font provided by raylib
|
// Default font provided by raylib
|
||||||
// NOTE: defaultFont is loaded on InitWindow and disposed on CloseWindow [module: core]
|
// NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core]
|
||||||
|
static Font defaultFont = { 0 };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -192,33 +191,31 @@ extern void LoadFontDefault(void)
|
||||||
|
|
||||||
// Re-construct image from defaultFontData and generate OpenGL texture
|
// Re-construct image from defaultFontData and generate OpenGL texture
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
int imWidth = 128;
|
Image imFont = {
|
||||||
int imHeight = 128;
|
.data = calloc(128*128, 2), // 2 bytes per pixel (gray + alpha)
|
||||||
|
.width = 128,
|
||||||
|
.height = 128,
|
||||||
|
.format = UNCOMPRESSED_GRAY_ALPHA,
|
||||||
|
.mipmaps = 1
|
||||||
|
};
|
||||||
|
|
||||||
Color *imagePixels = (Color *)RL_MALLOC(imWidth*imHeight*sizeof(Color));
|
// Fill image.data with defaultFontData (convert from bit to pixel!)
|
||||||
|
for (int i = 0, counter = 0; i < imFont.width*imFont.height; i += 32)
|
||||||
for (int i = 0; i < imWidth*imHeight; i++) imagePixels[i] = BLANK; // Initialize array
|
|
||||||
|
|
||||||
int counter = 0; // Font data elements counter
|
|
||||||
|
|
||||||
// Fill imgData with defaultFontData (convert from bit to pixel!)
|
|
||||||
for (int i = 0; i < imWidth*imHeight; i += 32)
|
|
||||||
{
|
{
|
||||||
for (int j = 31; j >= 0; j--)
|
for (int j = 31; j >= 0; j--)
|
||||||
{
|
{
|
||||||
if (BIT_CHECK(defaultFontData[counter], j)) imagePixels[i+j] = WHITE;
|
if (BIT_CHECK(defaultFontData[counter], j))
|
||||||
|
{
|
||||||
|
// NOTE: We are unreferencing data as short, so,
|
||||||
|
// we must consider data as little-endian order (alpha + gray)
|
||||||
|
((unsigned short *)imFont.data)[i + j] = 0xffff;
|
||||||
|
}
|
||||||
|
else ((unsigned short *)imFont.data)[i + j] = 0x00ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
counter++;
|
counter++;
|
||||||
|
|
||||||
if (counter > 512) counter = 0; // Security check...
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Image imFont = LoadImageEx(imagePixels, imWidth, imHeight);
|
|
||||||
ImageFormat(&imFont, UNCOMPRESSED_GRAY_ALPHA);
|
|
||||||
|
|
||||||
RL_FREE(imagePixels);
|
|
||||||
|
|
||||||
defaultFont.texture = LoadTextureFromImage(imFont);
|
defaultFont.texture = LoadTextureFromImage(imFont);
|
||||||
|
|
||||||
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount
|
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount
|
||||||
|
@ -295,15 +292,21 @@ Font GetFontDefault()
|
||||||
// Load Font from file into GPU memory (VRAM)
|
// Load Font from file into GPU memory (VRAM)
|
||||||
Font LoadFont(const char *fileName)
|
Font LoadFont(const char *fileName)
|
||||||
{
|
{
|
||||||
// Default hardcoded values for ttf file loading
|
// Default values for ttf font generation
|
||||||
#define DEFAULT_TTF_FONTSIZE 32 // Font first character (32 - space)
|
#ifndef FONT_TTF_DEFAULT_SIZE
|
||||||
#define DEFAULT_TTF_NUMCHARS 95 // ASCII 32..126 is 95 glyphs
|
#define FONT_TTF_DEFAULT_SIZE 32 // TTF font generation default char size (char-height)
|
||||||
#define DEFAULT_FIRST_CHAR 32 // Expected first char for image sprite font
|
#endif
|
||||||
|
#ifndef FONT_TTF_DEFAULT_NUMCHARS
|
||||||
|
#define FONT_TTF_DEFAULT_NUMCHARS 95 // TTF font generation default charset: 95 glyphs (ASCII 32..126)
|
||||||
|
#endif
|
||||||
|
#ifndef FONT_TTF_DEFAULT_FIRST_CHAR
|
||||||
|
#define FONT_TTF_DEFAULT_FIRST_CHAR 32 // TTF font generation default first char for image sprite font (32-Space)
|
||||||
|
#endif
|
||||||
|
|
||||||
Font font = { 0 };
|
Font font = { 0 };
|
||||||
|
|
||||||
#if defined(SUPPORT_FILEFORMAT_TTF)
|
#if defined(SUPPORT_FILEFORMAT_TTF)
|
||||||
if (IsFileExtension(fileName, ".ttf;.otf")) font = LoadFontEx(fileName, DEFAULT_TTF_FONTSIZE, NULL, DEFAULT_TTF_NUMCHARS);
|
if (IsFileExtension(fileName, ".ttf;.otf")) font = LoadFontEx(fileName, FONT_TTF_DEFAULT_SIZE, NULL, FONT_TTF_DEFAULT_NUMCHARS);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
#if defined(SUPPORT_FILEFORMAT_FNT)
|
#if defined(SUPPORT_FILEFORMAT_FNT)
|
||||||
|
@ -312,7 +315,7 @@ Font LoadFont(const char *fileName)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
Image image = LoadImage(fileName);
|
Image image = LoadImage(fileName);
|
||||||
if (image.data != NULL) font = LoadFontFromImage(image, MAGENTA, DEFAULT_FIRST_CHAR);
|
if (image.data != NULL) font = LoadFontFromImage(image, MAGENTA, FONT_TTF_DEFAULT_FIRST_CHAR);
|
||||||
UnloadImage(image);
|
UnloadImage(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,6 +366,10 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
|
||||||
// Load an Image font file (XNA style)
|
// Load an Image font file (XNA style)
|
||||||
Font LoadFontFromImage(Image image, Color key, int firstChar)
|
Font LoadFontFromImage(Image image, Color key, int firstChar)
|
||||||
{
|
{
|
||||||
|
#ifndef MAX_GLYPHS_FROM_IMAGE
|
||||||
|
#define MAX_GLYPHS_FROM_IMAGE 256 // Maximum number of glyphs supported on image scan
|
||||||
|
#endif
|
||||||
|
|
||||||
#define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
|
#define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
|
||||||
|
|
||||||
int charSpacing = 0;
|
int charSpacing = 0;
|
||||||
|
@ -371,13 +378,10 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
|
||||||
int x = 0;
|
int x = 0;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
|
|
||||||
// Default number of characters supported
|
|
||||||
#define MAX_FONTCHARS 256
|
|
||||||
|
|
||||||
// We allocate a temporal arrays for chars data measures,
|
// We allocate a temporal arrays for chars data measures,
|
||||||
// once we get the actual number of chars, we copy data to a sized arrays
|
// once we get the actual number of chars, we copy data to a sized arrays
|
||||||
int tempCharValues[MAX_FONTCHARS];
|
int tempCharValues[MAX_GLYPHS_FROM_IMAGE];
|
||||||
Rectangle tempCharRecs[MAX_FONTCHARS];
|
Rectangle tempCharRecs[MAX_GLYPHS_FROM_IMAGE];
|
||||||
|
|
||||||
Color *pixels = GetImageData(image);
|
Color *pixels = GetImageData(image);
|
||||||
|
|
||||||
|
@ -439,9 +443,13 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
|
||||||
for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK;
|
for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK;
|
||||||
|
|
||||||
// Create a new image with the processed color data (key color replaced by BLANK)
|
// Create a new image with the processed color data (key color replaced by BLANK)
|
||||||
Image fontClear = LoadImageEx(pixels, image.width, image.height);
|
Image fontClear = {
|
||||||
|
.data = pixels,
|
||||||
RL_FREE(pixels); // Free pixels array memory
|
.width = image.width,
|
||||||
|
.height = image.height,
|
||||||
|
.format = UNCOMPRESSED_R8G8B8A8,
|
||||||
|
.mipmaps = 1
|
||||||
|
};
|
||||||
|
|
||||||
// Create spritefont with all data parsed from image
|
// Create spritefont with all data parsed from image
|
||||||
Font font = { 0 };
|
Font font = { 0 };
|
||||||
|
@ -483,11 +491,18 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
|
||||||
{
|
{
|
||||||
// NOTE: Using some SDF generation default values,
|
// NOTE: Using some SDF generation default values,
|
||||||
// trades off precision with ability to handle *smaller* sizes
|
// trades off precision with ability to handle *smaller* sizes
|
||||||
#define SDF_CHAR_PADDING 4
|
#ifndef FONT_SDF_CHAR_PADDING
|
||||||
#define SDF_ON_EDGE_VALUE 128
|
#define FONT_SDF_CHAR_PADDING 4 // SDF font generation char padding
|
||||||
#define SDF_PIXEL_DIST_SCALE 64.0f
|
#endif
|
||||||
|
#ifndef FONT_SDF_ON_EDGE_VALUE
|
||||||
#define BITMAP_ALPHA_THRESHOLD 80
|
#define FONT_SDF_ON_EDGE_VALUE 128 // SDF font generation on edge value
|
||||||
|
#endif
|
||||||
|
#ifndef FONT_SDF_PIXEL_DIST_SCALE
|
||||||
|
#define FONT_SDF_PIXEL_DIST_SCALE 64.0f // SDF font generation pixel distance scale
|
||||||
|
#endif
|
||||||
|
#ifndef FONT_BITMAP_ALPHA_THRESHOLD
|
||||||
|
#define FONT_BITMAP_ALPHA_THRESHOLD 80 // Bitmap (B&W) font generation alpha threshold
|
||||||
|
#endif
|
||||||
|
|
||||||
CharInfo *chars = NULL;
|
CharInfo *chars = NULL;
|
||||||
|
|
||||||
|
@ -541,7 +556,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
|
||||||
// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide
|
// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide
|
||||||
|
|
||||||
if (type != FONT_SDF) chars[i].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
|
if (type != FONT_SDF) chars[i].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
|
||||||
else if (ch != 32) chars[i].image.data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, SDF_CHAR_PADDING, SDF_ON_EDGE_VALUE, SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
|
else if (ch != 32) chars[i].image.data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, FONT_SDF_CHAR_PADDING, FONT_SDF_ON_EDGE_VALUE, FONT_SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
|
||||||
else chars[i].image.data = NULL;
|
else chars[i].image.data = NULL;
|
||||||
|
|
||||||
stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL);
|
stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL);
|
||||||
|
@ -558,8 +573,15 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
|
||||||
// NOTE: We create an empty image for space character, it could be further required for atlas packing
|
// NOTE: We create an empty image for space character, it could be further required for atlas packing
|
||||||
if (ch == 32)
|
if (ch == 32)
|
||||||
{
|
{
|
||||||
chars[i].image = GenImageColor(chars[i].advanceX, fontSize, BLANK);
|
Image imSpace = {
|
||||||
ImageFormat(&chars[i].image, UNCOMPRESSED_GRAYSCALE);
|
.data = calloc(chars[i].advanceX*fontSize, 2),
|
||||||
|
.width = chars[i].advanceX,
|
||||||
|
.height = fontSize,
|
||||||
|
.format = UNCOMPRESSED_GRAYSCALE,
|
||||||
|
.mipmaps = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
chars[i].image = imSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == FONT_BITMAP)
|
if (type == FONT_BITMAP)
|
||||||
|
@ -568,7 +590,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
|
||||||
// NOTE: For optimum results, bitmap font should be generated at base pixel size
|
// NOTE: For optimum results, bitmap font should be generated at base pixel size
|
||||||
for (int p = 0; p < chw*chh; p++)
|
for (int p = 0; p < chw*chh; p++)
|
||||||
{
|
{
|
||||||
if (((unsigned char *)chars[i].image.data)[p] < BITMAP_ALPHA_THRESHOLD) ((unsigned char *)chars[i].image.data)[p] = 0;
|
if (((unsigned char *)chars[i].image.data)[p] < FONT_BITMAP_ALPHA_THRESHOLD) ((unsigned char *)chars[i].image.data)[p] = 0;
|
||||||
else ((unsigned char *)chars[i].image.data)[p] = 255;
|
else ((unsigned char *)chars[i].image.data)[p] = 255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -600,6 +622,12 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
|
||||||
{
|
{
|
||||||
Image atlas = { 0 };
|
Image atlas = { 0 };
|
||||||
|
|
||||||
|
if (chars == NULL)
|
||||||
|
{
|
||||||
|
TraceLog(LOG_WARNING, "FONT: Provided chars info not valid, returning empty image atlas");
|
||||||
|
return atlas;
|
||||||
|
}
|
||||||
|
|
||||||
*charRecs = NULL;
|
*charRecs = NULL;
|
||||||
|
|
||||||
// In case no chars count provided we suppose default of 95
|
// In case no chars count provided we suppose default of 95
|
||||||
|
@ -652,7 +680,7 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
|
||||||
// Move atlas position X for next character drawing
|
// Move atlas position X for next character drawing
|
||||||
offsetX += (chars[i].image.width + 2*padding);
|
offsetX += (chars[i].image.width + 2*padding);
|
||||||
|
|
||||||
if (offsetX >= (atlas.width - chars[i].image.width - padding))
|
if (offsetX >= (atlas.width - chars[i].image.width - 2*padding))
|
||||||
{
|
{
|
||||||
offsetX = padding;
|
offsetX = padding;
|
||||||
|
|
||||||
|
@ -714,7 +742,6 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
|
||||||
// TODO: Crop image if required for smaller size
|
// TODO: Crop image if required for smaller size
|
||||||
|
|
||||||
// Convert image data from GRAYSCALE to GRAY_ALPHA
|
// Convert image data from GRAYSCALE to GRAY_ALPHA
|
||||||
// WARNING: ImageAlphaMask(&atlas, atlas) does not work in this case, requires manual operation
|
|
||||||
unsigned char *dataGrayAlpha = (unsigned char *)RL_MALLOC(atlas.width*atlas.height*sizeof(unsigned char)*2); // Two channels
|
unsigned char *dataGrayAlpha = (unsigned char *)RL_MALLOC(atlas.width*atlas.height*sizeof(unsigned char)*2); // Two channels
|
||||||
|
|
||||||
for (int i = 0, k = 0; i < atlas.width*atlas.height; i++, k += 2)
|
for (int i = 0, k = 0; i < atlas.width*atlas.height; i++, k += 2)
|
||||||
|
@ -799,7 +826,7 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
|
||||||
|
|
||||||
float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor
|
float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor
|
||||||
|
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length;)
|
||||||
{
|
{
|
||||||
// Get next codepoint from byte string and glyph index in font
|
// Get next codepoint from byte string and glyph index in font
|
||||||
int codepointByteCount = 0;
|
int codepointByteCount = 0;
|
||||||
|
@ -833,7 +860,7 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
|
||||||
else textOffsetX += ((float)font.chars[index].advanceX*scaleFactor + spacing);
|
else textOffsetX += ((float)font.chars[index].advanceX*scaleFactor + spacing);
|
||||||
}
|
}
|
||||||
|
|
||||||
i += (codepointByteCount - 1); // Move text bytes counter to next codepoint
|
i += codepointByteCount; // Move text bytes counter to next codepoint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -945,7 +972,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
|
||||||
bool isGlyphSelected = false;
|
bool isGlyphSelected = false;
|
||||||
if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength)))
|
if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength)))
|
||||||
{
|
{
|
||||||
DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, glyphWidth, (int)((float)font.baseSize*scaleFactor) }, selectBackTint);
|
DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, (float)glyphWidth, (float)font.baseSize*scaleFactor }, selectBackTint);
|
||||||
isGlyphSelected = true;
|
isGlyphSelected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1053,11 +1080,14 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
|
||||||
// Returns index position for a unicode character on spritefont
|
// Returns index position for a unicode character on spritefont
|
||||||
int GetGlyphIndex(Font font, int codepoint)
|
int GetGlyphIndex(Font font, int codepoint)
|
||||||
{
|
{
|
||||||
#define TEXT_CHARACTER_NOTFOUND 63 // Character: '?'
|
#ifndef GLYPH_NOTFOUND_CHAR_FALLBACK
|
||||||
|
#define GLYPH_NOTFOUND_CHAR_FALLBACK 63 // Character used if requested codepoint is not found: '?'
|
||||||
|
#endif
|
||||||
|
|
||||||
#define UNORDERED_CHARSET
|
// Support charsets with any characters order
|
||||||
#if defined(UNORDERED_CHARSET)
|
#define SUPPORT_UNORDERED_CHARSET
|
||||||
int index = TEXT_CHARACTER_NOTFOUND;
|
#if defined(SUPPORT_UNORDERED_CHARSET)
|
||||||
|
int index = GLYPH_NOTFOUND_CHAR_FALLBACK;
|
||||||
|
|
||||||
for (int i = 0; i < font.charsCount; i++)
|
for (int i = 0; i < font.charsCount; i++)
|
||||||
{
|
{
|
||||||
|
@ -1077,7 +1107,64 @@ int GetGlyphIndex(Font font, int codepoint)
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Text strings management functions
|
// Text strings management functions
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
// Get text length in bytes, check for \0 character
|
||||||
|
unsigned int TextLength(const char *text)
|
||||||
|
{
|
||||||
|
unsigned int length = 0; //strlen(text)
|
||||||
|
|
||||||
|
if (text != NULL)
|
||||||
|
{
|
||||||
|
while (*text++) length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formatting of text with variables to 'embed'
|
||||||
|
// WARNING: String returned will expire after this function is called MAX_TEXTFORMAT_BUFFERS times
|
||||||
|
const char *TextFormat(const char *text, ...)
|
||||||
|
{
|
||||||
|
#ifndef MAX_TEXTFORMAT_BUFFERS
|
||||||
|
#define MAX_TEXTFORMAT_BUFFERS 4 // Maximum number of static buffers for text formatting
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations
|
||||||
|
static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||||
|
static int index = 0;
|
||||||
|
|
||||||
|
char *currentBuffer = buffers[index];
|
||||||
|
memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, text);
|
||||||
|
vsprintf(currentBuffer, text, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
index += 1; // Move to next buffer for next function call
|
||||||
|
if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
|
||||||
|
|
||||||
|
return currentBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get integer value from text
|
||||||
|
// NOTE: This function replaces atoi() [stdlib.h]
|
||||||
|
int TextToInteger(const char *text)
|
||||||
|
{
|
||||||
|
int value = 0;
|
||||||
|
int sign = 1;
|
||||||
|
|
||||||
|
if ((text[0] == '+') || (text[0] == '-'))
|
||||||
|
{
|
||||||
|
if (text[0] == '-') sign = -1;
|
||||||
|
text++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0');
|
||||||
|
|
||||||
|
return value*sign;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(SUPPORT_TEXT_MANIPULATION)
|
||||||
// Copy one string to another, returns bytes copied
|
// Copy one string to another, returns bytes copied
|
||||||
int TextCopy(char *dst, const char *src)
|
int TextCopy(char *dst, const char *src)
|
||||||
{
|
{
|
||||||
|
@ -1111,43 +1198,6 @@ bool TextIsEqual(const char *text1, const char *text2)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get text length in bytes, check for \0 character
|
|
||||||
unsigned int TextLength(const char *text)
|
|
||||||
{
|
|
||||||
unsigned int length = 0; //strlen(text)
|
|
||||||
|
|
||||||
if (text != NULL)
|
|
||||||
{
|
|
||||||
while (*text++) length++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Formatting of text with variables to 'embed'
|
|
||||||
// WARNING: String returned will expire after this function is called MAX_TEXTFORMAT_BUFFERS times
|
|
||||||
const char *TextFormat(const char *text, ...)
|
|
||||||
{
|
|
||||||
#define MAX_TEXTFORMAT_BUFFERS 4
|
|
||||||
|
|
||||||
// We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations
|
|
||||||
static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
|
||||||
static int index = 0;
|
|
||||||
|
|
||||||
char *currentBuffer = buffers[index];
|
|
||||||
memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using
|
|
||||||
|
|
||||||
va_list args;
|
|
||||||
va_start(args, text);
|
|
||||||
vsprintf(currentBuffer, text, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
index += 1; // Move to next buffer for next function call
|
|
||||||
if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
|
|
||||||
|
|
||||||
return currentBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a piece of a text string
|
// Get a piece of a text string
|
||||||
const char *TextSubtext(const char *text, int position, int length)
|
const char *TextSubtext(const char *text, int position, int length)
|
||||||
{
|
{
|
||||||
|
@ -1179,6 +1229,9 @@ const char *TextSubtext(const char *text, int position, int length)
|
||||||
// WARNING: Internally allocated memory must be freed by the user (if return != NULL)
|
// WARNING: Internally allocated memory must be freed by the user (if return != NULL)
|
||||||
char *TextReplace(char *text, const char *replace, const char *by)
|
char *TextReplace(char *text, const char *replace, const char *by)
|
||||||
{
|
{
|
||||||
|
// Sanity checks and initialization
|
||||||
|
if (!text || !replace || !by) return NULL;
|
||||||
|
|
||||||
char *result;
|
char *result;
|
||||||
|
|
||||||
char *insertPoint; // Next insert point
|
char *insertPoint; // Next insert point
|
||||||
|
@ -1188,13 +1241,9 @@ char *TextReplace(char *text, const char *replace, const char *by)
|
||||||
int lastReplacePos; // Distance between replace and end of last replace
|
int lastReplacePos; // Distance between replace and end of last replace
|
||||||
int count; // Number of replacements
|
int count; // Number of replacements
|
||||||
|
|
||||||
// Sanity checks and initialization
|
|
||||||
if (!text || !replace) return NULL;
|
|
||||||
|
|
||||||
replaceLen = TextLength(replace);
|
replaceLen = TextLength(replace);
|
||||||
if (replaceLen == 0) return NULL; // Empty replace causes infinite loop during count
|
if (replaceLen == 0) return NULL; // Empty replace causes infinite loop during count
|
||||||
|
|
||||||
if (!by) by = ""; // Replace by nothing if not provided
|
|
||||||
byLen = TextLength(by);
|
byLen = TextLength(by);
|
||||||
|
|
||||||
// Count the number of replacements needed
|
// Count the number of replacements needed
|
||||||
|
@ -1213,7 +1262,7 @@ char *TextReplace(char *text, const char *replace, const char *by)
|
||||||
while (count--)
|
while (count--)
|
||||||
{
|
{
|
||||||
insertPoint = strstr(text, replace);
|
insertPoint = strstr(text, replace);
|
||||||
lastReplacePos = insertPoint - text;
|
lastReplacePos = (int)(insertPoint - text);
|
||||||
temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
|
temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
|
||||||
temp = strcpy(temp, by) + byLen;
|
temp = strcpy(temp, by) + byLen;
|
||||||
text += lastReplacePos + replaceLen; // Move to next "end of replace"
|
text += lastReplacePos + replaceLen; // Move to next "end of replace"
|
||||||
|
@ -1244,29 +1293,32 @@ char *TextInsert(const char *text, const char *insert, int position)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join text strings with delimiter
|
// Join text strings with delimiter
|
||||||
// REQUIRES: strcat()
|
// REQUIRES: memset(), memcpy()
|
||||||
const char *TextJoin(const char **textList, int count, const char *delimiter)
|
const char *TextJoin(const char **textList, int count, const char *delimiter)
|
||||||
{
|
{
|
||||||
static char text[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
static char text[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||||
memset(text, 0, MAX_TEXT_BUFFER_LENGTH);
|
memset(text, 0, MAX_TEXT_BUFFER_LENGTH);
|
||||||
|
char *textPtr = text;
|
||||||
|
|
||||||
int totalLength = 0;
|
int totalLength = 0;
|
||||||
int delimiterLen = TextLength(delimiter);
|
int delimiterLen = TextLength(delimiter);
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
int textListLength = TextLength(textList[i]);
|
int textLength = TextLength(textList[i]);
|
||||||
|
|
||||||
// Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH
|
// Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH
|
||||||
if ((totalLength + textListLength) < MAX_TEXT_BUFFER_LENGTH)
|
if ((totalLength + textLength) < MAX_TEXT_BUFFER_LENGTH)
|
||||||
{
|
{
|
||||||
strcat(text, textList[i]);
|
memcpy(textPtr, textList[i], textLength);
|
||||||
totalLength += textListLength;
|
totalLength += textLength;
|
||||||
|
textPtr += textLength;
|
||||||
|
|
||||||
if ((delimiterLen > 0) && (i < (count - 1)))
|
if ((delimiterLen > 0) && (i < (count - 1)))
|
||||||
{
|
{
|
||||||
strcat(text, delimiter);
|
memcpy(textPtr, delimiter, delimiterLen);
|
||||||
totalLength += delimiterLen;
|
totalLength += delimiterLen;
|
||||||
|
textPtr += delimiterLen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1280,12 +1332,12 @@ const char **TextSplit(const char *text, char delimiter, int *count)
|
||||||
// NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
|
// NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
|
||||||
// inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
|
// inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
|
||||||
// all used memory is static... it has some limitations:
|
// all used memory is static... it has some limitations:
|
||||||
// 1. Maximum number of possible split strings is set by TEXTSPLIT_MAX_SUBSTRINGS_COUNT
|
// 1. Maximum number of possible split strings is set by MAX_TEXTSPLIT_COUNT
|
||||||
// 2. Maximum size of text to split is TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
|
// 2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH
|
||||||
|
|
||||||
static const char *result[TEXTSPLIT_MAX_SUBSTRINGS_COUNT] = { NULL };
|
static const char *result[MAX_TEXTSPLIT_COUNT] = { NULL };
|
||||||
static char buffer[TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
|
||||||
memset(buffer, 0, TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH);
|
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
|
||||||
|
|
||||||
result[0] = buffer;
|
result[0] = buffer;
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
|
@ -1295,7 +1347,7 @@ const char **TextSplit(const char *text, char delimiter, int *count)
|
||||||
counter = 1;
|
counter = 1;
|
||||||
|
|
||||||
// Count how many substrings we have on text and point to every one
|
// Count how many substrings we have on text and point to every one
|
||||||
for (int i = 0; i < TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH; i++)
|
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
|
||||||
{
|
{
|
||||||
buffer[i] = text[i];
|
buffer[i] = text[i];
|
||||||
if (buffer[i] == '\0') break;
|
if (buffer[i] == '\0') break;
|
||||||
|
@ -1305,7 +1357,7 @@ const char **TextSplit(const char *text, char delimiter, int *count)
|
||||||
result[counter] = buffer + i + 1;
|
result[counter] = buffer + i + 1;
|
||||||
counter++;
|
counter++;
|
||||||
|
|
||||||
if (counter == TEXTSPLIT_MAX_SUBSTRINGS_COUNT) break;
|
if (counter == MAX_TEXTSPLIT_COUNT) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1330,7 +1382,7 @@ int TextFindIndex(const char *text, const char *find)
|
||||||
|
|
||||||
char *ptr = strstr(text, find);
|
char *ptr = strstr(text, find);
|
||||||
|
|
||||||
if (ptr != NULL) position = ptr - text;
|
if (ptr != NULL) position = (int)(ptr - text);
|
||||||
|
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
@ -1398,24 +1450,6 @@ const char *TextToPascal(const char *text)
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get integer value from text
|
|
||||||
// NOTE: This function replaces atoi() [stdlib.h]
|
|
||||||
int TextToInteger(const char *text)
|
|
||||||
{
|
|
||||||
int value = 0;
|
|
||||||
int sign = 1;
|
|
||||||
|
|
||||||
if ((text[0] == '+') || (text[0] == '-'))
|
|
||||||
{
|
|
||||||
if (text[0] == '-') sign = -1;
|
|
||||||
text++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0');
|
|
||||||
|
|
||||||
return value*sign;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode text codepoint into utf8 text (memory must be freed!)
|
// Encode text codepoint into utf8 text (memory must be freed!)
|
||||||
char *TextToUtf8(int *codepoints, int length)
|
char *TextToUtf8(int *codepoints, int length)
|
||||||
{
|
{
|
||||||
|
@ -1428,7 +1462,7 @@ char *TextToUtf8(int *codepoints, int length)
|
||||||
for (int i = 0, bytes = 0; i < length; i++)
|
for (int i = 0, bytes = 0; i < length; i++)
|
||||||
{
|
{
|
||||||
utf8 = CodepointToUtf8(codepoints[i], &bytes);
|
utf8 = CodepointToUtf8(codepoints[i], &bytes);
|
||||||
strncpy(text + size, utf8, bytes);
|
memcpy(text + size, utf8, bytes);
|
||||||
size += bytes;
|
size += bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1440,6 +1474,44 @@ char *TextToUtf8(int *codepoints, int length)
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Encode codepoint into utf8 text (char array length returned as parameter)
|
||||||
|
RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength)
|
||||||
|
{
|
||||||
|
static char utf8[6] = { 0 };
|
||||||
|
int length = 0;
|
||||||
|
|
||||||
|
if (codepoint <= 0x7f)
|
||||||
|
{
|
||||||
|
utf8[0] = (char)codepoint;
|
||||||
|
length = 1;
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0x7ff)
|
||||||
|
{
|
||||||
|
utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
|
||||||
|
utf8[1] = (char)((codepoint & 0x3f) | 0x80);
|
||||||
|
length = 2;
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0xffff)
|
||||||
|
{
|
||||||
|
utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
|
||||||
|
utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
|
||||||
|
utf8[2] = (char)((codepoint & 0x3f) | 0x80);
|
||||||
|
length = 3;
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0x10ffff)
|
||||||
|
{
|
||||||
|
utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0);
|
||||||
|
utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
|
||||||
|
utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
|
||||||
|
utf8[3] = (char)((codepoint & 0x3f) | 0x80);
|
||||||
|
length = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
*byteLength = length;
|
||||||
|
|
||||||
|
return utf8;
|
||||||
|
}
|
||||||
|
|
||||||
// Get all codepoints in a string, codepoints count returned by parameters
|
// Get all codepoints in a string, codepoints count returned by parameters
|
||||||
int *GetCodepoints(const char *text, int *count)
|
int *GetCodepoints(const char *text, int *count)
|
||||||
{
|
{
|
||||||
|
@ -1481,7 +1553,7 @@ int GetCodepointsCount(const char *text)
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
#endif // SUPPORT_TEXT_MANIPULATION
|
||||||
|
|
||||||
// Returns next codepoint in a UTF8 encoded text, scanning until '\0' is found
|
// Returns next codepoint in a UTF8 encoded text, scanning until '\0' is found
|
||||||
// When a invalid UTF8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
|
// When a invalid UTF8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
|
||||||
|
@ -1595,50 +1667,23 @@ int GetNextCodepoint(const char *text, int *bytesProcessed)
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode codepoint into utf8 text (char array length returned as parameter)
|
|
||||||
RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength)
|
|
||||||
{
|
|
||||||
static char utf8[6] = { 0 };
|
|
||||||
int length = 0;
|
|
||||||
|
|
||||||
if (codepoint <= 0x7f)
|
|
||||||
{
|
|
||||||
utf8[0] = (char)codepoint;
|
|
||||||
length = 1;
|
|
||||||
}
|
|
||||||
else if (codepoint <= 0x7ff)
|
|
||||||
{
|
|
||||||
utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
|
|
||||||
utf8[1] = (char)((codepoint & 0x3f) | 0x80);
|
|
||||||
length = 2;
|
|
||||||
}
|
|
||||||
else if (codepoint <= 0xffff)
|
|
||||||
{
|
|
||||||
utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
|
|
||||||
utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
|
|
||||||
utf8[2] = (char)((codepoint & 0x3f) | 0x80);
|
|
||||||
length = 3;
|
|
||||||
}
|
|
||||||
else if (codepoint <= 0x10ffff)
|
|
||||||
{
|
|
||||||
utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0);
|
|
||||||
utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
|
|
||||||
utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
|
|
||||||
utf8[3] = (char)((codepoint & 0x3f) | 0x80);
|
|
||||||
length = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
*byteLength = length;
|
|
||||||
|
|
||||||
return utf8;
|
|
||||||
}
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module specific Functions Definition
|
// Module specific Functions Definition
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
#if defined(SUPPORT_FILEFORMAT_FNT)
|
#if defined(SUPPORT_FILEFORMAT_FNT)
|
||||||
|
|
||||||
|
// Read a line from memory
|
||||||
|
// NOTE: Returns the number of bytes read
|
||||||
|
static int GetLine(const char *origin, char *buffer, int maxLength)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
for (; count < maxLength; count++) if (origin[count] == '\n') break;
|
||||||
|
memcpy(buffer, origin, count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
// Load a BMFont file (AngelCode font file)
|
// Load a BMFont file (AngelCode font file)
|
||||||
|
// REQUIRES: strstr(), sscanf(), strrchr(), memcpy()
|
||||||
static Font LoadBMFont(const char *fileName)
|
static Font LoadBMFont(const char *fileName)
|
||||||
{
|
{
|
||||||
#define MAX_BUFFER_SIZE 256
|
#define MAX_BUFFER_SIZE 256
|
||||||
|
@ -1649,80 +1694,92 @@ static Font LoadBMFont(const char *fileName)
|
||||||
char *searchPoint = NULL;
|
char *searchPoint = NULL;
|
||||||
|
|
||||||
int fontSize = 0;
|
int fontSize = 0;
|
||||||
int texWidth = 0;
|
|
||||||
int texHeight = 0;
|
|
||||||
char texFileName[129];
|
|
||||||
int charsCount = 0;
|
int charsCount = 0;
|
||||||
|
|
||||||
|
int imWidth = 0;
|
||||||
|
int imHeight = 0;
|
||||||
|
char imFileName[129];
|
||||||
|
|
||||||
int base = 0; // Useless data
|
int base = 0; // Useless data
|
||||||
|
|
||||||
FILE *fntFile = NULL;
|
char *fileText = LoadFileText(fileName);
|
||||||
|
|
||||||
fntFile = fopen(fileName, "rt");
|
if (fileText == NULL) return font;
|
||||||
|
|
||||||
if (fntFile == NULL)
|
char *fileTextPtr = fileText;
|
||||||
{
|
|
||||||
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open FNT file", fileName);
|
|
||||||
return font;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: We skip first line, it contains no useful information
|
// NOTE: We skip first line, it contains no useful information
|
||||||
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
|
int lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
|
||||||
//searchPoint = strstr(buffer, "size");
|
fileTextPtr += (lineBytes + 1);
|
||||||
//sscanf(searchPoint, "size=%i", &fontSize);
|
|
||||||
|
|
||||||
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
|
// Read line data
|
||||||
|
lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
|
||||||
searchPoint = strstr(buffer, "lineHeight");
|
searchPoint = strstr(buffer, "lineHeight");
|
||||||
sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &texWidth, &texHeight);
|
sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &imWidth, &imHeight);
|
||||||
|
fileTextPtr += (lineBytes + 1);
|
||||||
|
|
||||||
TRACELOGD("FONT: [%s] Loaded font info:", fileName);
|
TRACELOGD("FONT: [%s] Loaded font info:", fileName);
|
||||||
TRACELOGD(" > Base size: %i", fontSize);
|
TRACELOGD(" > Base size: %i", fontSize);
|
||||||
TRACELOGD(" > Texture scale: %ix%i", texWidth, texHeight);
|
TRACELOGD(" > Texture scale: %ix%i", imWidth, imHeight);
|
||||||
|
|
||||||
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
|
lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
|
||||||
searchPoint = strstr(buffer, "file");
|
searchPoint = strstr(buffer, "file");
|
||||||
sscanf(searchPoint, "file=\"%128[^\"]\"", texFileName);
|
sscanf(searchPoint, "file=\"%128[^\"]\"", imFileName);
|
||||||
|
fileTextPtr += (lineBytes + 1);
|
||||||
|
|
||||||
TRACELOGD(" > Texture filename: %s", texFileName);
|
TRACELOGD(" > Texture filename: %s", imFileName);
|
||||||
|
|
||||||
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
|
lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
|
||||||
searchPoint = strstr(buffer, "count");
|
searchPoint = strstr(buffer, "count");
|
||||||
sscanf(searchPoint, "count=%i", &charsCount);
|
sscanf(searchPoint, "count=%i", &charsCount);
|
||||||
|
fileTextPtr += (lineBytes + 1);
|
||||||
|
|
||||||
TRACELOGD(" > Chars count: %i", charsCount);
|
TRACELOGD(" > Chars count: %i", charsCount);
|
||||||
|
|
||||||
// Compose correct path using route of .fnt file (fileName) and texFileName
|
// Compose correct path using route of .fnt file (fileName) and imFileName
|
||||||
char *texPath = NULL;
|
char *imPath = NULL;
|
||||||
char *lastSlash = NULL;
|
char *lastSlash = NULL;
|
||||||
|
|
||||||
lastSlash = strrchr(fileName, '/');
|
lastSlash = strrchr(fileName, '/');
|
||||||
if (lastSlash == NULL)
|
if (lastSlash == NULL) lastSlash = strrchr(fileName, '\\');
|
||||||
|
|
||||||
|
if (lastSlash != NULL)
|
||||||
{
|
{
|
||||||
lastSlash = strrchr(fileName, '\\');
|
// NOTE: We need some extra space to avoid memory corruption on next allocations!
|
||||||
|
imPath = 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));
|
||||||
}
|
}
|
||||||
|
else imPath = imFileName;
|
||||||
|
|
||||||
// NOTE: We need some extra space to avoid memory corruption on next allocations!
|
TRACELOGD(" > Image loading path: %s", imPath);
|
||||||
texPath = RL_MALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(texFileName) + 4);
|
|
||||||
|
|
||||||
// NOTE: strcat() and strncat() required a '\0' terminated string to work!
|
Image imFont = LoadImage(imPath);
|
||||||
*texPath = '\0';
|
|
||||||
strncat(texPath, fileName, TextLength(fileName) - TextLength(lastSlash) + 1);
|
|
||||||
strncat(texPath, texFileName, TextLength(texFileName));
|
|
||||||
|
|
||||||
TRACELOGD(" > Texture loading path: %s", texPath);
|
|
||||||
|
|
||||||
Image imFont = LoadImage(texPath);
|
|
||||||
|
|
||||||
if (imFont.format == UNCOMPRESSED_GRAYSCALE)
|
if (imFont.format == UNCOMPRESSED_GRAYSCALE)
|
||||||
{
|
{
|
||||||
// Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
|
// Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
|
||||||
ImageAlphaMask(&imFont, imFont);
|
Image imFontAlpha = {
|
||||||
for (int p = 0; p < (imFont.width*imFont.height*2); p += 2) ((unsigned char *)(imFont.data))[p] = 0xff;
|
.data = calloc(imFont.width*imFont.height, 2),
|
||||||
|
.width = imFont.width,
|
||||||
|
.height = imFont.height,
|
||||||
|
.format = UNCOMPRESSED_GRAY_ALPHA,
|
||||||
|
.mipmaps = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int p = 0, i = 0; p < (imFont.width*imFont.height*2); p += 2, i++)
|
||||||
|
{
|
||||||
|
((unsigned char *)(imFontAlpha.data))[p] = 0xff;
|
||||||
|
((unsigned char *)(imFontAlpha.data))[p + 1] = ((unsigned char *)imFont.data)[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
UnloadImage(imFont);
|
||||||
|
imFont = imFontAlpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
font.texture = LoadTextureFromImage(imFont);
|
font.texture = LoadTextureFromImage(imFont);
|
||||||
|
|
||||||
RL_FREE(texPath);
|
if (lastSlash != NULL) RL_FREE(imPath);
|
||||||
|
|
||||||
// Fill font characters info data
|
// Fill font characters info data
|
||||||
font.baseSize = fontSize;
|
font.baseSize = fontSize;
|
||||||
|
@ -1734,9 +1791,10 @@ static Font LoadBMFont(const char *fileName)
|
||||||
|
|
||||||
for (int i = 0; i < charsCount; i++)
|
for (int i = 0; i < charsCount; i++)
|
||||||
{
|
{
|
||||||
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
|
lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
|
||||||
sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i",
|
sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i",
|
||||||
&charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX);
|
&charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX);
|
||||||
|
fileTextPtr += (lineBytes + 1);
|
||||||
|
|
||||||
// Get character rectangle in the font atlas texture
|
// Get character rectangle in the font atlas texture
|
||||||
font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight };
|
font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight };
|
||||||
|
@ -1752,8 +1810,7 @@ static Font LoadBMFont(const char *fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
UnloadImage(imFont);
|
UnloadImage(imFont);
|
||||||
|
RL_FREE(fileText);
|
||||||
fclose(fntFile);
|
|
||||||
|
|
||||||
if (font.texture.id == 0)
|
if (font.texture.id == 0)
|
||||||
{
|
{
|
||||||
|
|
4067
raylib/textures.c
4067
raylib/textures.c
File diff suppressed because it is too large
Load diff
|
@ -49,27 +49,6 @@ func LoadImage(fileName string) *Image {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadImageEx - Load image data from Color array data (RGBA - 32bit)
|
|
||||||
func LoadImageEx(pixels []Color, width, height int32) *Image {
|
|
||||||
cpixels := pixels[0].cptr()
|
|
||||||
cwidth := (C.int)(width)
|
|
||||||
cheight := (C.int)(height)
|
|
||||||
ret := C.LoadImageEx(cpixels, cwidth, cheight)
|
|
||||||
v := newImageFromPointer(unsafe.Pointer(&ret))
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadImagePro - Load image from raw data with parameters
|
|
||||||
func LoadImagePro(data []byte, width, height int32, format PixelFormat) *Image {
|
|
||||||
cdata := unsafe.Pointer(&data[0])
|
|
||||||
cwidth := (C.int)(width)
|
|
||||||
cheight := (C.int)(height)
|
|
||||||
cformat := (C.int)(format)
|
|
||||||
ret := C.LoadImagePro(cdata, cwidth, cheight, cformat)
|
|
||||||
v := newImageFromPointer(unsafe.Pointer(&ret))
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadImageRaw - Load image data from RAW file
|
// LoadImageRaw - Load image data from RAW file
|
||||||
func LoadImageRaw(fileName string, width, height int32, format PixelFormat, headerSize int32) *Image {
|
func LoadImageRaw(fileName string, width, height int32, format PixelFormat, headerSize int32) *Image {
|
||||||
cfileName := C.CString(fileName)
|
cfileName := C.CString(fileName)
|
||||||
|
@ -165,6 +144,14 @@ func UpdateTexture(texture Texture2D, pixels []Color) {
|
||||||
C.UpdateTexture(*ctexture, cpixels)
|
C.UpdateTexture(*ctexture, cpixels)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateTextureRec - Update GPU texture rectangle with new data
|
||||||
|
func UpdateTextureRec(texture Texture2D, rec Rectangle, pixels []Color) {
|
||||||
|
ctexture := texture.cptr()
|
||||||
|
cpixels := unsafe.Pointer(&pixels[0])
|
||||||
|
crec := rec.cptr()
|
||||||
|
C.UpdateTextureRec(*ctexture, *crec, cpixels)
|
||||||
|
}
|
||||||
|
|
||||||
// ExportImage - Export image as a PNG file
|
// ExportImage - Export image as a PNG file
|
||||||
func ExportImage(image Image, name string) {
|
func ExportImage(image Image, name string) {
|
||||||
cname := C.CString(name)
|
cname := C.CString(name)
|
||||||
|
@ -329,14 +316,15 @@ func ImageDrawRectangleLines(dst *Image, rec Rectangle, thick int, color Color)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImageDrawText - Draw text (default font) within an image (destination)
|
// ImageDrawText - Draw text (default font) within an image (destination)
|
||||||
func ImageDrawText(dst *Image, position Vector2, text string, fontSize int32, color Color) {
|
func ImageDrawText(dst *Image, posX, posY int32, text string, fontSize int32, color Color) {
|
||||||
cdst := dst.cptr()
|
cdst := dst.cptr()
|
||||||
cposition := position.cptr()
|
posx := (C.int)(posX)
|
||||||
|
posy := (C.int)(posY)
|
||||||
ctext := C.CString(text)
|
ctext := C.CString(text)
|
||||||
defer C.free(unsafe.Pointer(ctext))
|
defer C.free(unsafe.Pointer(ctext))
|
||||||
cfontSize := (C.int)(fontSize)
|
cfontSize := (C.int)(fontSize)
|
||||||
ccolor := color.cptr()
|
ccolor := color.cptr()
|
||||||
C.ImageDrawText(cdst, *cposition, ctext, cfontSize, *ccolor)
|
C.ImageDrawText(cdst, ctext, posx, posy, cfontSize, *ccolor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImageDrawTextEx - Draw text (custom sprite font) within an image (destination)
|
// ImageDrawTextEx - Draw text (custom sprite font) within an image (destination)
|
||||||
|
@ -349,7 +337,7 @@ func ImageDrawTextEx(dst *Image, position Vector2, font Font, text string, fontS
|
||||||
cfontSize := (C.float)(fontSize)
|
cfontSize := (C.float)(fontSize)
|
||||||
cspacing := (C.float)(spacing)
|
cspacing := (C.float)(spacing)
|
||||||
ccolor := color.cptr()
|
ccolor := color.cptr()
|
||||||
C.ImageDrawTextEx(cdst, *cposition, *cfont, ctext, cfontSize, cspacing, *ccolor)
|
C.ImageDrawTextEx(cdst, *cfont, ctext, *cposition, cfontSize, cspacing, *ccolor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImageFlipVertical - Flip image vertically
|
// ImageFlipVertical - Flip image vertically
|
||||||
|
|
113
raylib/utils.c
113
raylib/utils.c
|
@ -50,9 +50,15 @@
|
||||||
#include <stdarg.h> // Required for: va_list, va_start(), va_end()
|
#include <stdarg.h> // Required for: va_list, va_start(), va_end()
|
||||||
#include <string.h> // Required for: strcpy(), strcat()
|
#include <string.h> // Required for: strcpy(), strcat()
|
||||||
|
|
||||||
#define MAX_TRACELOG_BUFFER_SIZE 128 // Max length of one trace-log message
|
//----------------------------------------------------------------------------------
|
||||||
|
// Defines and Macros
|
||||||
#define MAX_UWP_MESSAGES 512 // Max UWP messages to process
|
//----------------------------------------------------------------------------------
|
||||||
|
#ifndef MAX_TRACELOG_MSG_LENGTH
|
||||||
|
#define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message
|
||||||
|
#endif
|
||||||
|
#ifndef MAX_UWP_MESSAGES
|
||||||
|
#define MAX_UWP_MESSAGES 512 // Max UWP messages to process
|
||||||
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Global Variables Definition
|
// Global Variables Definition
|
||||||
|
@ -68,13 +74,6 @@ static AAssetManager *assetManager = NULL; // Android assets manage
|
||||||
static const char *internalDataPath = NULL; // Android internal data path
|
static const char *internalDataPath = NULL; // Android internal data path
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(PLATFORM_UWP)
|
|
||||||
static int UWPOutMessageId = -1; // Last index of output message
|
|
||||||
static UWPMessage *UWPOutMessages[MAX_UWP_MESSAGES]; // Messages out to UWP
|
|
||||||
static int UWPInMessageId = -1; // Last index of input message
|
|
||||||
static UWPMessage *UWPInMessages[MAX_UWP_MESSAGES]; // Messages in from UWP
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
// Module specific Functions Declaration
|
// Module specific Functions Declaration
|
||||||
//----------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------
|
||||||
|
@ -139,7 +138,7 @@ void TraceLog(int logType, const char *text, ...)
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
char buffer[MAX_TRACELOG_BUFFER_SIZE] = { 0 };
|
char buffer[MAX_TRACELOG_MSG_LENGTH] = { 0 };
|
||||||
|
|
||||||
switch (logType)
|
switch (logType)
|
||||||
{
|
{
|
||||||
|
@ -184,10 +183,10 @@ unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead)
|
||||||
|
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
{
|
{
|
||||||
data = (unsigned char *)RL_MALLOC(sizeof(unsigned char)*size);
|
data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char));
|
||||||
|
|
||||||
// NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements]
|
// NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements]
|
||||||
unsigned int count = fread(data, sizeof(unsigned char), size, file);
|
unsigned int count = (unsigned int)fread(data, sizeof(unsigned char), size, file);
|
||||||
*bytesRead = count;
|
*bytesRead = count;
|
||||||
|
|
||||||
if (count != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded", fileName);
|
if (count != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded", fileName);
|
||||||
|
@ -213,7 +212,7 @@ void SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite)
|
||||||
|
|
||||||
if (file != NULL)
|
if (file != NULL)
|
||||||
{
|
{
|
||||||
unsigned int count = fwrite(data, sizeof(unsigned char), bytesToWrite, file);
|
unsigned int count = (unsigned int)fwrite(data, sizeof(unsigned char), bytesToWrite, file);
|
||||||
|
|
||||||
if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write file", fileName);
|
if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write file", fileName);
|
||||||
else if (count != bytesToWrite) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName);
|
else if (count != bytesToWrite) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName);
|
||||||
|
@ -242,13 +241,13 @@ char *LoadFileText(const char *fileName)
|
||||||
// text mode causes carriage return-linefeed translation...
|
// text mode causes carriage return-linefeed translation...
|
||||||
// ...but using fseek() should return correct byte-offset
|
// ...but using fseek() should return correct byte-offset
|
||||||
fseek(textFile, 0, SEEK_END);
|
fseek(textFile, 0, SEEK_END);
|
||||||
int size = ftell(textFile);
|
unsigned int size = (unsigned int)ftell(textFile);
|
||||||
fseek(textFile, 0, SEEK_SET);
|
fseek(textFile, 0, SEEK_SET);
|
||||||
|
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
{
|
{
|
||||||
text = (char *)RL_MALLOC(sizeof(char)*(size + 1));
|
text = (char *)RL_MALLOC((size + 1)*sizeof(char));
|
||||||
int count = fread(text, sizeof(char), size, textFile);
|
unsigned int count = (unsigned int)fread(text, sizeof(char), size, textFile);
|
||||||
|
|
||||||
// WARNING: \r\n is converted to \n on reading, so,
|
// WARNING: \r\n is converted to \n on reading, so,
|
||||||
// read bytes count gets reduced by the number of lines
|
// read bytes count gets reduced by the number of lines
|
||||||
|
@ -318,8 +317,18 @@ FILE *android_fopen(const char *fileName, const char *mode)
|
||||||
// NOTE: AAsset provides access to read-only asset
|
// NOTE: AAsset provides access to read-only asset
|
||||||
AAsset *asset = AAssetManager_open(assetManager, fileName, AASSET_MODE_UNKNOWN);
|
AAsset *asset = AAssetManager_open(assetManager, fileName, AASSET_MODE_UNKNOWN);
|
||||||
|
|
||||||
if (asset != NULL) return funopen(asset, android_read, android_write, android_seek, android_close);
|
if (asset != NULL)
|
||||||
else return NULL;
|
{
|
||||||
|
// Return pointer to file in the assets
|
||||||
|
return funopen(asset, android_read, android_write, android_seek, android_close);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#undef fopen
|
||||||
|
// Just do a regular open if file is not found in the assets
|
||||||
|
return fopen(TextFormat("%s/%s", internalDataPath, fileName), mode);
|
||||||
|
#define fopen(name, mode) android_fopen(name, mode)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // PLATFORM_ANDROID
|
#endif // PLATFORM_ANDROID
|
||||||
|
@ -351,69 +360,3 @@ static int android_close(void *cookie)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif // PLATFORM_ANDROID
|
#endif // PLATFORM_ANDROID
|
||||||
|
|
||||||
#if defined(PLATFORM_UWP)
|
|
||||||
UWPMessage *CreateUWPMessage(void)
|
|
||||||
{
|
|
||||||
UWPMessage *msg = (UWPMessage *)RL_MALLOC(sizeof(UWPMessage));
|
|
||||||
msg->type = UWP_MSG_NONE;
|
|
||||||
Vector2 v0 = { 0, 0 };
|
|
||||||
msg->paramVector0 = v0;
|
|
||||||
msg->paramInt0 = 0;
|
|
||||||
msg->paramInt1 = 0;
|
|
||||||
msg->paramChar0 = 0;
|
|
||||||
msg->paramFloat0 = 0;
|
|
||||||
msg->paramDouble0 = 0;
|
|
||||||
msg->paramBool0 = false;
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeleteUWPMessage(UWPMessage *msg)
|
|
||||||
{
|
|
||||||
RL_FREE(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UWPHasMessages(void)
|
|
||||||
{
|
|
||||||
return (UWPOutMessageId > -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
UWPMessage *UWPGetMessage(void)
|
|
||||||
{
|
|
||||||
if (UWPHasMessages()) return UWPOutMessages[UWPOutMessageId--];
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UWPSendMessage(UWPMessage *msg)
|
|
||||||
{
|
|
||||||
if ((UWPInMessageId + 1) < MAX_UWP_MESSAGES)
|
|
||||||
{
|
|
||||||
UWPInMessageId++;
|
|
||||||
UWPInMessages[UWPInMessageId] = msg;
|
|
||||||
}
|
|
||||||
else TRACELOG(LOG_WARNING, "UWP: Not enough array space to register new inbound message");
|
|
||||||
}
|
|
||||||
|
|
||||||
void SendMessageToUWP(UWPMessage *msg)
|
|
||||||
{
|
|
||||||
if ((UWPOutMessageId + 1) < MAX_UWP_MESSAGES)
|
|
||||||
{
|
|
||||||
UWPOutMessageId++;
|
|
||||||
UWPOutMessages[UWPOutMessageId] = msg;
|
|
||||||
}
|
|
||||||
else TRACELOG(LOG_WARNING, "UWP: Not enough array space to register new outward message");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasMessageFromUWP(void)
|
|
||||||
{
|
|
||||||
return UWPInMessageId > -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
UWPMessage *GetMessageFromUWP(void)
|
|
||||||
{
|
|
||||||
if (HasMessageFromUWP()) return UWPInMessages[UWPInMessageId--];
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif // PLATFORM_UWP
|
|
||||||
|
|
|
@ -72,65 +72,6 @@ void InitAssetManager(AAssetManager *manager, const char *dataPath); // Initia
|
||||||
FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen() -> Read-only!
|
FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen() -> Read-only!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(PLATFORM_UWP)
|
|
||||||
// UWP Messages System
|
|
||||||
typedef enum {
|
|
||||||
UWP_MSG_NONE = 0,
|
|
||||||
|
|
||||||
// Send
|
|
||||||
UWP_MSG_SHOW_MOUSE,
|
|
||||||
UWP_MSG_HIDE_MOUSE,
|
|
||||||
UWP_MSG_LOCK_MOUSE,
|
|
||||||
UWP_MSG_UNLOCK_MOUSE,
|
|
||||||
UWP_MSG_SET_MOUSE_LOCATION, // paramVector0 (pos)
|
|
||||||
|
|
||||||
// Receive (Into C)
|
|
||||||
UWP_MSG_REGISTER_KEY, // paramInt0 (key), paramChar0 (status)
|
|
||||||
UWP_MSG_REGISTER_CLICK, // paramInt0 (button), paramChar0 (status)
|
|
||||||
UWP_MSG_SCROLL_WHEEL_UPDATE, // paramInt0 (delta)
|
|
||||||
UWP_MSG_UPDATE_MOUSE_LOCATION, // paramVector0 (pos)
|
|
||||||
UWP_MSG_SET_GAMEPAD_ACTIVE, // paramInt0 (gamepad), paramBool0 (active or not)
|
|
||||||
UWP_MSG_SET_GAMEPAD_BUTTON, // paramInt0 (gamepad), paramInt1 (button), paramChar0 (status)
|
|
||||||
UWP_MSG_SET_GAMEPAD_AXIS, // paramInt0 (gamepad), int1 (axis), paramFloat0 (value)
|
|
||||||
UWP_MSG_SET_DISPLAY_DIMS, // paramVector0 (display dimensions)
|
|
||||||
UWP_MSG_HANDLE_RESIZE, // paramVector0 (new dimensions) - Onresized event
|
|
||||||
UWP_MSG_SET_GAME_TIME, // paramInt0
|
|
||||||
} UWPMessageType;
|
|
||||||
|
|
||||||
typedef struct UWPMessage {
|
|
||||||
UWPMessageType type; // Message type
|
|
||||||
|
|
||||||
Vector2 paramVector0; // Vector parameters
|
|
||||||
int paramInt0; // Int parameter
|
|
||||||
int paramInt1; // Int parameter
|
|
||||||
char paramChar0; // Char parameters
|
|
||||||
float paramFloat0; // Float parameters
|
|
||||||
double paramDouble0; // Double parameters
|
|
||||||
bool paramBool0; // Bool parameters
|
|
||||||
|
|
||||||
// More parameters can be added and fed to functions
|
|
||||||
} UWPMessage;
|
|
||||||
|
|
||||||
// Allocate UWP Message
|
|
||||||
RLAPI UWPMessage* CreateUWPMessage(void);
|
|
||||||
|
|
||||||
// Free UWP Message
|
|
||||||
RLAPI void DeleteUWPMessage(UWPMessage* msg);
|
|
||||||
|
|
||||||
// Get messages into C++
|
|
||||||
RLAPI bool UWPHasMessages(void);
|
|
||||||
RLAPI UWPMessage* UWPGetMessage(void);
|
|
||||||
RLAPI void UWPSendMessage(UWPMessage* msg);
|
|
||||||
|
|
||||||
// For C to call
|
|
||||||
#ifndef __cplusplus // Hide from C++ code
|
|
||||||
void SendMessageToUWP(UWPMessage* msg);
|
|
||||||
bool HasMessageFromUWP(void);
|
|
||||||
UWPMessage* GetMessageFromUWP(void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif //defined(PLATFORM_UWP)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
119
raylib/uwp_events.h
Normal file
119
raylib/uwp_events.h
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
/**********************************************************************************************
|
||||||
|
*
|
||||||
|
* raylib.uwp_events - Functions for bootstrapping UWP functionality within raylib's core.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* LICENSE: zlib/libpng
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-2020 Reece Mackie (@Rover656)
|
||||||
|
*
|
||||||
|
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||||
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose, including commercial
|
||||||
|
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||||
|
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||||
|
* in the product documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||||
|
* as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*
|
||||||
|
**********************************************************************************************/
|
||||||
|
|
||||||
|
#ifndef UWP_EVENTS_H
|
||||||
|
#define UWP_EVENTS_H
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PLATFORM_UWP)
|
||||||
|
|
||||||
|
// Determine if UWP functions are set and ready for raylib's use.
|
||||||
|
bool UWPIsConfigured();
|
||||||
|
|
||||||
|
// Call this to set the UWP data path you wish for saving and loading.
|
||||||
|
void UWPSetDataPath(const char* path);
|
||||||
|
|
||||||
|
// Function for getting program time.
|
||||||
|
typedef double(*UWPQueryTimeFunc)();
|
||||||
|
UWPQueryTimeFunc UWPGetQueryTimeFunc(void);
|
||||||
|
void UWPSetQueryTimeFunc(UWPQueryTimeFunc func);
|
||||||
|
|
||||||
|
// Function for sleeping the current thread
|
||||||
|
typedef void (*UWPSleepFunc)(double sleepUntil);
|
||||||
|
UWPSleepFunc UWPGetSleepFunc(void);
|
||||||
|
void UWPSetSleepFunc(UWPSleepFunc func);
|
||||||
|
|
||||||
|
// Function for querying the display size
|
||||||
|
typedef void(*UWPDisplaySizeFunc)(int* width, int* height);
|
||||||
|
UWPDisplaySizeFunc UWPGetDisplaySizeFunc(void);
|
||||||
|
void UWPSetDisplaySizeFunc(UWPDisplaySizeFunc func);
|
||||||
|
|
||||||
|
// Functions for mouse cursor control
|
||||||
|
typedef void(*UWPMouseFunc)(void);
|
||||||
|
UWPMouseFunc UWPGetMouseLockFunc();
|
||||||
|
void UWPSetMouseLockFunc(UWPMouseFunc func);
|
||||||
|
UWPMouseFunc UWPGetMouseUnlockFunc();
|
||||||
|
void UWPSetMouseUnlockFunc(UWPMouseFunc func);
|
||||||
|
UWPMouseFunc UWPGetMouseShowFunc();
|
||||||
|
void UWPSetMouseShowFunc(UWPMouseFunc func);
|
||||||
|
UWPMouseFunc UWPGetMouseHideFunc();
|
||||||
|
void UWPSetMouseHideFunc(UWPMouseFunc func);
|
||||||
|
|
||||||
|
// Function for setting mouse cursor position.
|
||||||
|
typedef void (*UWPMouseSetPosFunc)(int x, int y);
|
||||||
|
UWPMouseSetPosFunc UWPGetMouseSetPosFunc();
|
||||||
|
void UWPSetMouseSetPosFunc(UWPMouseSetPosFunc func);
|
||||||
|
|
||||||
|
// The below functions are implemented in core.c but are placed here so they can be called by user code.
|
||||||
|
// This choice is made as platform-specific code is preferred to be kept away from raylib.h
|
||||||
|
|
||||||
|
// Call this when a Key is pressed or released.
|
||||||
|
void UWPKeyDownEvent(int key, bool down, bool controlKey);
|
||||||
|
|
||||||
|
// Call this on the CoreWindow::CharacterRecieved event
|
||||||
|
void UWPKeyCharEvent(int key);
|
||||||
|
|
||||||
|
// Call when a mouse button state changes
|
||||||
|
void UWPMouseButtonEvent(int button, bool down);
|
||||||
|
|
||||||
|
// Call when the mouse cursor moves
|
||||||
|
void UWPMousePosEvent(double x, double y);
|
||||||
|
|
||||||
|
// Call when the mouse wheel moves
|
||||||
|
void UWPMouseWheelEvent(int deltaY);
|
||||||
|
|
||||||
|
// Call when the window resizes
|
||||||
|
void UWPResizeEvent(int width, int height);
|
||||||
|
|
||||||
|
// Call when a gamepad is made active
|
||||||
|
void UWPActivateGamepadEvent(int gamepad, bool active);
|
||||||
|
|
||||||
|
// Call when a gamepad button state changes
|
||||||
|
void UWPRegisterGamepadButton(int gamepad, int button, bool down);
|
||||||
|
|
||||||
|
// Call when a gamepad axis state changes
|
||||||
|
void UWPRegisterGamepadAxis(int gamepad, int axis, float value);
|
||||||
|
|
||||||
|
// Call when the touch point moves
|
||||||
|
void UWPGestureMove(int pointer, float x, float y);
|
||||||
|
|
||||||
|
// Call when there is a touch down or up
|
||||||
|
void UWPGestureTouch(int pointer, float x, float y, bool touch);
|
||||||
|
|
||||||
|
// Set the core window pointer so that we can pass it to EGL.
|
||||||
|
void* UWPGetCoreWindowPtr();
|
||||||
|
void UWPSetCoreWindowPtr(void* ptr);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // PLATFORM_UWP
|
||||||
|
|
||||||
|
#endif // UWP_EVENTS_H
|
Loading…
Add table
Add a link
Reference in a new issue