update raylib and deps

This commit is contained in:
Juan Medina 2020-09-02 13:57:04 +01:00
parent fd64d4172a
commit 276beaf660
32 changed files with 43820 additions and 12589 deletions

View file

@ -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.

View file

@ -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()
}

View file

@ -135,6 +135,9 @@ void SetCameraMoveControls(int frontKey, int backKey,
#include <math.h> // Required for: sinf(), cosf(), sqrtf()
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#ifndef PI
#define PI 3.14159265358979323846
#endif
@ -145,9 +148,6 @@ void SetCameraMoveControls(int frontKey, int backKey,
#define RAD2DEG (180.0f/PI)
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
// Camera mouse movement sensitivity
#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f
#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_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_WAVING_DIVIDER 200.0f
@ -197,17 +197,18 @@ typedef enum {
MOVE_DOWN
} CameraMove;
// Camera global state context data
// Camera global state context data [56 bytes]
typedef struct {
int mode; // Current camera mode
unsigned int mode; // Current camera mode
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
int moveControl[6];
int smoothZoomControl; // raylib: KEY_LEFT_CONTROL
int altControl; // raylib: KEY_LEFT_ALT
int panControl; // raylib: MOUSE_MIDDLE_BUTTON
// Camera movement control keys
int moveControl[6]; // Move controls (CAMERA_FIRST_PERSON)
int smoothZoomControl; // Smooth zoom control key
int altControl; // Alternative control key
int panControl; // Pan view control key
} CameraData;
//----------------------------------------------------------------------------------
@ -219,9 +220,9 @@ static CameraData CAMERA = { // Global CAMERA state context
.playerEyesPosition = 1.85f,
.angle = { 0 },
.moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' },
.smoothZoomControl = 341,
.altControl = 342,
.panControl = 2
.smoothZoomControl = 341, // raylib: KEY_LEFT_CONTROL
.altControl = 342, // raylib: KEY_LEFT_ALT
.panControl = 2 // raylib: MOUSE_MIDDLE_BUTTON
};
//----------------------------------------------------------------------------------
@ -253,13 +254,13 @@ void SetCameraMode(Camera camera, int mode)
float dy = v2.y - v1.y;
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.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.x = atan2f(dx, dz); // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz)); // Camera angle in plane XY (0 aligned with X, move positive CW)
CAMERA.playerEyesPosition = camera.position.y;
CAMERA.playerEyesPosition = camera.position.y; // Init player eyes position to camera Y position
// Lock cursor for first person and third person cameras
if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor();
@ -287,6 +288,7 @@ void UpdateCamera(Camera *camera)
int mouseWheelMove = GetMouseWheelMove();
// Keys input detection
// TODO: Input detection is raylib-dependant, it could be moved outside the module
bool panKey = IsMouseButtonDown(CAMERA.panControl);
bool altKey = IsKeyDown(CAMERA.altControl);
bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl);
@ -297,8 +299,6 @@ void UpdateCamera(Camera *camera)
IsKeyDown(CAMERA.moveControl[MOVE_UP]),
IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) };
// TODO: Touch input detection (probably gestures system required)
if (CAMERA.mode != CAMERA_CUSTOM)
{
mousePositionDelta.x = mousePosition.x - previousMousePosition.x;
@ -321,7 +321,6 @@ void UpdateCamera(Camera *camera)
}
// 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))
{
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;
}
// 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))
{
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...
camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
} break;

View file

@ -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
#if defined(RAYLIB_CMAKE)
@ -63,12 +63,56 @@
// Support saving binary data automatically to a generated storage.data file. This file is managed internally.
#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
//------------------------------------------------------------------------------------
// Support VR simulation functionality (stereo rendering)
#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
//------------------------------------------------------------------------------------
@ -79,6 +123,7 @@
// Some lines-based shapes could still use lines
#define SUPPORT_QUADS_DRAW_MODE 1
//------------------------------------------------------------------------------------
// Module: textures - Configuration Flags
//------------------------------------------------------------------------------------
@ -86,7 +131,7 @@
#define SUPPORT_FILEFORMAT_PNG 1
#define SUPPORT_FILEFORMAT_BMP 1
#define SUPPORT_FILEFORMAT_TGA 1
#define SUPPORT_FILEFORMAT_JPG 1
//#define SUPPORT_FILEFORMAT_JPG 1
#define SUPPORT_FILEFORMAT_GIF 1
//#define SUPPORT_FILEFORMAT_PSD 1
#define SUPPORT_FILEFORMAT_DDS 1
@ -98,11 +143,12 @@
// Support image export functionality (.png, .bmp, .tga, .jpg)
#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)
#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
@ -114,6 +160,18 @@
#define SUPPORT_FILEFORMAT_FNT 1
#define SUPPORT_FILEFORMAT_TTF 1
// Support text management functions
// If not defined, still some functions are supported: TextLength(), TextFormat()
#define SUPPORT_TEXT_MANIPULATION 1
// text: Configuration values
//------------------------------------------------------------------------------------
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
#define MAX_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
//------------------------------------------------------------------------------------
@ -126,6 +184,7 @@
// NOTE: Some generated meshes DO NOT include generated texture coordinates
#define SUPPORT_MESH_GENERATION 1
//------------------------------------------------------------------------------------
// Module: audio - Configuration Flags
//------------------------------------------------------------------------------------
@ -137,6 +196,15 @@
//#define SUPPORT_FILEFORMAT_FLAC 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
//------------------------------------------------------------------------------------
@ -145,4 +213,10 @@
#define SUPPORT_TRACELOG 1
//#define SUPPORT_TRACELOG_DEBUG 1
// utils: Configuration values
//------------------------------------------------------------------------------------
#define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message
#define MAX_UWP_MESSAGES 512 // Max UWP messages to process
#endif //defined(RAYLIB_CMAKE)

File diff suppressed because it is too large Load diff

View file

@ -100,9 +100,9 @@ func UnhideWindow() {
C.UnhideWindow()
}
// HideWindow - Hide the window
func HideWindow() {
C.HideWindow()
// DecorateWindow - Decorate the window (only PLATFORM_DESKTOP)
func DecorateWindow() {
C.DecorateWindow()
}
// SetWindowIcon - Set icon for window (only PLATFORM_DESKTOP)

263
raylib/easings.h Normal file
View 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

4895
raylib/external/dr_wav.h vendored

File diff suppressed because it is too large Load diff

View file

@ -81,15 +81,13 @@
#ifndef INCLUDE_JAR_MOD_H
#define INCLUDE_JAR_MOD_H
#include <stdio.h>
#include <stdlib.h>
//#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
// Allow custom memory allocators
#ifndef JARMOD_MALLOC
#define JARMOD_MALLOC(sz) malloc(sz)
#endif
#ifndef JARMOD_FREE
#define JARMOD_FREE(p) free(p)
#endif
// Basic type
@ -240,7 +238,9 @@ typedef struct jar_mod_tracker_buffer_state_
tracker_state * track_state_buf;
}jar_mod_tracker_buffer_state;
#ifdef __cplusplus
extern "C" {
#endif
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);
@ -261,6 +261,10 @@ void jar_mod_seek_start(jar_mod_context_t * ctx);
//-------------------------------------------------------------------------------
#ifdef JAR_MOD_IMPLEMENTATION
#include <stdio.h>
#include <stdlib.h>
//#include <stdbool.h>
// Effects list
#define EFFECT_ARPEGGIO 0x0 // Supported
#define EFFECT_PORTAMENTO_UP 0x1 // Supported
@ -1504,7 +1508,7 @@ void jar_mod_unload( jar_mod_context_t * modctx)
{
if(modctx->modfile)
{
free(modctx->modfile);
JARMOD_FREE(modctx->modfile);
modctx->modfile = 0;
modctx->modfilesize = 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 fsize = 0;
if(modctx->modfile)
{
free(modctx->modfile);
JARMOD_FREE(modctx->modfile);
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)
{
modctx->modfile = malloc(fsize);
modctx->modfile = JARMOD_MALLOC(fsize);
modctx->modfilesize = fsize;
memset(modctx->modfile, 0, fsize);
fread(modctx->modfile, fsize, 1, f);

View file

@ -51,27 +51,29 @@
#ifndef INCLUDE_JAR_XM_H
#define INCLUDE_JAR_XM_H
#include <stdint.h>
#define JAR_XM_DEBUG 0
#define JAR_XM_LINEAR_INTERPOLATION 1 // speed increase with decrease in quality
#define JAR_XM_DEFENSIVE 1
#define JAR_XM_RAMPING 1
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include <string.h>
//-------------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
// Allow custom memory allocators
#ifndef JARXM_MALLOC
#define JARXM_MALLOC(sz) malloc(sz)
#endif
#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
extern "C" {
#endif
/** Create a XM context.
*
* @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)
{
float* musicBuffer = malloc((2*numsamples)*sizeof(float));
float* musicBuffer = JARXM_MALLOC((2*numsamples)*sizeof(float));
jar_xm_generate_samples(ctx, musicBuffer, numsamples);
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;
}
free(musicBuffer);
JARXM_FREE(musicBuffer);
}
/** 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)
{
float* musicBuffer = malloc((2*numsamples)*sizeof(float));
float* musicBuffer = JARXM_MALLOC((2*numsamples)*sizeof(float));
jar_xm_generate_samples(ctx, musicBuffer, numsamples);
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;
}
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
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#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
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) {
/* malloc() failed, trouble ahead */
DEBUG("call to malloc() failed, returned %p", (void*)mempool);
/* JARXM_MALLOC() failed, trouble ahead */
DEBUG("call to JARXM_MALLOC() failed, returned %p", (void*)mempool);
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);
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);
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) {
free(ctx->allocated_memory);
JARXM_FREE(ctx->allocated_memory);
}
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;
}
char* data = malloc(size + 1);
char* data = JARXM_MALLOC(size + 1);
if(!data || fread(data, 1, size, xmf) < size) {
fclose(xmf);
DEBUG_ERR(data ? "fread() failed" : "malloc() failed");
free(data);
DEBUG_ERR(data ? "fread() failed" : "JARXM_MALLOC() failed");
JARXM_FREE(data);
*ctx = NULL;
return 5;
}
@ -2632,7 +2637,7 @@ int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const
fclose(xmf);
ret = jar_xm_create_context_safe(ctx, data, size, rate);
free(data);
JARXM_FREE(data);
switch(ret) {
case 0:
@ -2670,7 +2675,7 @@ void jar_xm_reset(jar_xm_context_t* ctx)
jar_xm_cut_note(&ctx->channels[i]);
}
ctx->current_row = 0;
ctx->current_table_index = ctx->module.restart_position;
ctx->current_table_index = 0;
ctx->current_tick = 0;
}

File diff suppressed because it is too large Load diff

View file

@ -154,7 +154,6 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang
#include <math.h> // Required for: sqrtf(), atan2f()
#endif
#if defined(__APPLE__) // macOS also defines __MACH__
#include <mach/clock.h> // Required for: clock_get_time()
#include <mach/mach.h> // Required for: mach_timespec_t
@ -163,19 +162,20 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define FORCE_TO_SWIPE 0.0005f // Measured in normalized screen units/time
#define MINIMUM_DRAG 0.015f // 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 TAP_TIMEOUT 300 // Time in milliseconds
#define PINCH_TIMEOUT 300 // Time in milliseconds
#define DOUBLETAP_RANGE 0.03f // Measured in normalized screen units (0.0f to 1.0f)
#define FORCE_TO_SWIPE 0.0005f // Swipe force, measured in normalized screen units/time
#define MINIMUM_DRAG 0.015f // Drag minimum force, measured in normalized screen units (0.0f to 1.0f)
#define MINIMUM_PINCH 0.005f // Pinch minimum force, measured in normalized screen units (0.0f to 1.0f)
#define TAP_TIMEOUT 300 // Tap minimum time, measured in milliseconds
#define PINCH_TIMEOUT 300 // Pinch minimum time, measured in milliseconds
#define DOUBLETAP_RANGE 0.03f // DoubleTap range, measured in normalized screen units (0.0f to 1.0f)
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Gestures module state context [136 bytes]
typedef struct {
int current; // Current detected gesture
unsigned int current; // Current detected gesture
unsigned int enabledFlags; // Enabled gestures flags
struct {
int firstId; // Touch id for first touch point
@ -215,8 +215,8 @@ typedef struct {
//----------------------------------------------------------------------------------
static GesturesData GESTURES = {
.Touch.firstId = -1,
.current = GESTURE_NONE,
.enabledFlags = 0b0000001111111111 // All gestures enabled by default
.current = GESTURE_NONE, // No current gesture detected
.enabledFlags = 0b0000001111111111 // All gestures supported by default
};
//----------------------------------------------------------------------------------

File diff suppressed because it is too large Load diff

2063
raylib/physac.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -90,3 +90,59 @@ func OpenAsset(name string) (Asset, error) {
}
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
}
// 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()
}
// HideWindow - Hide the window
func HideWindow() {
C.HideWindow()
}
// 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
}

View file

@ -1,5 +1,3 @@
// +build !noaudio
/**********************************************************************************************
*
* 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_NO_JACK
#define MA_NO_WAV
#define MA_NO_FLAC
#define MA_NO_MP3
#define MINIAUDIO_IMPLEMENTATION
#include "external/miniaudio.h" // miniaudio library
#undef PlaySound // Win32 API: windows.h > mmsystem.h defines PlaySound macro
@ -174,6 +175,20 @@ typedef struct tagBITMAPINFOHEADER {
#if !defined(TRACELOG)
#define TRACELOG(level, ...) (void)0
#endif
// Allow custom memory allocators
#ifndef RL_MALLOC
#define RL_MALLOC(sz) malloc(sz)
#endif
#ifndef RL_CALLOC
#define RL_CALLOC(n,sz) calloc(n,sz)
#endif
#ifndef RL_REALLOC
#define RL_REALLOC(ptr,sz) realloc(ptr,sz)
#endif
#ifndef RL_FREE
#define RL_FREE(ptr) free(ptr)
#endif
#endif
#if defined(SUPPORT_FILEFORMAT_OGG)
@ -199,14 +214,13 @@ typedef struct tagBITMAPINFOHEADER {
#include "external/jar_mod.h" // MOD loading functions
#endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
#define DRFLAC_MALLOC RL_MALLOC
#define DRFLAC_REALLOC RL_REALLOC
#define DRFLAC_FREE RL_FREE
#if defined(SUPPORT_FILEFORMAT_WAV)
#define DRWAV_MALLOC RL_MALLOC
#define DRWAV_REALLOC RL_REALLOC
#define DRWAV_FREE RL_FREE
#define DR_FLAC_IMPLEMENTATION
#define DR_FLAC_NO_WIN32_IO
#include "external/dr_flac.h" // FLAC loading functions
#define DR_WAV_IMPLEMENTATION
#include "external/dr_wav.h" // WAV loading functions
#endif
#if defined(SUPPORT_FILEFORMAT_MP3)
@ -218,6 +232,16 @@ typedef struct tagBITMAPINFOHEADER {
#include "external/dr_mp3.h" // MP3 loading functions
#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)
#undef bool
#endif
@ -225,11 +249,22 @@ typedef struct tagBITMAPINFOHEADER {
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define AUDIO_DEVICE_FORMAT ma_format_f32
#define AUDIO_DEVICE_CHANNELS 2
#define AUDIO_DEVICE_SAMPLE_RATE 44100
#ifndef AUDIO_DEVICE_FORMAT
#define AUDIO_DEVICE_FORMAT ma_format_f32 // Device output format (float-32bit)
#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
@ -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
// standard double-buffering system, a 4096 samples buffer has been chosen, it should be enough
// 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
#if defined(RAUDIO_STANDALONE)
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 bool IsFileExtension(const char *fileName, const char *ext); // Check file extension
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
//----------------------------------------------------------------------------------
@ -393,14 +430,14 @@ void InitAudioDevice(void)
// 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);
config.playback.pDeviceID = NULL; // NULL for the default playback AUDIO.System.device.
config.playback.format = AUDIO_DEVICE_FORMAT;
config.playback.channels = AUDIO_DEVICE_CHANNELS;
config.capture.pDeviceID = NULL; // NULL for the default capture AUDIO.System.device.
config.capture.format = ma_format_s16;
config.capture.channels = 1;
config.sampleRate = AUDIO_DEVICE_SAMPLE_RATE;
config.dataCallback = OnSendAudioDataToDevice;
config.pUserData = NULL;
config.playback.format = AUDIO_DEVICE_FORMAT;
config.playback.channels = AUDIO_DEVICE_CHANNELS;
config.capture.pDeviceID = NULL; // NULL for the default capture AUDIO.System.device.
config.capture.format = ma_format_s16;
config.capture.channels = 1;
config.sampleRate = AUDIO_DEVICE_SAMPLE_RATE;
config.dataCallback = OnSendAudioDataToDevice;
config.pUserData = NULL;
result = ma_device_init(&AUDIO.System.context, &config, &AUDIO.System.device);
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
// 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");
ma_device_uninit(&AUDIO.System.device);
@ -432,11 +469,11 @@ void InitAudioDevice(void)
}
TRACELOG(LOG_INFO, "AUDIO: Device initialized successfully");
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, " > 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, " > Periods size: %d", AUDIO.System.device.playback.internalPeriodSizeInFrames*AUDIO.System.device.playback.internalPeriods);
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, " > 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, " > Periods size: %d", AUDIO.System.device.playback.internalPeriodSizeInFrames*AUDIO.System.device.playback.internalPeriods);
InitAudioBufferPool();
@ -486,7 +523,7 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
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
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)
void ExportWaveAsCode(Wave wave, const char *fileName)
{
#define BYTES_TEXT_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);
#ifndef TEXT_BYTES_PER_LINE
#define TEXT_BYTES_PER_LINE 20
#endif
fprintf(txtFile, "// Wave data information\n");
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);
int waveDataSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
// Write byte data as hexadecimal text
fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize);
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]);
fprintf(txtFile, "0x%x };\n", ((unsigned char *)wave.data)[dataSize - 1]);
// NOTE: Text data buffer size is estimated considering wave data size in bytes
// and requiring 6 char bytes for every byte: "0x00, "
char *txtData = (char *)RL_CALLOC(6*waveDataSize + 2000, sizeof(char));
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
@ -1041,6 +1083,27 @@ Music LoadMusicStream(const char *fileName)
bool musicLoaded = 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)
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
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.loopCount = 0; // Infinite loop by default
music.looping = true; // Looping enabled by default
musicLoaded = true;
}
}
@ -1072,7 +1135,7 @@ Music LoadMusicStream(const char *fileName)
music.stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels);
music.sampleCount = (unsigned int)ctxFlac->totalSampleCount;
music.loopCount = 0; // Infinite loop by default
music.looping = true; // Looping enabled by default
musicLoaded = true;
}
}
@ -1091,7 +1154,7 @@ Music LoadMusicStream(const char *fileName)
music.stream = InitAudioStream(ctxMp3->sampleRate, 32, 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;
}
}
@ -1111,7 +1174,7 @@ Music LoadMusicStream(const char *fileName)
// NOTE: Only stereo is supported for XM
music.stream = InitAudioStream(48000, 16, 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
musicLoaded = true;
@ -1134,17 +1197,21 @@ Music LoadMusicStream(const char *fileName)
// NOTE: Only stereo is supported for MOD
music.stream = InitAudioStream(48000, 16, 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;
music.ctxData = ctxMod;
}
}
#endif
else TRACELOG(LOG_WARNING, "STREAM: [%s] Fileformat not supported", fileName);
if (!musicLoaded)
{
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)
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
#endif
@ -1182,6 +1249,9 @@ void UnloadMusicStream(Music music)
CloseAudioStream(music.stream);
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)
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
#endif
@ -1233,6 +1303,9 @@ void StopMusicStream(Music music)
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)
case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break;
#endif
@ -1277,6 +1350,15 @@ void UpdateMusicStream(Music music)
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)
case MUSIC_AUDIO_OGG:
{
@ -1340,15 +1422,8 @@ void UpdateMusicStream(Music music)
// Reset audio stream for looping
if (streamEnding)
{
StopMusicStream(music); // Stop music (and reset)
// 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);
StopMusicStream(music); // Stop music (and reset)
if (music.looping) PlayMusicStream(music); // Play again
}
else
{
@ -1376,13 +1451,6 @@ void SetMusicPitch(Music music, float 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)
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
// frames. This can be achieved with ma_data_converter_get_required_input_frame_count().
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;
while (totalOutputFramesProcessed < frameCount)
@ -1806,6 +1874,7 @@ static void InitAudioBufferPool(void)
// Dummy buffers
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);
}
@ -1816,133 +1885,36 @@ static void InitAudioBufferPool(void)
// Close the audio buffers pool
static void CloseAudioBufferPool(void)
{
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
{
RL_FREE(AUDIO.MultiChannel.pool[i]->data);
RL_FREE(AUDIO.MultiChannel.pool[i]);
}
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) RL_FREE(AUDIO.MultiChannel.pool[i]);
}
#if defined(SUPPORT_FILEFORMAT_WAV)
// Load WAV file into Wave structure
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 };
FILE *wavFile = NULL;
wavFile = fopen(fileName, "rb");
if (wavFile == NULL)
// Loading WAV from memory to avoid FILE accesses
unsigned int fileSize = 0;
unsigned char *fileData = LoadFileData(fileName, &fileSize);
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.data = NULL;
}
else
{
// Read in the first chunk into the struct
fread(&wavRiffHeader, sizeof(WAVRiffHeader), 1, wavFile);
// Check for RIFF and WAVE tags
if ((wavRiffHeader.chunkID[0] != 'R') ||
(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);
wave.sampleCount = wav.totalPCMFrameCount*wav.channels;
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 TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load WAV data", fileName);
drwav_uninit(&wav);
RL_FREE(fileData);
return wave;
}
@ -1950,81 +1922,24 @@ static Wave LoadWAV(const char *fileName)
// Save wave data as WAV file
static int SaveWAV(Wave wave, const char *fileName)
{
int success = 0;
int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
// Basic WAV headers structs
typedef struct {
char chunkID[4];
int chunkSize;
char format[4];
} RiffHeader;
typedef struct {
char subChunkID[4];
int subChunkSize;
short audioFormat;
short numChannels;
int sampleRate;
int byteRate;
short blockAlign;
short bitsPerSample;
} WaveFormat;
typedef struct {
char subChunkID[4];
int subChunkSize;
} WaveData;
FILE *wavFile = fopen(fileName, "wb");
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;
drwav wav = { 0 };
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;
drwav_init_file_write(&wav, fileName, &format, NULL);
//drwav_init_memory_write(&wav, &fileData, &fileDataSize, &format, NULL); // TODO: Memory version
drwav_write_pcm_frames(&wav, wave.sampleCount/wave.channels, wave.data);
drwav_uninit(&wav);
// SaveFileData(fileName, fileData, fileDataSize);
//drwav_free(fileData, NULL);
return true;
}
#endif
@ -2035,7 +1950,11 @@ static Wave LoadOGG(const char *fileName)
{
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);
else
@ -2058,6 +1977,8 @@ static Wave LoadOGG(const char *fileName)
stb_vorbis_close(oggFile);
}
RL_FREE(fileData);
return wave;
}
@ -2069,10 +1990,14 @@ static Wave LoadOGG(const char *fileName)
static Wave LoadFLAC(const char *fileName)
{
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
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);
else
@ -2080,11 +2005,10 @@ static Wave LoadFLAC(const char *fileName)
wave.sampleCount = (unsigned int)totalSampleCount;
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");
}
RL_FREE(fileData);
return wave;
}
@ -2097,10 +2021,14 @@ static Wave LoadMP3(const char *fileName)
{
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
unsigned long int totalFrameCount = 0;
unsigned long long int totalFrameCount = 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);
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");
}
RL_FREE(fileData);
return wave;
}
#endif
@ -2123,7 +2053,7 @@ static Wave LoadMP3(const char *fileName)
// Some required functions for audio standalone module version
#if defined(RAUDIO_STANDALONE)
// Check file extension
bool IsFileExtension(const char *fileName, const char *ext)
static bool IsFileExtension(const char *fileName, const char *ext)
{
bool result = false;
const char *fileExt;
@ -2135,6 +2065,89 @@ bool IsFileExtension(const char *fileName, const char *ext)
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
#undef AudioBuffer

View file

@ -255,14 +255,6 @@ func SetMusicPitch(music Music, pitch float32) {
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)
func GetMusicTimeLength(music Music) float32 {
cmusic := *(*C.Music)(unsafe.Pointer(&music))

View file

@ -111,8 +111,8 @@ typedef struct Music {
int ctxType; // Type of music context (audio filetype)
void *ctxData; // Audio context data, depends on type
bool looping; // Music looping enable
unsigned int sampleCount; // Total number of samples
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
AudioStream stream; // Audio stream
} Music;
@ -173,7 +173,6 @@ void ResumeMusicStream(Music music); // Resume playin
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 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 GetMusicTimePlayed(Music music); // Get current music time played (in seconds)

View file

@ -35,6 +35,11 @@ Example:
*/
package rl
/*
#include "raylib.h"
#include <stdlib.h>
*/
import "C"
import (
"image"
"io"
@ -108,7 +113,7 @@ type AudioStream struct {
// Number of channels (1-mono, 2-stereo)
Channels uint32
// Buffer
Buffer *_Ctype_struct_rAudioBuffer
Buffer *C.rAudioBuffer
}
// newAudioStreamFromPointer - Returns new AudioStream from pointer
@ -910,9 +915,12 @@ type BlendMode int32
// Color blending modes (pre-defined)
const (
BlendAlpha BlendMode = iota
BlendAdditive
BlendMultiplied
BlendAlpha BlendMode = iota // Blend textures considering alpha (default)
BlendAdditive // Blend textures adding colors
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)
@ -1086,17 +1094,26 @@ func newImageFromPointer(ptr unsafe.Pointer) *Image {
// NewImageFromImage - Returns new Image from Go image.Image
func NewImageFromImage(img image.Image) *Image {
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 x := 0; x < size.X; x++ {
color := img.At(x, y)
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)
}
}
return LoadImageEx(pixels, int32(size.X), int32(size.Y))
v := newImageFromPointer(unsafe.Pointer(&ret))
return v
}
// Texture2D type, bpp always RGBA (32bit)

View file

@ -99,8 +99,6 @@
#define DEG2RAD (PI/180.0f)
#define RAD2DEG (180.0f/PI)
#define MAX_TOUCH_POINTS 10 // Maximum number of touch points supported
// Allow custom memory allocators
#ifndef RL_MALLOC
#define RL_MALLOC(sz) malloc(sz)
@ -159,6 +157,7 @@
#define SubText TextSubtext
#define ShowWindow UnhideWindow
#define LoadText LoadFileText
//#define Fade(c, a) ColorAlpha(c, a)
//----------------------------------------------------------------------------------
// Structures Definition
@ -442,8 +441,8 @@ typedef struct Music {
int ctxType; // Type of music context (audio filetype)
void *ctxData; // Audio context data, depends on type
bool looping; // Music looping enable
unsigned int sampleCount; // Total number of samples
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
AudioStream stream; // Audio stream
} Music;
@ -665,20 +664,17 @@ typedef enum {
} GamepadButton;
typedef enum {
// This is here just for error checking
GAMEPAD_AXIS_UNKNOWN = 0,
// Left stick
GAMEPAD_AXIS_LEFT_X,
GAMEPAD_AXIS_LEFT_Y,
GAMEPAD_AXIS_LEFT_X = 0,
GAMEPAD_AXIS_LEFT_Y = 1,
// Right stick
GAMEPAD_AXIS_RIGHT_X,
GAMEPAD_AXIS_RIGHT_Y,
GAMEPAD_AXIS_RIGHT_X = 2,
GAMEPAD_AXIS_RIGHT_Y = 3,
// Pressure levels for the back triggers
GAMEPAD_AXIS_LEFT_TRIGGER, // [1..-1] (pressure-level)
GAMEPAD_AXIS_RIGHT_TRIGGER // [1..-1] (pressure-level)
GAMEPAD_AXIS_LEFT_TRIGGER = 4, // [1..-1] (pressure-level)
GAMEPAD_AXIS_RIGHT_TRIGGER = 5 // [1..-1] (pressure-level)
} GamepadAxis;
// Shader location point type
@ -811,7 +807,10 @@ typedef enum {
typedef enum {
BLEND_ALPHA = 0, // Blend textures considering alpha (default)
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;
// 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 void CloseWindow(void); // Close window and unload OpenGL context
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 IsWindowHidden(void); // Check if window is currently hidden
RLAPI bool IsWindowFullscreen(void); // Check if window is currently fullscreen
RLAPI void ToggleFullscreen(void); // Toggle fullscreen mode (only PLATFORM_DESKTOP)
RLAPI void UnhideWindow(void); // Show 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 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)
@ -894,7 +899,9 @@ RLAPI int GetMonitorWidth(int monitor); // Get primary
RLAPI int GetMonitorHeight(int monitor); // Get primary monitor height
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 GetMonitorRefreshRate(int monitor); // Get primary monitor refresh rate
RLAPI Vector2 GetWindowPosition(void); // Get window position XY on monitor
RLAPI Vector2 GetWindowScaleDPI(void); // Get window scale DPI factor
RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the primary monitor
RLAPI const char *GetClipboardText(void); // Get 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 void EnableCursor(void); // Enables cursor (unlock cursor)
RLAPI void DisableCursor(void); // Disables cursor (lock cursor)
RLAPI bool IsCursorOnScreen(void); // Check if cursor is on the current screen.
// Drawing-related functions
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 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
RLAPI void SetConfigFlags(unsigned int flags); // Setup window configuration flags (view FLAGS)
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
// NOTE: This functions do not require GPU access
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 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 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 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
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 ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font)
RLAPI Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint); // Create an image from text (custom sprite font)
RLAPI void 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 ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image
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 ImageToPOT(Image *image, Color fill); // Convert image to POT (power-of-two)
RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle
RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value
RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color
RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image
RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel
RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (Bicubic scaling algorithm)
RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); // Resize image (Nearest-Neighbor scaling algorithm)
RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color 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 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
@ -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 ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255)
RLAPI void ImageColorReplace(Image *image, Color color, Color replace); // Modify image color: replace color
RLAPI Color *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
// 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 ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color); // Draw rectangle lines within an image
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source)
RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (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 ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination)
RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination)
// Texture loading functions
// NOTE: These functions require GPU access
@ -1180,6 +1179,7 @@ RLAPI RenderTexture2D LoadRenderTexture(int width, int height);
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM)
RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data
RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data
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)
@ -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 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 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 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
RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture)
// Color/pixel related functions
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)
@ -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 DrawPoint3D(Vector3 position, Color color); // Draw a point in 3D space, actually a small line
RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color); // Draw a circle in 3D world space
RLAPI void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color); // Draw a color-filled triangle (vertex in counter-clockwise order!)
RLAPI void DrawTriangleStrip3D(Vector3 *points, int 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 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
@ -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 DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0))
RLAPI void DrawGizmo(Vector3 position); // Draw simple gizmo
//DrawTorus(), DrawTeapot() could be useful?
//------------------------------------------------------------------------------------
// 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 void MeshTangents(Mesh *mesh); // Compute mesh tangents
RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals
RLAPI void MeshNormalsSmooth(Mesh *mesh); // Smooth (average) vertex normals
// Model drawing functions
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 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 SetMusicLoopCount(Music music, int count); // Set music loop count (loop repeats)
RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds)
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)

View file

@ -154,6 +154,18 @@ RMDEF float Lerp(float start, float end, float amount)
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
//----------------------------------------------------------------------------------
@ -179,6 +191,13 @@ RMDEF Vector2 Vector2Add(Vector2 v1, Vector2 v2)
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)
RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)
{
@ -186,6 +205,13 @@ RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)
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
RMDEF float Vector2Length(Vector2 v)
{
@ -193,6 +219,13 @@ RMDEF float Vector2Length(Vector2 v)
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
RMDEF float Vector2DotProduct(Vector2 v1, Vector2 v2)
{
@ -223,7 +256,7 @@ RMDEF Vector2 Vector2Scale(Vector2 v, float scale)
}
// 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 };
return result;
@ -236,15 +269,8 @@ RMDEF Vector2 Vector2Negate(Vector2 v)
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
RMDEF Vector2 Vector2DivideV(Vector2 v1, Vector2 v2)
RMDEF Vector2 Vector2Divide(Vector2 v1, Vector2 v2)
{
Vector2 result = { v1.x/v2.x, v1.y/v2.y };
return result;
@ -253,7 +279,7 @@ RMDEF Vector2 Vector2DivideV(Vector2 v1, Vector2 v2)
// Normalize provided vector
RMDEF Vector2 Vector2Normalize(Vector2 v)
{
Vector2 result = Vector2Divide(v, Vector2Length(v));
Vector2 result = Vector2Scale(v, 1/Vector2Length(v));
return result;
}
@ -276,6 +302,24 @@ RMDEF Vector2 Vector2Rotate(Vector2 v, float degs)
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
//----------------------------------------------------------------------------------
@ -301,6 +345,13 @@ RMDEF Vector3 Vector3Add(Vector3 v1, Vector3 v2)
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
RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
{
@ -308,6 +359,13 @@ RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
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
RMDEF Vector3 Vector3Scale(Vector3 v, float scalar)
{
@ -362,6 +420,13 @@ RMDEF float Vector3Length(const Vector3 v)
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
RMDEF float Vector3DotProduct(Vector3 v1, Vector3 v2)
{
@ -386,15 +451,8 @@ RMDEF Vector3 Vector3Negate(Vector3 v)
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
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 };
return result;
@ -737,6 +795,32 @@ RMDEF Matrix MatrixSubtract(Matrix left, Matrix right)
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
RMDEF Matrix MatrixTranslate(float x, float y, float z)
{
@ -793,33 +877,6 @@ RMDEF Matrix MatrixRotate(Vector3 axis, float angle)
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)
RMDEF Matrix MatrixRotateX(float angle)
{
@ -868,6 +925,46 @@ RMDEF Matrix MatrixRotateZ(float angle)
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
RMDEF Matrix MatrixScale(float x, float y, float z)
{
@ -879,32 +976,6 @@ RMDEF Matrix MatrixScale(float x, float y, float z)
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
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
//----------------------------------------------------------------------------------
// 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
RMDEF Quaternion QuaternionIdentity(void)
{
@ -1108,6 +1207,28 @@ RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2)
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
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.y = cross.y;
result.z = cross.y;
result.z = cross.z;
result.w = 1.0f + cos2Theta; // NOTE: Added QuaternioIdentity()
// Normalize to essentially nlerp the original and identity to 0.5
@ -1191,101 +1312,58 @@ RMDEF Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to)
// Returns a quaternion for a given rotation matrix
RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
{
Quaternion result = { 0 };
float trace = MatrixTrace(mat);
if (trace > 0.0f)
Quaternion result = { 0.0f };
if ((mat.m0 > mat.m5) && (mat.m0 > mat.m10))
{
float s = sqrtf(trace + 1)*2.0f;
float invS = 1.0f/s;
result.w = s*0.25f;
result.x = (mat.m6 - mat.m9)*invS;
result.y = (mat.m8 - mat.m2)*invS;
result.z = (mat.m1 - mat.m4)*invS;
}
float s = sqrtf(1.0f + mat.m0 - mat.m5 - mat.m10)*2;
result.x = 0.25f*s;
result.y = (mat.m4 + mat.m1)/s;
result.z = (mat.m2 + mat.m8)/s;
result.w = (mat.m9 - mat.m6)/s;
}
else if (mat.m5 > mat.m10)
{
float s = sqrtf(1.0f + mat.m5 - mat.m0 - mat.m10)*2;
result.x = (mat.m4 + mat.m1)/s;
result.y = 0.25f*s;
result.z = (mat.m9 + mat.m6)/s;
result.w = (mat.m2 - mat.m8)/s;
}
else
{
float m00 = mat.m0, m11 = mat.m5, m22 = mat.m10;
if (m00 > m11 && m00 > m22)
{
float s = (float)sqrt(1.0f + m00 - m11 - m22)*2.0f;
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;
}
float s = sqrtf(1.0f + mat.m10 - mat.m0 - mat.m5)*2;
result.x = (mat.m2 + mat.m8)/s;
result.y = (mat.m9 + mat.m6)/s;
result.z = 0.25f*s;
result.w = (mat.m4 - mat.m1)/s;
}
return result;
}
// Returns a matrix for a given quaternion
RMDEF Matrix QuaternionToMatrix(Quaternion q)
{
Matrix result = { 0 };
Matrix result = MatrixIdentity();
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 ab = 2*(q.x*q.y), ac=2*(q.x*q.z), bc=2*(q.y*q.z);
float ad = 2*(q.x*q.w), bd=2*(q.y*q.w), cd=2*(q.z*q.w);
float x = q.x, y = q.y, z = q.z, w = q.w;
float x2 = x + x;
float y2 = y + y;
float z2 = z + z;
float length = QuaternionLength(q);
float lengthSquared = length*length;
float xx = x*x2/lengthSquared;
float xy = x*y2/lengthSquared;
float xz = x*z2/lengthSquared;
float yy = y*y2/lengthSquared;
float yz = y*z2/lengthSquared;
float zz = z*z2/lengthSquared;
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;
result.m0 = 1 - b2 - c2;
result.m1 = ab - cd;
result.m2 = ac + bd;
result.m4 = ab + cd;
result.m5 = 1 - a2 - c2;
result.m6 = bc - ad;
result.m8 = ac - bd;
result.m9 = bc + ad;
result.m10 = 1 - a2 - b2;
return result;
}
@ -1399,4 +1477,27 @@ RMDEF Quaternion QuaternionTransform(Quaternion q, Matrix mat)
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

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
*
* 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:
* - 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)
#endif
#define RMEM_VERSION "v1.3" // changelog at bottom of header.
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
@ -66,39 +68,45 @@ struct MemNode {
MemNode *next, *prev;
};
// Freelist implementation
typedef struct AllocList {
MemNode *head, *tail;
size_t len, maxNodes;
bool autoDefrag : 1;
size_t len;
} AllocList;
typedef struct Stack {
uint8_t *mem, *base;
// Arena allocator.
typedef struct Arena {
uintptr_t mem, offs;
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 {
AllocList freeList;
Stack stack;
MemNode *buckets[MEMPOOL_BUCKET_SIZE];
AllocList large, buckets[MEMPOOL_BUCKET_SIZE];
Arena arena;
} MemPool;
// Object Pool
typedef struct ObjPool {
Stack stack;
size_t objSize, freeBlocks;
uintptr_t mem, offs;
size_t objSize, freeBlocks, memSize;
} ObjPool;
// Double-Ended Stack aka Deque
typedef struct BiStack {
uint8_t *mem, *front, *back;
uintptr_t mem, front, back;
size_t size;
} BiStack;
#if defined(__cplusplus)
extern "C" { // Prevents name mangling of functions
#endif
@ -115,10 +123,7 @@ RMEMAPI void *MemPoolRealloc(MemPool *mempool, void *ptr, size_t bytes);
RMEMAPI void MemPoolFree(MemPool *mempool, void *ptr);
RMEMAPI void MemPoolCleanUp(MemPool *mempool, void **ptrref);
RMEMAPI void MemPoolReset(MemPool *mempool);
RMEMAPI bool MemPoolDefrag(MemPool *mempool);
RMEMAPI size_t GetMemPoolFreeMemory(const MemPool mempool);
RMEMAPI void ToggleMemPoolAutoDefrag(MemPool *mempool);
//------------------------------------------------------------------------------------
// Functions Declaration - Object Pool
@ -161,7 +166,9 @@ RMEMAPI intptr_t BiStackMargins(BiStack destack);
#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
@ -188,6 +195,145 @@ static inline size_t __AlignSize(const size_t size, const size_t align)
return (size + (align - 1)) & -align;
}
static MemNode *__SplitMemNode(MemNode *const node, const size_t bytes)
{
uintptr_t n = ( uintptr_t )node;
MemNode *const r = ( MemNode* )(n + (node->size - bytes));
node->size -= bytes;
r->size = bytes;
return r;
}
static void __InsertMemNodeBefore(AllocList *const list, MemNode *const insert, MemNode *const curr)
{
insert->next = curr;
if (curr->prev==NULL) list->head = insert;
else
{
insert->prev = curr->prev;
curr->prev->next = insert;
}
curr->prev = insert;
}
static void __ReplaceMemNode(MemNode *const old, MemNode *const replace)
{
replace->prev = old->prev;
replace->next = old->next;
if( old->prev != NULL )
old->prev->next = replace;
if( old->next != NULL )
old->next->prev = replace;
}
static MemNode *__RemoveMemNode(AllocList *const list, MemNode *const node)
{
if (node->prev != NULL) node->prev->next = node->next;
else
{
list->head = node->next;
if (list->head != NULL) list->head->prev = NULL;
else list->tail = NULL;
}
if (node->next != NULL) node->next->prev = node->prev;
else
{
list->tail = node->prev;
if (list->tail != NULL) list->tail->next = NULL;
else list->head = NULL;
}
list->len--;
return node;
}
static MemNode *__FindMemNode(AllocList *const list, const size_t bytes)
{
for (MemNode *node = list->head; node != NULL; node = node->next)
{
if (node->size < bytes) continue;
// close in size - reduce fragmentation by not splitting.
else if (node->size <= bytes + MEM_SPLIT_THRESHOLD) return __RemoveMemNode(list, node);
else return __SplitMemNode(node, bytes);
}
return NULL;
}
static void __InsertMemNode(MemPool *const mempool, AllocList *const list, MemNode *const node, const bool is_bucket)
{
if (list->head == NULL)
{
list->head = node;
list->len++;
}
else
{
for (MemNode *iter = list->head; iter != NULL; iter = iter->next)
{
if (( uintptr_t )iter == mempool->arena.offs)
{
mempool->arena.offs += iter->size;
__RemoveMemNode(list, iter);
iter = list->head;
}
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
//----------------------------------------------------------------------------------
@ -196,114 +342,77 @@ MemPool CreateMemPool(const size_t size)
{
MemPool mempool = { 0 };
if (size == 0UL) return mempool;
if (size == 0) return mempool;
else
{
// Align the mempool size to at least the size of an alloc node.
mempool.stack.size = size;
mempool.stack.mem = malloc(mempool.stack.size*sizeof *mempool.stack.mem);
if (mempool.stack.mem == NULL)
{
mempool.stack.size = 0UL;
return mempool;
}
uint8_t *const restrict buf = malloc(size*sizeof *buf);
if (buf==NULL) return mempool;
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;
}
}
}
MemPool CreateMemPoolFromBuffer(void *buf, const size_t size)
MemPool CreateMemPoolFromBuffer(void *const restrict buf, const size_t size)
{
MemPool mempool = { 0 };
if ((size == 0UL) || (buf == NULL) || (size <= sizeof(MemNode))) return mempool;
if ((size == 0) || (buf == NULL) || (size <= sizeof(MemNode))) return mempool;
else
{
mempool.stack.size = size;
mempool.stack.mem = buf;
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;
}
}
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
{
free(mempool->stack.mem);
void *const restrict ptr = ( void* )mempool->arena.mem;
free(ptr);
*mempool = (MemPool){ 0 };
}
}
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
{
MemNode *new_mem = NULL;
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 ((BUCKET_INDEX < MEMPOOL_BUCKET_SIZE) &&
(mempool->buckets[BUCKET_INDEX] != NULL) &&
(mempool->buckets[BUCKET_INDEX]->size >= ALLOC_SIZE))
if (BUCKET_SLOT < MEMPOOL_BUCKET_SIZE)
{
new_mem = mempool->buckets[BUCKET_INDEX];
mempool->buckets[BUCKET_INDEX] = mempool->buckets[BUCKET_INDEX]->next;
if( mempool->buckets[BUCKET_INDEX] != NULL )
mempool->buckets[BUCKET_INDEX]->prev = NULL;
new_mem = __FindMemNode(&mempool->buckets[BUCKET_SLOT], ALLOC_SIZE);
}
else if (mempool->freeList.head != NULL)
else if (mempool->large.head != NULL)
{
const size_t MEM_SPLIT_THRESHOLD = 16;
// 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;
}
}
new_mem = __FindMemNode(&mempool->large, ALLOC_SIZE);
}
if (new_mem == NULL)
{
// 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
{
// Couldn't allocate from a freelist, allocate from available 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.
new_mem = (MemNode *)mempool->stack.base;
new_mem = ( MemNode* )mempool->arena.offs;
new_mem->size = ALLOC_SIZE;
}
}
@ -313,33 +422,32 @@ void *MemPoolAlloc(MemPool *const mempool, const size_t size)
// | mem size | lowest addr of block
// | next node | 12 byte (32-bit) header
// | prev node | 24 byte (64-bit) header
// --------------
// |------------|
// | alloc'd |
// | memory |
// | space | highest addr of block
// --------------
new_mem->next = new_mem->prev = NULL;
uint8_t *const 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);
}
}
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.
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
{
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;
uint8_t *const resized_block = MemPoolAlloc(mempool, size);
if (resized_block == NULL) return NULL;
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));
MemPoolFree(mempool, ptr);
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
{
// Behind the actual pointer data is the allocation info.
MemNode *const mem_node = (MemNode *)((uint8_t *)ptr - sizeof *mem_node);
const size_t BUCKET_INDEX = (mem_node->size >> MEMPOOL_BUCKET_BITS) - 1;
const uintptr_t block = p - sizeof(MemNode);
MemNode *const mem_node = ( MemNode* )block;
const size_t BUCKET_SLOT = (mem_node->size >> MEMPOOL_BUCKET_BITS) - 1;
// Make sure the pointer data is valid.
if (((uintptr_t)mem_node < (uintptr_t)mempool->stack.base) ||
(((uintptr_t)mem_node - (uintptr_t)mempool->stack.mem) > mempool->stack.size) ||
(mem_node->size == 0UL) ||
(mem_node->size > mempool->stack.size)) return;
// If the mem_node is right at the stack base ptr, then add it to the stack.
else if ((uintptr_t)mem_node == (uintptr_t)mempool->stack.base)
if ((block < mempool->arena.offs) ||
((block - mempool->arena.mem) > mempool->arena.size) ||
(mem_node->size == 0) ||
(mem_node->size > mempool->arena.size)) return;
// If the mem_node is right at the arena offs, then merge it back to the arena.
else if (block == mempool->arena.offs)
{
mempool->stack.base += mem_node->size;
mempool->arena.offs += mem_node->size;
}
// attempted stack merge failed, try to place it into the memnode buckets
else if (BUCKET_INDEX < MEMPOOL_BUCKET_SIZE)
else
{
if (mempool->buckets[BUCKET_INDEX] == NULL) mempool->buckets[BUCKET_INDEX] = mem_node;
else
{
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);
// try to place it into bucket or large freelist.
struct AllocList *const l = (BUCKET_SLOT < MEMPOOL_BUCKET_SIZE) ? &mempool->buckets[BUCKET_SLOT] : &mempool->large;
__InsertMemNode(mempool, l, mem_node, (BUCKET_SLOT < MEMPOOL_BUCKET_SIZE));
}
}
}
void MemPoolCleanUp(MemPool *const restrict mempool, void **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
{
MemPoolFree(mempool, *ptrref);
@ -422,264 +497,127 @@ void MemPoolCleanUp(MemPool *const restrict mempool, void **ptrref)
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;
}
void MemPoolReset(MemPool *const mempool)
{
if (mempool == NULL) return;
mempool->freeList.head = mempool->freeList.tail = NULL;
mempool->freeList.len = 0;
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
mempool->large.head = mempool->large.tail = NULL;
mempool->large.len = 0;
for (size_t i = 0; i < MEMPOOL_BUCKET_SIZE; i++)
{
// If the memory pool has been entirely released, fully defrag it.
if (mempool->stack.size == GetMemPoolFreeMemory(*mempool))
{
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->buckets[i].head = mempool->buckets[i].tail = NULL;
mempool->buckets[i].len = 0;
}
}
void ToggleMemPoolAutoDefrag(MemPool *const mempool)
{
if (mempool == NULL) return;
else mempool->freeList.autoDefrag ^= true;
mempool->arena.offs = mempool->arena.mem + mempool->arena.size;
}
//----------------------------------------------------------------------------------
// 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 objpool = { 0 };
if ((len == 0UL) || (objsize == 0UL)) return objpool;
if ((len == 0) || (objsize == 0)) return objpool;
else
{
objpool.objSize = __AlignSize(objsize, sizeof(size_t));
objpool.stack.size = objpool.freeBlocks = len;
objpool.stack.mem = calloc(objpool.stack.size, objpool.objSize);
if (objpool.stack.mem == NULL)
const size_t aligned_size = __AlignSize(objsize, sizeof(size_t));
uint8_t *const restrict buf = calloc(len, aligned_size);
if (buf == NULL) return objpool;
objpool.objSize = aligned_size;
objpool.memSize = objpool.freeBlocks = len;
objpool.mem = ( uintptr_t )buf;
for (size_t i=0; i<objpool.freeBlocks; i++)
{
objpool.stack.size = 0UL;
return objpool;
}
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;
size_t *const restrict index = ( size_t* )(objpool.mem + (i*aligned_size));
*index = i + 1;
}
objpool.stack.base = objpool.stack.mem;
objpool.offs = objpool.mem;
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
{
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};
}
}
void *ObjPoolAlloc(ObjPool *const objpool)
{
if (objpool == NULL) return NULL;
else
if (objpool->freeBlocks > 0)
{
if (objpool->freeBlocks > 0UL)
{
// For first allocation, head points to the very first index.
// Head = &pool[0];
// ret = Head == ret = &pool[0];
union ObjInfo ret = { .byte = objpool->stack.base };
objpool->freeBlocks--;
// For first allocation, head points to the very first index.
// Head = &pool[0];
// ret = Head == ret = &pool[0];
size_t *const restrict block = ( size_t* )objpool->offs;
objpool->freeBlocks--;
// after allocating, we set head to the address of the index that *Head holds.
// Head = &pool[*Head * pool.objsize];
objpool->stack.base = (objpool->freeBlocks != 0UL)? objpool->stack.mem + (*ret.index*objpool->objSize) : NULL;
memset(ret.byte, 0, objpool->objSize);
return ret.byte;
}
else return NULL;
// after allocating, we set head to the address of the index that *Head holds.
// Head = &pool[*Head * pool.objsize];
objpool->offs = (objpool->freeBlocks != 0)? objpool->mem + (*block*objpool->objSize) : 0;
return memset(block, 0, objpool->objSize);
}
else return NULL;
}
void ObjPoolFree(ObjPool *const restrict objpool, void *ptr)
void ObjPoolFree(ObjPool *const restrict objpool, void *const ptr)
{
union ObjInfo p = { .byte = ptr };
if ((objpool == NULL) || (ptr == NULL) || (p.byte < objpool->stack.mem) || (p.byte > objpool->stack.mem + objpool->stack.size*objpool->objSize)) return;
uintptr_t block = (uintptr_t)ptr;
if ((ptr == NULL) || (block < objpool->mem) || (block > objpool->mem + objpool->memSize*objpool->objSize)) return;
else
{
// When we free our pointer, we recycle the pointer space to store the previous index and then we push it as our new head.
// *p = index of Head in relation to the buffer;
// Head = p;
*p.index = (objpool->stack.base != NULL)? (objpool->stack.base - objpool->stack.mem)/objpool->objSize : objpool->stack.size;
objpool->stack.base = p.byte;
size_t *const restrict index = ( size_t* )block;
*index = (objpool->offs != 0)? (objpool->offs - objpool->mem)/objpool->objSize : objpool->memSize;
objpool->offs = block;
objpool->freeBlocks++;
}
}
void ObjPoolCleanUp(ObjPool *const restrict objpool, void **ptrref)
void ObjPoolCleanUp(ObjPool *const restrict objpool, void **const restrict ptrref)
{
if ((objpool == NULL) || (ptrref == NULL) || (*ptrref == NULL)) return;
if (ptrref == NULL) return;
else
{
ObjPoolFree(objpool, *ptrref);
@ -694,71 +632,85 @@ void ObjPoolCleanUp(ObjPool *const restrict objpool, void **ptrref)
BiStack CreateBiStack(const size_t len)
{
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.mem = malloc(len*sizeof *destack.mem);
if (destack.mem==NULL) destack.size = 0UL;
else
{
destack.front = destack.mem;
destack.back = destack.mem + len;
}
destack.mem = ( uintptr_t )buf;
destack.front = destack.mem;
destack.back = destack.mem + len;
return destack;
}
BiStack CreateBiStackFromBuffer(void *const buf, const size_t len)
{
BiStack destack = { 0 };
if (len == 0UL || buf == NULL) return destack;
destack.size = len;
destack.mem = destack.front = buf;
destack.back = destack.mem + len;
return destack;
if (len == 0 || buf == NULL) return destack;
else
{
destack.size = len;
destack.mem = destack.front = ( uintptr_t )buf;
destack.back = destack.mem + len;
return destack;
}
}
void DestroyBiStack(BiStack *const destack)
void DestroyBiStack(BiStack *const restrict destack)
{
if ((destack == NULL) || (destack->mem == NULL)) return;
free(destack->mem);
*destack = (BiStack){0};
if (destack->mem == 0) return;
else
{
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;
const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t));
// front end stack is too high!
if (destack->front + ALIGNED_LEN >= destack->back) return NULL;
uint8_t *ptr = destack->front;
destack->front += ALIGNED_LEN;
return ptr;
if (destack->mem == 0) return NULL;
else
{
const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t));
// front end arena is too high!
if (destack->front + ALIGNED_LEN >= destack->back) return NULL;
else
{
uint8_t *const restrict ptr = ( uint8_t* )destack->front;
destack->front += ALIGNED_LEN;
return ptr;
}
}
}
void *BiStackAllocBack(BiStack *const destack, const size_t len)
void *BiStackAllocBack(BiStack *const restrict destack, const size_t len)
{
if ((destack == NULL) || (destack->mem == NULL)) return NULL;
const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t));
// back end stack is too low
if (destack->back - ALIGNED_LEN <= destack->front) return NULL;
destack->back -= ALIGNED_LEN;
return destack->back;
if (destack->mem == 0) return NULL;
else
{
const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t));
// back end arena is too low
if (destack->back - ALIGNED_LEN <= destack->front) return NULL;
else
{
destack->back -= ALIGNED_LEN;
uint8_t *const restrict ptr = ( uint8_t* )destack->back;
return ptr;
}
}
}
void BiStackResetFront(BiStack *const destack)
{
if ((destack == NULL) || (destack->mem == NULL)) return;
destack->front = destack->mem;
if (destack->mem == 0) return;
else destack->front = destack->mem;
}
void BiStackResetBack(BiStack *const destack)
{
if ((destack == NULL) || (destack->mem == NULL)) return;
destack->back = destack->mem + destack->size;
if (destack->mem == 0) return;
else destack->back = destack->mem + destack->size;
}
void BiStackResetAll(BiStack *const destack)
@ -767,9 +719,21 @@ void BiStackResetAll(BiStack *const destack)
BiStackResetFront(destack);
}
intptr_t BiStackMargins(const BiStack destack)
inline intptr_t BiStackMargins(const BiStack destack)
{
return destack.back - destack.front;
}
#endif // RMEM_IMPLEMENTATION
/*******
* Changelog
* v1.0: First Creation.
* v1.1: bug patches for the mempool and addition of object pool.
* v1.2: addition of bidirectional arena.
* v1.3:
* optimizations of allocators.
* renamed 'Stack' to 'Arena'.
* replaced certain define constants with an anonymous enum.
* refactored MemPool to no longer require active or deferred defragging.
********/

2252
raylib/rnet.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -47,7 +47,12 @@
//----------------------------------------------------------------------------------
// 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
@ -155,17 +160,19 @@ void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
// Draw line using cubic-bezier curves in-out
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 current;
for (int i = 1; i <= LINE_DIVISIONS; i++)
for (int i = 1; i <= BEZIER_LINE_DIVISIONS; i++)
{
// Cubic easing in-out
// NOTE: Easing is calculated only for y position value
current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)LINE_DIVISIONS);
current.x = previous.x + (endPos.x - startPos.x)/ (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)BEZIER_LINE_DIVISIONS;
DrawLineEx(previous, current, thick, color);
@ -214,18 +221,15 @@ void DrawCircleSector(Vector2 center, float radius, int startAngle, int endAngle
if (segments < 4)
{
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
#define CIRCLE_ERROR_RATE 0.5f
// 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;
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
if (segments <= 0) segments = 4;
}
float stepLength = (float)(endAngle - startAngle)/(float)segments;
float angle = startAngle;
float angle = (float)startAngle;
#if defined(SUPPORT_QUADS_DRAW_MODE)
if (rlCheckBufferLimit(4*segments/2)) rlglDraw();
@ -306,20 +310,15 @@ void DrawCircleSectorLines(Vector2 center, float radius, int startAngle, int end
if (segments < 4)
{
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
#ifndef CIRCLE_ERROR_RATE
#define CIRCLE_ERROR_RATE 0.5f
#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;
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
if (segments <= 0) segments = 4;
}
float stepLength = (float)(endAngle - startAngle)/(float)segments;
float angle = startAngle;
float angle = (float)startAngle;
// Hide the cap lines when the circle is full
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)
{
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);
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);
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();
}
@ -407,9 +406,9 @@ void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color c
for (int i = 0; i < 360; i += 10)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(centerX, centerY);
rlVertex2f(centerX + sinf(DEG2RAD*i)*radiusH, centerY + cosf(DEG2RAD*i)*radiusV);
rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radiusH, centerY + cosf(DEG2RAD*(i + 10))*radiusV);
rlVertex2f((float)centerX, (float)centerY);
rlVertex2f((float)centerX + sinf(DEG2RAD*i)*radiusH, (float)centerY + cosf(DEG2RAD*i)*radiusV);
rlVertex2f((float)centerX + sinf(DEG2RAD*(i + 10))*radiusH, (float)centerY + cosf(DEG2RAD*(i + 10))*radiusV);
}
rlEnd();
}
@ -454,14 +453,9 @@ void DrawRing(Vector2 center, float innerRadius, float outerRadius, int startAng
if (segments < 4)
{
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
#ifndef CIRCLE_ERROR_RATE
#define CIRCLE_ERROR_RATE 0.5f
#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;
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
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 angle = startAngle;
float angle = (float)startAngle;
#if defined(SUPPORT_QUADS_DRAW_MODE)
if (rlCheckBufferLimit(4*segments)) rlglDraw();
@ -550,14 +544,9 @@ void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, int sta
if (segments < 4)
{
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
#ifndef CIRCLE_ERROR_RATE
#define CIRCLE_ERROR_RATE 0.5f
#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;
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
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 angle = startAngle;
float angle = (float)startAngle;
bool showCapLines = true;
int limit = 4*(segments + 1);
@ -629,6 +618,8 @@ void DrawRectangleRec(Rectangle rec, Color color)
// Draw a color-filled rectangle with pro parameters
void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color)
{
if (rlCheckBufferLimit(4)) rlglDraw();
rlEnableTexture(GetShapesTexture().id);
rlPushMatrix();
@ -764,13 +755,9 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
// Calculate number of segments to use for the corners
if (segments < 4)
{
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
#ifndef CIRCLE_ERROR_RATE
#define CIRCLE_ERROR_RATE 0.5f
#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;
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = (int)(ceilf(2*PI/th)/4.0f);
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
if (segments < 4)
{
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088
#ifndef CIRCLE_ERROR_RATE
#define CIRCLE_ERROR_RATE 0.5f
#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;
// Calculate the maximum angle between segments based on the error rate (usually 0.5f)
float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = (int)(ceilf(2*PI/th)/2.0f);
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
// 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)
{
if (pointsCount >= 3)
@ -1298,7 +1282,7 @@ void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color)
{
if (pointsCount >= 3)
{
if (rlCheckBufferLimit(pointsCount)) rlglDraw();
if (rlCheckBufferLimit(3*(pointsCount - 2))) rlglDraw();
rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a);

View file

@ -16,7 +16,7 @@
* #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
* 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)
*
*
@ -54,12 +54,12 @@
#endif
#include <stdlib.h> // Required for: malloc(), free()
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fgets()
#include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy(), strcat(), strncat(), sscanf()
#include <stdio.h> // Required for: vsprintf()
#include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()]
#include <stdarg.h> // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()]
#include <ctype.h> // Requried for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
#include "utils.h" // Required for: fopen() Android mapping
#include "utils.h" // Required for: LoadFileText()
#if defined(SUPPORT_FILEFORMAT_TTF)
#define STB_RECT_PACK_IMPLEMENTATION
@ -73,17 +73,15 @@
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal()
#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()
#ifndef MAX_TEXT_BUFFER_LENGTH
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
#endif
#if !defined(TEXTSPLIT_MAX_SUBSTRINGS_COUNT)
#define TEXTSPLIT_MAX_SUBSTRINGS_COUNT 128 // Size of static pointers array: TextSplit()
#ifndef MAX_TEXT_UNICODE_CHARS
#define MAX_TEXT_UNICODE_CHARS 512 // Maximum number of unicode codepoints: GetCodepoints()
#endif
#ifndef MAX_TEXTSPLIT_COUNT
#define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit()
#endif
//----------------------------------------------------------------------------------
@ -95,8 +93,9 @@
// Global variables
//----------------------------------------------------------------------------------
#if defined(SUPPORT_DEFAULT_FONT)
static Font defaultFont = { 0 }; // Default font provided by raylib
// NOTE: defaultFont is loaded on InitWindow and disposed on CloseWindow [module: core]
// Default font provided by raylib
// NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core]
static Font defaultFont = { 0 };
#endif
//----------------------------------------------------------------------------------
@ -192,33 +191,31 @@ extern void LoadFontDefault(void)
// Re-construct image from defaultFontData and generate OpenGL texture
//----------------------------------------------------------------------
int imWidth = 128;
int imHeight = 128;
Image imFont = {
.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));
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)
// 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 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++;
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);
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount
@ -295,15 +292,21 @@ Font GetFontDefault()
// Load Font from file into GPU memory (VRAM)
Font LoadFont(const char *fileName)
{
// Default hardcoded values for ttf file loading
#define DEFAULT_TTF_FONTSIZE 32 // Font first character (32 - space)
#define DEFAULT_TTF_NUMCHARS 95 // ASCII 32..126 is 95 glyphs
#define DEFAULT_FIRST_CHAR 32 // Expected first char for image sprite font
// Default values for ttf font generation
#ifndef FONT_TTF_DEFAULT_SIZE
#define FONT_TTF_DEFAULT_SIZE 32 // TTF font generation default char size (char-height)
#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 };
#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
#endif
#if defined(SUPPORT_FILEFORMAT_FNT)
@ -312,7 +315,7 @@ Font LoadFont(const char *fileName)
#endif
{
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);
}
@ -363,6 +366,10 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
// Load an Image font file (XNA style)
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))
int charSpacing = 0;
@ -371,13 +378,10 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
int x = 0;
int y = 0;
// Default number of characters supported
#define MAX_FONTCHARS 256
// We allocate a temporal arrays for chars data measures,
// once we get the actual number of chars, we copy data to a sized arrays
int tempCharValues[MAX_FONTCHARS];
Rectangle tempCharRecs[MAX_FONTCHARS];
int tempCharValues[MAX_GLYPHS_FROM_IMAGE];
Rectangle tempCharRecs[MAX_GLYPHS_FROM_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;
// Create a new image with the processed color data (key color replaced by BLANK)
Image fontClear = LoadImageEx(pixels, image.width, image.height);
RL_FREE(pixels); // Free pixels array memory
Image fontClear = {
.data = pixels,
.width = image.width,
.height = image.height,
.format = UNCOMPRESSED_R8G8B8A8,
.mipmaps = 1
};
// Create spritefont with all data parsed from image
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,
// trades off precision with ability to handle *smaller* sizes
#define SDF_CHAR_PADDING 4
#define SDF_ON_EDGE_VALUE 128
#define SDF_PIXEL_DIST_SCALE 64.0f
#define BITMAP_ALPHA_THRESHOLD 80
#ifndef FONT_SDF_CHAR_PADDING
#define FONT_SDF_CHAR_PADDING 4 // SDF font generation char padding
#endif
#ifndef FONT_SDF_ON_EDGE_VALUE
#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;
@ -541,7 +556,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
// 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);
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;
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
if (ch == 32)
{
chars[i].image = GenImageColor(chars[i].advanceX, fontSize, BLANK);
ImageFormat(&chars[i].image, UNCOMPRESSED_GRAYSCALE);
Image imSpace = {
.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)
@ -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
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;
}
}
@ -600,6 +622,12 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
{
Image atlas = { 0 };
if (chars == NULL)
{
TraceLog(LOG_WARNING, "FONT: Provided chars info not valid, returning empty image atlas");
return atlas;
}
*charRecs = NULL;
// 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
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;
@ -714,7 +742,6 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
// TODO: Crop image if required for smaller size
// 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
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
for (int i = 0; i < length; i++)
for (int i = 0; i < length;)
{
// Get next codepoint from byte string and glyph index in font
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);
}
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;
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;
}
@ -1053,11 +1080,14 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
// Returns index position for a unicode character on spritefont
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
#if defined(UNORDERED_CHARSET)
int index = TEXT_CHARACTER_NOTFOUND;
// Support charsets with any characters order
#define SUPPORT_UNORDERED_CHARSET
#if defined(SUPPORT_UNORDERED_CHARSET)
int index = GLYPH_NOTFOUND_CHAR_FALLBACK;
for (int i = 0; i < font.charsCount; i++)
{
@ -1077,7 +1107,64 @@ int GetGlyphIndex(Font font, int codepoint)
//----------------------------------------------------------------------------------
// 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
int TextCopy(char *dst, const char *src)
{
@ -1111,43 +1198,6 @@ bool TextIsEqual(const char *text1, const char *text2)
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
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)
char *TextReplace(char *text, const char *replace, const char *by)
{
// Sanity checks and initialization
if (!text || !replace || !by) return NULL;
char *result;
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 count; // Number of replacements
// Sanity checks and initialization
if (!text || !replace) return NULL;
replaceLen = TextLength(replace);
if (replaceLen == 0) return NULL; // Empty replace causes infinite loop during count
if (!by) by = ""; // Replace by nothing if not provided
byLen = TextLength(by);
// Count the number of replacements needed
@ -1213,7 +1262,7 @@ char *TextReplace(char *text, const char *replace, const char *by)
while (count--)
{
insertPoint = strstr(text, replace);
lastReplacePos = insertPoint - text;
lastReplacePos = (int)(insertPoint - text);
temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
temp = strcpy(temp, by) + byLen;
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
// REQUIRES: strcat()
// REQUIRES: memset(), memcpy()
const char *TextJoin(const char **textList, int count, const char *delimiter)
{
static char text[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(text, 0, MAX_TEXT_BUFFER_LENGTH);
char *textPtr = text;
int totalLength = 0;
int delimiterLen = TextLength(delimiter);
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
if ((totalLength + textListLength) < MAX_TEXT_BUFFER_LENGTH)
if ((totalLength + textLength) < MAX_TEXT_BUFFER_LENGTH)
{
strcat(text, textList[i]);
totalLength += textListLength;
memcpy(textPtr, textList[i], textLength);
totalLength += textLength;
textPtr += textLength;
if ((delimiterLen > 0) && (i < (count - 1)))
{
strcat(text, delimiter);
memcpy(textPtr, delimiter, 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)
// inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
// all used memory is static... it has some limitations:
// 1. Maximum number of possible split strings is set by TEXTSPLIT_MAX_SUBSTRINGS_COUNT
// 2. Maximum size of text to split is TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
// 1. Maximum number of possible split strings is set by MAX_TEXTSPLIT_COUNT
// 2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH
static const char *result[TEXTSPLIT_MAX_SUBSTRINGS_COUNT] = { NULL };
static char buffer[TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH);
static const char *result[MAX_TEXTSPLIT_COUNT] = { NULL };
static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
result[0] = buffer;
int counter = 0;
@ -1295,7 +1347,7 @@ const char **TextSplit(const char *text, char delimiter, int *count)
counter = 1;
// Count how many substrings we have on text and point to every one
for (int i = 0; i < TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH; i++)
for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
{
buffer[i] = text[i];
if (buffer[i] == '\0') break;
@ -1305,7 +1357,7 @@ const char **TextSplit(const char *text, char delimiter, int *count)
result[counter] = buffer + i + 1;
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);
if (ptr != NULL) position = ptr - text;
if (ptr != NULL) position = (int)(ptr - text);
return position;
}
@ -1398,24 +1450,6 @@ const char *TextToPascal(const char *text)
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!)
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++)
{
utf8 = CodepointToUtf8(codepoints[i], &bytes);
strncpy(text + size, utf8, bytes);
memcpy(text + size, utf8, bytes);
size += bytes;
}
@ -1440,6 +1474,44 @@ char *TextToUtf8(int *codepoints, int length)
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
int *GetCodepoints(const char *text, int *count)
{
@ -1481,7 +1553,7 @@ int GetCodepointsCount(const char *text)
return len;
}
#endif // SUPPORT_TEXT_MANIPULATION
// 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
@ -1595,50 +1667,23 @@ int GetNextCodepoint(const char *text, int *bytesProcessed)
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
//----------------------------------------------------------------------------------
#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)
// REQUIRES: strstr(), sscanf(), strrchr(), memcpy()
static Font LoadBMFont(const char *fileName)
{
#define MAX_BUFFER_SIZE 256
@ -1649,80 +1694,92 @@ static Font LoadBMFont(const char *fileName)
char *searchPoint = NULL;
int fontSize = 0;
int texWidth = 0;
int texHeight = 0;
char texFileName[129];
int charsCount = 0;
int imWidth = 0;
int imHeight = 0;
char imFileName[129];
int base = 0; // Useless data
FILE *fntFile = NULL;
char *fileText = LoadFileText(fileName);
fntFile = fopen(fileName, "rt");
if (fntFile == NULL)
{
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open FNT file", fileName);
return font;
}
if (fileText == NULL) return font;
char *fileTextPtr = fileText;
// NOTE: We skip first line, it contains no useful information
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
//searchPoint = strstr(buffer, "size");
//sscanf(searchPoint, "size=%i", &fontSize);
int lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
fileTextPtr += (lineBytes + 1);
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
// Read line data
lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
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(" > Base size: %i", fontSize);
TRACELOGD(" > Texture scale: %ix%i", texWidth, texHeight);
TRACELOGD(" > Base size: %i", fontSize);
TRACELOGD(" > Texture scale: %ix%i", imWidth, imHeight);
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
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");
sscanf(searchPoint, "count=%i", &charsCount);
fileTextPtr += (lineBytes + 1);
TRACELOGD(" > Chars count: %i", charsCount);
// Compose correct path using route of .fnt file (fileName) and texFileName
char *texPath = NULL;
// Compose correct path using route of .fnt file (fileName) and imFileName
char *imPath = NULL;
char *lastSlash = NULL;
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!
texPath = RL_MALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(texFileName) + 4);
TRACELOGD(" > Image loading path: %s", imPath);
// NOTE: strcat() and strncat() required a '\0' terminated string to work!
*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);
Image imFont = LoadImage(imPath);
if (imFont.format == UNCOMPRESSED_GRAYSCALE)
{
// Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
ImageAlphaMask(&imFont, imFont);
for (int p = 0; p < (imFont.width*imFont.height*2); p += 2) ((unsigned char *)(imFont.data))[p] = 0xff;
Image imFontAlpha = {
.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);
RL_FREE(texPath);
if (lastSlash != NULL) RL_FREE(imPath);
// Fill font characters info data
font.baseSize = fontSize;
@ -1734,9 +1791,10 @@ static Font LoadBMFont(const char *fileName)
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",
&charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX);
fileTextPtr += (lineBytes + 1);
// Get character rectangle in the font atlas texture
font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight };
@ -1752,8 +1810,7 @@ static Font LoadBMFont(const char *fileName)
}
UnloadImage(imFont);
fclose(fntFile);
RL_FREE(fileText);
if (font.texture.id == 0)
{

File diff suppressed because it is too large Load diff

View file

@ -49,27 +49,6 @@ func LoadImage(fileName string) *Image {
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
func LoadImageRaw(fileName string, width, height int32, format PixelFormat, headerSize int32) *Image {
cfileName := C.CString(fileName)
@ -165,6 +144,14 @@ func UpdateTexture(texture Texture2D, pixels []Color) {
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
func ExportImage(image Image, name string) {
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)
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()
cposition := position.cptr()
posx := (C.int)(posX)
posy := (C.int)(posY)
ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext))
cfontSize := (C.int)(fontSize)
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)
@ -349,7 +337,7 @@ func ImageDrawTextEx(dst *Image, position Vector2, font Font, text string, fontS
cfontSize := (C.float)(fontSize)
cspacing := (C.float)(spacing)
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

View file

@ -50,9 +50,15 @@
#include <stdarg.h> // Required for: va_list, va_start(), va_end()
#include <string.h> // Required for: strcpy(), strcat()
#define MAX_TRACELOG_BUFFER_SIZE 128 // Max length of one trace-log message
#define MAX_UWP_MESSAGES 512 // Max UWP messages to process
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#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
@ -68,13 +74,6 @@ static AAssetManager *assetManager = NULL; // Android assets manage
static const char *internalDataPath = NULL; // Android internal data path
#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
//----------------------------------------------------------------------------------
@ -139,7 +138,7 @@ void TraceLog(int logType, const char *text, ...)
default: break;
}
#else
char buffer[MAX_TRACELOG_BUFFER_SIZE] = { 0 };
char buffer[MAX_TRACELOG_MSG_LENGTH] = { 0 };
switch (logType)
{
@ -184,10 +183,10 @@ unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead)
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]
unsigned int count = fread(data, sizeof(unsigned char), size, file);
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);
@ -213,7 +212,7 @@ void SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite)
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);
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...
// ...but using fseek() should return correct byte-offset
fseek(textFile, 0, SEEK_END);
int size = ftell(textFile);
unsigned int size = (unsigned int)ftell(textFile);
fseek(textFile, 0, SEEK_SET);
if (size > 0)
{
text = (char *)RL_MALLOC(sizeof(char)*(size + 1));
int count = fread(text, sizeof(char), size, textFile);
text = (char *)RL_MALLOC((size + 1)*sizeof(char));
unsigned int count = (unsigned int)fread(text, sizeof(char), size, textFile);
// WARNING: \r\n is converted to \n on reading, so,
// 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
AAsset *asset = AAssetManager_open(assetManager, fileName, AASSET_MODE_UNKNOWN);
if (asset != NULL) return funopen(asset, android_read, android_write, android_seek, android_close);
else return NULL;
if (asset != 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
@ -351,69 +360,3 @@ static int android_close(void *cookie)
return 0;
}
#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

View file

@ -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!
#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
}
#endif

119
raylib/uwp_events.h Normal file
View 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