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() #include <math.h> // Required for: sinf(), cosf(), sqrtf()
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#ifndef PI #ifndef PI
#define PI 3.14159265358979323846 #define PI 3.14159265358979323846
#endif #endif
@ -145,9 +148,6 @@ void SetCameraMoveControls(int frontKey, int backKey,
#define RAD2DEG (180.0f/PI) #define RAD2DEG (180.0f/PI)
#endif #endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
// Camera mouse movement sensitivity // Camera mouse movement sensitivity
#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f #define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f
#define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f #define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f
@ -170,7 +170,7 @@ void SetCameraMoveControls(int frontKey, int backKey,
#define CAMERA_FIRST_PERSON_MIN_CLAMP 89.0f #define CAMERA_FIRST_PERSON_MIN_CLAMP 89.0f
#define CAMERA_FIRST_PERSON_MAX_CLAMP -89.0f #define CAMERA_FIRST_PERSON_MAX_CLAMP -89.0f
#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 5.0f #define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 8.0f
#define CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f #define CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f
#define CAMERA_FIRST_PERSON_WAVING_DIVIDER 200.0f #define CAMERA_FIRST_PERSON_WAVING_DIVIDER 200.0f
@ -197,17 +197,18 @@ typedef enum {
MOVE_DOWN MOVE_DOWN
} CameraMove; } CameraMove;
// Camera global state context data // Camera global state context data [56 bytes]
typedef struct { typedef struct {
int mode; // Current camera mode unsigned int mode; // Current camera mode
float targetDistance; // Camera distance from position to target float targetDistance; // Camera distance from position to target
float playerEyesPosition; // Default player eyes position from ground (in meters) float playerEyesPosition; // Player eyes position from ground (in meters)
Vector2 angle; // Camera angle in plane XZ Vector2 angle; // Camera angle in plane XZ
int moveControl[6]; // Camera movement control keys
int smoothZoomControl; // raylib: KEY_LEFT_CONTROL int moveControl[6]; // Move controls (CAMERA_FIRST_PERSON)
int altControl; // raylib: KEY_LEFT_ALT int smoothZoomControl; // Smooth zoom control key
int panControl; // raylib: MOUSE_MIDDLE_BUTTON int altControl; // Alternative control key
int panControl; // Pan view control key
} CameraData; } CameraData;
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -219,9 +220,9 @@ static CameraData CAMERA = { // Global CAMERA state context
.playerEyesPosition = 1.85f, .playerEyesPosition = 1.85f,
.angle = { 0 }, .angle = { 0 },
.moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' }, .moveControl = { 'W', 'S', 'D', 'A', 'E', 'Q' },
.smoothZoomControl = 341, .smoothZoomControl = 341, // raylib: KEY_LEFT_CONTROL
.altControl = 342, .altControl = 342, // raylib: KEY_LEFT_ALT
.panControl = 2 .panControl = 2 // raylib: MOUSE_MIDDLE_BUTTON
}; };
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -253,13 +254,13 @@ void SetCameraMode(Camera camera, int mode)
float dy = v2.y - v1.y; float dy = v2.y - v1.y;
float dz = v2.z - v1.z; float dz = v2.z - v1.z;
CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz); CAMERA.targetDistance = sqrtf(dx*dx + dy*dy + dz*dz); // Distance to target
// Camera angle calculation // Camera angle calculation
CAMERA.angle.x = atan2f(dx, dz); // Camera angle in plane XZ (0 aligned with Z, move positive CCW) CAMERA.angle.x = atan2f(dx, dz); // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz)); // Camera angle in plane XY (0 aligned with X, move positive CW) CAMERA.angle.y = atan2f(dy, sqrtf(dx*dx + dz*dz)); // Camera angle in plane XY (0 aligned with X, move positive CW)
CAMERA.playerEyesPosition = camera.position.y; CAMERA.playerEyesPosition = camera.position.y; // Init player eyes position to camera Y position
// Lock cursor for first person and third person cameras // Lock cursor for first person and third person cameras
if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor(); if ((mode == CAMERA_FIRST_PERSON) || (mode == CAMERA_THIRD_PERSON)) DisableCursor();
@ -287,6 +288,7 @@ void UpdateCamera(Camera *camera)
int mouseWheelMove = GetMouseWheelMove(); int mouseWheelMove = GetMouseWheelMove();
// Keys input detection // Keys input detection
// TODO: Input detection is raylib-dependant, it could be moved outside the module
bool panKey = IsMouseButtonDown(CAMERA.panControl); bool panKey = IsMouseButtonDown(CAMERA.panControl);
bool altKey = IsKeyDown(CAMERA.altControl); bool altKey = IsKeyDown(CAMERA.altControl);
bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl); bool szoomKey = IsKeyDown(CAMERA.smoothZoomControl);
@ -297,8 +299,6 @@ void UpdateCamera(Camera *camera)
IsKeyDown(CAMERA.moveControl[MOVE_UP]), IsKeyDown(CAMERA.moveControl[MOVE_UP]),
IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) }; IsKeyDown(CAMERA.moveControl[MOVE_DOWN]) };
// TODO: Touch input detection (probably gestures system required)
if (CAMERA.mode != CAMERA_CUSTOM) if (CAMERA.mode != CAMERA_CUSTOM)
{ {
mousePositionDelta.x = mousePosition.x - previousMousePosition.x; mousePositionDelta.x = mousePosition.x - previousMousePosition.x;
@ -321,7 +321,6 @@ void UpdateCamera(Camera *camera)
} }
// Camera looking down // Camera looking down
// TODO: Review, weird comparison of CAMERA.targetDistance == 120.0f?
else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) else if ((camera->position.y > camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
{ {
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
@ -342,7 +341,6 @@ void UpdateCamera(Camera *camera)
if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP; if (CAMERA.targetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) CAMERA.targetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
} }
// Camera looking up // Camera looking up
// TODO: Review, weird comparisson of CAMERA.targetDistance == 120.0f?
else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0)) else if ((camera->position.y < camera->target.y) && (CAMERA.targetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
{ {
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance; camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/CAMERA.targetDistance;
@ -489,8 +487,10 @@ void UpdateCamera(Camera *camera)
// TODO: It seems camera->position is not correctly updated or some rounding issue makes the camera move straight to camera->target... // TODO: It seems camera->position is not correctly updated or some rounding issue makes the camera move straight to camera->target...
camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x; camera->position.x = sinf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.x;
if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; if (CAMERA.angle.y <= 0.0f) camera->position.y = sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y; else camera->position.y = -sinf(CAMERA.angle.y)*CAMERA.targetDistance*sinf(CAMERA.angle.y) + camera->target.y;
camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z; camera->position.z = cosf(CAMERA.angle.x)*CAMERA.targetDistance*cosf(CAMERA.angle.y) + camera->target.z;
} break; } break;

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 // Edit to control what features Makefile'd raylib is compiled with
#if defined(RAYLIB_CMAKE) #if defined(RAYLIB_CMAKE)
@ -63,12 +63,56 @@
// Support saving binary data automatically to a generated storage.data file. This file is managed internally. // Support saving binary data automatically to a generated storage.data file. This file is managed internally.
#define SUPPORT_DATA_STORAGE 1 #define SUPPORT_DATA_STORAGE 1
// core: Configuration values
//------------------------------------------------------------------------------------
#if defined(__linux__)
#define MAX_FILEPATH_LENGTH 4096 // Maximum length for filepaths (Linux PATH_MAX default value)
#else
#define MAX_FILEPATH_LENGTH 512 // Maximum length supported for filepaths
#endif
#define MAX_GAMEPADS 4 // Max number of gamepads supported
#define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad)
#define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad)
#define MAX_TOUCH_POINTS 10 // Maximum number of touch points supported
#define MAX_KEY_PRESSED_QUEUE 16 // Max number of characters in the key input queue
#define STORAGE_DATA_FILE "storage.data" // Automatic storage filename
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Module: rlgl - Configuration Flags // Module: rlgl - Configuration Flags
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Support VR simulation functionality (stereo rendering) // Support VR simulation functionality (stereo rendering)
#define SUPPORT_VR_SIMULATOR 1 #define SUPPORT_VR_SIMULATOR 1
// rlgl: Configuration values
//------------------------------------------------------------------------------------
#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
#define DEFAULT_BATCH_BUFFER_ELEMENTS 8192 // Default internal render batch limits
#elif defined(GRAPHICS_API_OPENGL_ES2)
#define DEFAULT_BATCH_BUFFER_ELEMENTS 2048 // Default internal render batch limits
#endif
#define DEFAULT_BATCH_BUFFERS 1 // Default number of batch buffers (multi-buffering)
#define DEFAULT_BATCH_DRAWCALLS 256 // Default number of batch draw calls (by state changes: mode, texture)
#define MAX_MATRIX_STACK_SIZE 32 // Maximum size of internal Matrix stack
#define MAX_SHADER_LOCATIONS 32 // Maximum number of shader locations supported
#define MAX_MATERIAL_MAPS 12 // Maximum number of shader maps supported
#define RL_CULL_DISTANCE_NEAR 0.01 // Default projection matrix near cull distance
#define RL_CULL_DISTANCE_FAR 1000.0 // Default projection matrix far cull distance
// Default shader vertex attribute names to set location points
#define DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Binded by default to shader location: 0
#define DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Binded by default to shader location: 1
#define DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Binded by default to shader location: 2
#define DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Binded by default to shader location: 3
#define DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Binded by default to shader location: 4
#define DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Binded by default to shader location: 5
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Module: shapes - Configuration Flags // Module: shapes - Configuration Flags
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
@ -79,6 +123,7 @@
// Some lines-based shapes could still use lines // Some lines-based shapes could still use lines
#define SUPPORT_QUADS_DRAW_MODE 1 #define SUPPORT_QUADS_DRAW_MODE 1
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Module: textures - Configuration Flags // Module: textures - Configuration Flags
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
@ -86,7 +131,7 @@
#define SUPPORT_FILEFORMAT_PNG 1 #define SUPPORT_FILEFORMAT_PNG 1
#define SUPPORT_FILEFORMAT_BMP 1 #define SUPPORT_FILEFORMAT_BMP 1
#define SUPPORT_FILEFORMAT_TGA 1 #define SUPPORT_FILEFORMAT_TGA 1
#define SUPPORT_FILEFORMAT_JPG 1 //#define SUPPORT_FILEFORMAT_JPG 1
#define SUPPORT_FILEFORMAT_GIF 1 #define SUPPORT_FILEFORMAT_GIF 1
//#define SUPPORT_FILEFORMAT_PSD 1 //#define SUPPORT_FILEFORMAT_PSD 1
#define SUPPORT_FILEFORMAT_DDS 1 #define SUPPORT_FILEFORMAT_DDS 1
@ -98,11 +143,12 @@
// Support image export functionality (.png, .bmp, .tga, .jpg) // Support image export functionality (.png, .bmp, .tga, .jpg)
#define SUPPORT_IMAGE_EXPORT 1 #define SUPPORT_IMAGE_EXPORT 1
// Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
// If not defined only three image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageToPOT()
#define SUPPORT_IMAGE_MANIPULATION 1
// Support procedural image generation functionality (gradient, spot, perlin-noise, cellular) // Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)
#define SUPPORT_IMAGE_GENERATION 1 #define SUPPORT_IMAGE_GENERATION 1
// Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop...
// If not defined, still some functions are supported: ImageFormat(), ImageCrop(), ImageToPOT()
#define SUPPORT_IMAGE_MANIPULATION 1
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Module: text - Configuration Flags // Module: text - Configuration Flags
@ -114,6 +160,18 @@
#define SUPPORT_FILEFORMAT_FNT 1 #define SUPPORT_FILEFORMAT_FNT 1
#define SUPPORT_FILEFORMAT_TTF 1 #define SUPPORT_FILEFORMAT_TTF 1
// Support text management functions
// If not defined, still some functions are supported: TextLength(), TextFormat()
#define SUPPORT_TEXT_MANIPULATION 1
// text: Configuration values
//------------------------------------------------------------------------------------
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
#define MAX_TEXT_UNICODE_CHARS 512 // Maximum number of unicode codepoints: GetCodepoints()
#define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit()
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Module: models - Configuration Flags // Module: models - Configuration Flags
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
@ -126,6 +184,7 @@
// NOTE: Some generated meshes DO NOT include generated texture coordinates // NOTE: Some generated meshes DO NOT include generated texture coordinates
#define SUPPORT_MESH_GENERATION 1 #define SUPPORT_MESH_GENERATION 1
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Module: audio - Configuration Flags // Module: audio - Configuration Flags
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
@ -137,6 +196,15 @@
//#define SUPPORT_FILEFORMAT_FLAC 1 //#define SUPPORT_FILEFORMAT_FLAC 1
#define SUPPORT_FILEFORMAT_MP3 1 #define SUPPORT_FILEFORMAT_MP3 1
// audio: Configuration values
//------------------------------------------------------------------------------------
#define AUDIO_DEVICE_FORMAT ma_format_f32 // Device output format (miniaudio: float-32bit)
#define AUDIO_DEVICE_CHANNELS 2 // Device output channels: stereo
#define AUDIO_DEVICE_SAMPLE_RATE 44100 // Device output sample rate
#define DEFAULT_AUDIO_BUFFER_SIZE 4096 // Default audio buffer size for streaming
#define MAX_AUDIO_BUFFER_POOL_CHANNELS 16 // Maximum number of audio pool channels
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Module: utils - Configuration Flags // Module: utils - Configuration Flags
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
@ -145,4 +213,10 @@
#define SUPPORT_TRACELOG 1 #define SUPPORT_TRACELOG 1
//#define SUPPORT_TRACELOG_DEBUG 1 //#define SUPPORT_TRACELOG_DEBUG 1
// utils: Configuration values
//------------------------------------------------------------------------------------
#define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message
#define MAX_UWP_MESSAGES 512 // Max UWP messages to process
#endif //defined(RAYLIB_CMAKE) #endif //defined(RAYLIB_CMAKE)

File diff suppressed because it is too large Load diff

View file

@ -100,9 +100,9 @@ func UnhideWindow() {
C.UnhideWindow() C.UnhideWindow()
} }
// HideWindow - Hide the window // DecorateWindow - Decorate the window (only PLATFORM_DESKTOP)
func HideWindow() { func DecorateWindow() {
C.HideWindow() C.DecorateWindow()
} }
// SetWindowIcon - Set icon for window (only PLATFORM_DESKTOP) // 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 #ifndef INCLUDE_JAR_MOD_H
#define INCLUDE_JAR_MOD_H #define INCLUDE_JAR_MOD_H
#include <stdio.h> // Allow custom memory allocators
#include <stdlib.h> #ifndef JARMOD_MALLOC
//#include <stdbool.h> #define JARMOD_MALLOC(sz) malloc(sz)
#endif
#ifndef JARMOD_FREE
#ifdef __cplusplus #define JARMOD_FREE(p) free(p)
extern "C" {
#endif #endif
// Basic type // Basic type
@ -240,7 +238,9 @@ typedef struct jar_mod_tracker_buffer_state_
tracker_state * track_state_buf; tracker_state * track_state_buf;
}jar_mod_tracker_buffer_state; }jar_mod_tracker_buffer_state;
#ifdef __cplusplus
extern "C" {
#endif
bool jar_mod_init(jar_mod_context_t * modctx); bool jar_mod_init(jar_mod_context_t * modctx);
bool jar_mod_setcfg(jar_mod_context_t * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter); bool jar_mod_setcfg(jar_mod_context_t * modctx, int samplerate, int bits, int stereo, int stereo_separation, int filter);
@ -261,6 +261,10 @@ void jar_mod_seek_start(jar_mod_context_t * ctx);
//------------------------------------------------------------------------------- //-------------------------------------------------------------------------------
#ifdef JAR_MOD_IMPLEMENTATION #ifdef JAR_MOD_IMPLEMENTATION
#include <stdio.h>
#include <stdlib.h>
//#include <stdbool.h>
// Effects list // Effects list
#define EFFECT_ARPEGGIO 0x0 // Supported #define EFFECT_ARPEGGIO 0x0 // Supported
#define EFFECT_PORTAMENTO_UP 0x1 // Supported #define EFFECT_PORTAMENTO_UP 0x1 // Supported
@ -1504,7 +1508,7 @@ void jar_mod_unload( jar_mod_context_t * modctx)
{ {
if(modctx->modfile) if(modctx->modfile)
{ {
free(modctx->modfile); JARMOD_FREE(modctx->modfile);
modctx->modfile = 0; modctx->modfile = 0;
modctx->modfilesize = 0; modctx->modfilesize = 0;
modctx->loopcount = 0; modctx->loopcount = 0;
@ -1513,14 +1517,12 @@ void jar_mod_unload( jar_mod_context_t * modctx)
} }
} }
mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename) mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename)
{ {
mulong fsize = 0; mulong fsize = 0;
if(modctx->modfile) if(modctx->modfile)
{ {
free(modctx->modfile); JARMOD_FREE(modctx->modfile);
modctx->modfile = 0; modctx->modfile = 0;
} }
@ -1533,7 +1535,7 @@ mulong jar_mod_load_file(jar_mod_context_t * modctx, const char* filename)
if(fsize && fsize < 32*1024*1024) if(fsize && fsize < 32*1024*1024)
{ {
modctx->modfile = malloc(fsize); modctx->modfile = JARMOD_MALLOC(fsize);
modctx->modfilesize = fsize; modctx->modfilesize = fsize;
memset(modctx->modfile, 0, fsize); memset(modctx->modfile, 0, fsize);
fread(modctx->modfile, fsize, 1, f); fread(modctx->modfile, fsize, 1, f);

View file

@ -51,27 +51,29 @@
#ifndef INCLUDE_JAR_XM_H #ifndef INCLUDE_JAR_XM_H
#define INCLUDE_JAR_XM_H #define INCLUDE_JAR_XM_H
#include <stdint.h>
#define JAR_XM_DEBUG 0 #define JAR_XM_DEBUG 0
#define JAR_XM_LINEAR_INTERPOLATION 1 // speed increase with decrease in quality #define JAR_XM_LINEAR_INTERPOLATION 1 // speed increase with decrease in quality
#define JAR_XM_DEFENSIVE 1 #define JAR_XM_DEFENSIVE 1
#define JAR_XM_RAMPING 1 #define JAR_XM_RAMPING 1
#include <stdio.h> // Allow custom memory allocators
#include <stdlib.h> #ifndef JARXM_MALLOC
#include <stdint.h> #define JARXM_MALLOC(sz) malloc(sz)
#include <limits.h> #endif
#include <string.h> #ifndef JARXM_FREE
#define JARXM_FREE(p) free(p)
//-------------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif #endif
//-------------------------------------------------------------------------------
struct jar_xm_context_s; struct jar_xm_context_s;
typedef struct jar_xm_context_s jar_xm_context_t; typedef struct jar_xm_context_s jar_xm_context_t;
#ifdef __cplusplus
extern "C" {
#endif
/** Create a XM context. /** Create a XM context.
* *
* @param moddata the contents of the module * @param moddata the contents of the module
@ -133,7 +135,7 @@ void jar_xm_generate_samples(jar_xm_context_t* ctx, float* output, size_t numsam
*/ */
void jar_xm_generate_samples_16bit(jar_xm_context_t* ctx, short* output, size_t numsamples) void jar_xm_generate_samples_16bit(jar_xm_context_t* ctx, short* output, size_t numsamples)
{ {
float* musicBuffer = malloc((2*numsamples)*sizeof(float)); float* musicBuffer = JARXM_MALLOC((2*numsamples)*sizeof(float));
jar_xm_generate_samples(ctx, musicBuffer, numsamples); jar_xm_generate_samples(ctx, musicBuffer, numsamples);
if(output){ if(output){
@ -142,7 +144,7 @@ void jar_xm_generate_samples_16bit(jar_xm_context_t* ctx, short* output, size_t
output[x] = musicBuffer[x] * SHRT_MAX; output[x] = musicBuffer[x] * SHRT_MAX;
} }
free(musicBuffer); JARXM_FREE(musicBuffer);
} }
/** Play the module, resample from 32 bit to 8 bit, and put the sound samples in an output buffer. /** Play the module, resample from 32 bit to 8 bit, and put the sound samples in an output buffer.
@ -152,7 +154,7 @@ void jar_xm_generate_samples_16bit(jar_xm_context_t* ctx, short* output, size_t
*/ */
void jar_xm_generate_samples_8bit(jar_xm_context_t* ctx, char* output, size_t numsamples) void jar_xm_generate_samples_8bit(jar_xm_context_t* ctx, char* output, size_t numsamples)
{ {
float* musicBuffer = malloc((2*numsamples)*sizeof(float)); float* musicBuffer = JARXM_MALLOC((2*numsamples)*sizeof(float));
jar_xm_generate_samples(ctx, musicBuffer, numsamples); jar_xm_generate_samples(ctx, musicBuffer, numsamples);
if(output){ if(output){
@ -161,7 +163,7 @@ void jar_xm_generate_samples_8bit(jar_xm_context_t* ctx, char* output, size_t nu
output[x] = musicBuffer[x] * CHAR_MAX; output[x] = musicBuffer[x] * CHAR_MAX;
} }
free(musicBuffer); JARXM_FREE(musicBuffer);
} }
@ -306,6 +308,9 @@ uint64_t jar_xm_get_remaining_samples(jar_xm_context_t* ctx);
#ifdef JAR_XM_IMPLEMENTATION #ifdef JAR_XM_IMPLEMENTATION
#include <math.h> #include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h> #include <string.h>
#if JAR_XM_DEBUG //JAR_XM_DEBUG defined as 0 #if JAR_XM_DEBUG //JAR_XM_DEBUG defined as 0
@ -630,10 +635,10 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz
#endif #endif
bytes_needed = jar_xm_get_memory_needed_for_context(moddata, moddata_length); bytes_needed = jar_xm_get_memory_needed_for_context(moddata, moddata_length);
mempool = malloc(bytes_needed); mempool = JARXM_MALLOC(bytes_needed);
if(mempool == NULL && bytes_needed > 0) { if(mempool == NULL && bytes_needed > 0) {
/* malloc() failed, trouble ahead */ /* JARXM_MALLOC() failed, trouble ahead */
DEBUG("call to malloc() failed, returned %p", (void*)mempool); DEBUG("call to JARXM_MALLOC() failed, returned %p", (void*)mempool);
return 2; return 2;
} }
@ -641,7 +646,7 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz
memset(mempool, 0, bytes_needed); memset(mempool, 0, bytes_needed);
ctx = (*ctxp = (jar_xm_context_t *)mempool); ctx = (*ctxp = (jar_xm_context_t *)mempool);
ctx->allocated_memory = mempool; /* Keep original pointer for free() */ ctx->allocated_memory = mempool; /* Keep original pointer for JARXM_FREE() */
mempool += sizeof(jar_xm_context_t); mempool += sizeof(jar_xm_context_t);
ctx->rate = rate; ctx->rate = rate;
@ -691,7 +696,7 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz
} }
void jar_xm_free_context(jar_xm_context_t* ctx) { void jar_xm_free_context(jar_xm_context_t* ctx) {
free(ctx->allocated_memory); JARXM_FREE(ctx->allocated_memory);
} }
void jar_xm_set_max_loop_count(jar_xm_context_t* ctx, uint8_t loopcnt) { void jar_xm_set_max_loop_count(jar_xm_context_t* ctx, uint8_t loopcnt) {
@ -2620,11 +2625,11 @@ int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const
return 4; return 4;
} }
char* data = malloc(size + 1); char* data = JARXM_MALLOC(size + 1);
if(!data || fread(data, 1, size, xmf) < size) { if(!data || fread(data, 1, size, xmf) < size) {
fclose(xmf); fclose(xmf);
DEBUG_ERR(data ? "fread() failed" : "malloc() failed"); DEBUG_ERR(data ? "fread() failed" : "JARXM_MALLOC() failed");
free(data); JARXM_FREE(data);
*ctx = NULL; *ctx = NULL;
return 5; return 5;
} }
@ -2632,7 +2637,7 @@ int jar_xm_create_context_from_file(jar_xm_context_t** ctx, uint32_t rate, const
fclose(xmf); fclose(xmf);
ret = jar_xm_create_context_safe(ctx, data, size, rate); ret = jar_xm_create_context_safe(ctx, data, size, rate);
free(data); JARXM_FREE(data);
switch(ret) { switch(ret) {
case 0: case 0:
@ -2670,7 +2675,7 @@ void jar_xm_reset(jar_xm_context_t* ctx)
jar_xm_cut_note(&ctx->channels[i]); jar_xm_cut_note(&ctx->channels[i]);
} }
ctx->current_row = 0; ctx->current_row = 0;
ctx->current_table_index = ctx->module.restart_position; ctx->current_table_index = 0;
ctx->current_tick = 0; ctx->current_tick = 0;
} }

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

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 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 * raudio - A simple and easy-to-use audio library based on miniaudio
@ -161,6 +159,9 @@ typedef struct tagBITMAPINFOHEADER {
#define MA_FREE RL_FREE #define MA_FREE RL_FREE
#define MA_NO_JACK #define MA_NO_JACK
#define MA_NO_WAV
#define MA_NO_FLAC
#define MA_NO_MP3
#define MINIAUDIO_IMPLEMENTATION #define MINIAUDIO_IMPLEMENTATION
#include "external/miniaudio.h" // miniaudio library #include "external/miniaudio.h" // miniaudio library
#undef PlaySound // Win32 API: windows.h > mmsystem.h defines PlaySound macro #undef PlaySound // Win32 API: windows.h > mmsystem.h defines PlaySound macro
@ -174,6 +175,20 @@ typedef struct tagBITMAPINFOHEADER {
#if !defined(TRACELOG) #if !defined(TRACELOG)
#define TRACELOG(level, ...) (void)0 #define TRACELOG(level, ...) (void)0
#endif #endif
// Allow custom memory allocators
#ifndef RL_MALLOC
#define RL_MALLOC(sz) malloc(sz)
#endif
#ifndef RL_CALLOC
#define RL_CALLOC(n,sz) calloc(n,sz)
#endif
#ifndef RL_REALLOC
#define RL_REALLOC(ptr,sz) realloc(ptr,sz)
#endif
#ifndef RL_FREE
#define RL_FREE(ptr) free(ptr)
#endif
#endif #endif
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
@ -199,14 +214,13 @@ typedef struct tagBITMAPINFOHEADER {
#include "external/jar_mod.h" // MOD loading functions #include "external/jar_mod.h" // MOD loading functions
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC) #if defined(SUPPORT_FILEFORMAT_WAV)
#define DRFLAC_MALLOC RL_MALLOC #define DRWAV_MALLOC RL_MALLOC
#define DRFLAC_REALLOC RL_REALLOC #define DRWAV_REALLOC RL_REALLOC
#define DRFLAC_FREE RL_FREE #define DRWAV_FREE RL_FREE
#define DR_FLAC_IMPLEMENTATION #define DR_WAV_IMPLEMENTATION
#define DR_FLAC_NO_WIN32_IO #include "external/dr_wav.h" // WAV loading functions
#include "external/dr_flac.h" // FLAC loading functions
#endif #endif
#if defined(SUPPORT_FILEFORMAT_MP3) #if defined(SUPPORT_FILEFORMAT_MP3)
@ -218,6 +232,16 @@ typedef struct tagBITMAPINFOHEADER {
#include "external/dr_mp3.h" // MP3 loading functions #include "external/dr_mp3.h" // MP3 loading functions
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FLAC)
#define DRFLAC_MALLOC RL_MALLOC
#define DRFLAC_REALLOC RL_REALLOC
#define DRFLAC_FREE RL_FREE
#define DR_FLAC_IMPLEMENTATION
#define DR_FLAC_NO_WIN32_IO
#include "external/dr_flac.h" // FLAC loading functions
#endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
#undef bool #undef bool
#endif #endif
@ -225,11 +249,22 @@ typedef struct tagBITMAPINFOHEADER {
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#define AUDIO_DEVICE_FORMAT ma_format_f32 #ifndef AUDIO_DEVICE_FORMAT
#define AUDIO_DEVICE_CHANNELS 2 #define AUDIO_DEVICE_FORMAT ma_format_f32 // Device output format (float-32bit)
#define AUDIO_DEVICE_SAMPLE_RATE 44100 #endif
#ifndef AUDIO_DEVICE_CHANNELS
#define AUDIO_DEVICE_CHANNELS 2 // Device output channels: stereo
#endif
#ifndef AUDIO_DEVICE_SAMPLE_RATE
#define AUDIO_DEVICE_SAMPLE_RATE 44100 // Device output sample rate
#endif
#ifndef MAX_AUDIO_BUFFER_POOL_CHANNELS
#define MAX_AUDIO_BUFFER_POOL_CHANNELS 16 // Audio pool channels
#endif
#ifndef DEFAULT_AUDIO_BUFFER_SIZE
#define DEFAULT_AUDIO_BUFFER_SIZE 4096 // Default audio buffer size
#endif
#define MAX_AUDIO_BUFFER_POOL_CHANNELS 16
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
@ -321,7 +356,7 @@ static AudioData AUDIO = { // Global AUDIO context
// After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds and a // After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds and a
// standard double-buffering system, a 4096 samples buffer has been chosen, it should be enough // standard double-buffering system, a 4096 samples buffer has been chosen, it should be enough
// In case of music-stalls, just increase this number // In case of music-stalls, just increase this number
.Buffer.defaultSize = 4096 .Buffer.defaultSize = DEFAULT_AUDIO_BUFFER_SIZE
}; };
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -349,8 +384,10 @@ static Wave LoadMP3(const char *fileName); // Load MP3 file
#endif #endif
#if defined(RAUDIO_STANDALONE) #if defined(RAUDIO_STANDALONE)
bool IsFileExtension(const char *fileName, const char *ext);// Check file extension static bool IsFileExtension(const char *fileName, const char *ext); // Check file extension
void TraceLog(int msgType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) static unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead); // Load file data as byte array (read)
static void SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite); // Save data to file from byte array (write)
static void SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated
#endif #endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -393,14 +430,14 @@ void InitAudioDevice(void)
// NOTE: Using the default device. Format is floating point because it simplifies mixing. // NOTE: Using the default device. Format is floating point because it simplifies mixing.
ma_device_config config = ma_device_config_init(ma_device_type_playback); ma_device_config config = ma_device_config_init(ma_device_type_playback);
config.playback.pDeviceID = NULL; // NULL for the default playback AUDIO.System.device. config.playback.pDeviceID = NULL; // NULL for the default playback AUDIO.System.device.
config.playback.format = AUDIO_DEVICE_FORMAT; config.playback.format = AUDIO_DEVICE_FORMAT;
config.playback.channels = AUDIO_DEVICE_CHANNELS; config.playback.channels = AUDIO_DEVICE_CHANNELS;
config.capture.pDeviceID = NULL; // NULL for the default capture AUDIO.System.device. config.capture.pDeviceID = NULL; // NULL for the default capture AUDIO.System.device.
config.capture.format = ma_format_s16; config.capture.format = ma_format_s16;
config.capture.channels = 1; config.capture.channels = 1;
config.sampleRate = AUDIO_DEVICE_SAMPLE_RATE; config.sampleRate = AUDIO_DEVICE_SAMPLE_RATE;
config.dataCallback = OnSendAudioDataToDevice; config.dataCallback = OnSendAudioDataToDevice;
config.pUserData = NULL; config.pUserData = NULL;
result = ma_device_init(&AUDIO.System.context, &config, &AUDIO.System.device); result = ma_device_init(&AUDIO.System.context, &config, &AUDIO.System.device);
if (result != MA_SUCCESS) if (result != MA_SUCCESS)
@ -423,7 +460,7 @@ void InitAudioDevice(void)
// Mixing happens on a seperate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may // Mixing happens on a seperate thread which means we need to synchronize. I'm using a mutex here to make things simple, but may
// want to look at something a bit smarter later on to keep everything real-time, if that's necessary. // want to look at something a bit smarter later on to keep everything real-time, if that's necessary.
if (ma_mutex_init(&AUDIO.System.context, &AUDIO.System.lock) != MA_SUCCESS) if (ma_mutex_init(&AUDIO.System.lock) != MA_SUCCESS)
{ {
TRACELOG(LOG_ERROR, "AUDIO: Failed to create mutex for mixing"); TRACELOG(LOG_ERROR, "AUDIO: Failed to create mutex for mixing");
ma_device_uninit(&AUDIO.System.device); ma_device_uninit(&AUDIO.System.device);
@ -432,11 +469,11 @@ void InitAudioDevice(void)
} }
TRACELOG(LOG_INFO, "AUDIO: Device initialized successfully"); TRACELOG(LOG_INFO, "AUDIO: Device initialized successfully");
TRACELOG(LOG_INFO, " > Backend: miniaudio / %s", ma_get_backend_name(AUDIO.System.context.backend)); TRACELOG(LOG_INFO, " > Backend: miniaudio / %s", ma_get_backend_name(AUDIO.System.context.backend));
TRACELOG(LOG_INFO, " > Format: %s -> %s", ma_get_format_name(AUDIO.System.device.playback.format), ma_get_format_name(AUDIO.System.device.playback.internalFormat)); TRACELOG(LOG_INFO, " > Format: %s -> %s", ma_get_format_name(AUDIO.System.device.playback.format), ma_get_format_name(AUDIO.System.device.playback.internalFormat));
TRACELOG(LOG_INFO, " > Channels: %d -> %d", AUDIO.System.device.playback.channels, AUDIO.System.device.playback.internalChannels); TRACELOG(LOG_INFO, " > Channels: %d -> %d", AUDIO.System.device.playback.channels, AUDIO.System.device.playback.internalChannels);
TRACELOG(LOG_INFO, " > Sample rate: %d -> %d", AUDIO.System.device.sampleRate, AUDIO.System.device.playback.internalSampleRate); TRACELOG(LOG_INFO, " > Sample rate: %d -> %d", AUDIO.System.device.sampleRate, AUDIO.System.device.playback.internalSampleRate);
TRACELOG(LOG_INFO, " > Periods size: %d", AUDIO.System.device.playback.internalPeriodSizeInFrames*AUDIO.System.device.playback.internalPeriods); TRACELOG(LOG_INFO, " > Periods size: %d", AUDIO.System.device.playback.internalPeriodSizeInFrames*AUDIO.System.device.playback.internalPeriods);
InitAudioBufferPool(); InitAudioBufferPool();
@ -486,7 +523,7 @@ AudioBuffer *LoadAudioBuffer(ma_format format, ma_uint32 channels, ma_uint32 sam
return NULL; return NULL;
} }
audioBuffer->data = RL_CALLOC(sizeInFrames*channels*ma_get_bytes_per_sample(format), 1); if (sizeInFrames > 0) audioBuffer->data = RL_CALLOC(sizeInFrames*channels*ma_get_bytes_per_sample(format), 1);
// Audio data runs through a format converter // Audio data runs through a format converter
ma_data_converter_config converterConfig = ma_data_converter_config_init(format, AUDIO_DEVICE_FORMAT, channels, AUDIO_DEVICE_CHANNELS, sampleRate, AUDIO_DEVICE_SAMPLE_RATE); ma_data_converter_config converterConfig = ma_data_converter_config_init(format, AUDIO_DEVICE_FORMAT, channels, AUDIO_DEVICE_CHANNELS, sampleRate, AUDIO_DEVICE_SAMPLE_RATE);
@ -775,47 +812,52 @@ void ExportWave(Wave wave, const char *fileName)
// Export wave sample data to code (.h) // Export wave sample data to code (.h)
void ExportWaveAsCode(Wave wave, const char *fileName) void ExportWaveAsCode(Wave wave, const char *fileName)
{ {
#define BYTES_TEXT_PER_LINE 20 #ifndef TEXT_BYTES_PER_LINE
#define TEXT_BYTES_PER_LINE 20
char varFileName[256] = { 0 };
int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
FILE *txtFile = fopen(fileName, "wt");
if (txtFile != NULL)
{
fprintf(txtFile, "\n//////////////////////////////////////////////////////////////////////////////////\n");
fprintf(txtFile, "// //\n");
fprintf(txtFile, "// WaveAsCode exporter v1.0 - Wave data exported as an array of bytes //\n");
fprintf(txtFile, "// //\n");
fprintf(txtFile, "// more info and bugs-report: github.com/raysan5/raylib //\n");
fprintf(txtFile, "// feedback and support: ray[at]raylib.com //\n");
fprintf(txtFile, "// //\n");
fprintf(txtFile, "// Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n");
fprintf(txtFile, "// //\n");
fprintf(txtFile, "//////////////////////////////////////////////////////////////////////////////////\n\n");
#if !defined(RAUDIO_STANDALONE)
// Get file name from path and convert variable name to uppercase
strcpy(varFileName, GetFileNameWithoutExt(fileName));
for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; }
#else
strcpy(varFileName, fileName);
#endif #endif
fprintf(txtFile, "// Wave data information\n"); int waveDataSize = wave.sampleCount*wave.channels*wave.sampleSize/8;
fprintf(txtFile, "#define %s_SAMPLE_COUNT %u\n", varFileName, wave.sampleCount);
fprintf(txtFile, "#define %s_SAMPLE_RATE %u\n", varFileName, wave.sampleRate);
fprintf(txtFile, "#define %s_SAMPLE_SIZE %u\n", varFileName, wave.sampleSize);
fprintf(txtFile, "#define %s_CHANNELS %u\n\n", varFileName, wave.channels);
// Write byte data as hexadecimal text // NOTE: Text data buffer size is estimated considering wave data size in bytes
fprintf(txtFile, "static unsigned char %s_DATA[%i] = { ", varFileName, dataSize); // and requiring 6 char bytes for every byte: "0x00, "
for (int i = 0; i < dataSize - 1; i++) fprintf(txtFile, ((i%BYTES_TEXT_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]); char *txtData = (char *)RL_CALLOC(6*waveDataSize + 2000, sizeof(char));
fprintf(txtFile, "0x%x };\n", ((unsigned char *)wave.data)[dataSize - 1]);
fclose(txtFile); int bytesCount = 0;
} bytesCount += sprintf(txtData + bytesCount, "\n//////////////////////////////////////////////////////////////////////////////////\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "// WaveAsCode exporter v1.0 - Wave data exported as an array of bytes //\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "// more info and bugs-report: github.com/raysan5/raylib //\n");
bytesCount += sprintf(txtData + bytesCount, "// feedback and support: ray[at]raylib.com //\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "// Copyright (c) 2018 Ramon Santamaria (@raysan5) //\n");
bytesCount += sprintf(txtData + bytesCount, "// //\n");
bytesCount += sprintf(txtData + bytesCount, "//////////////////////////////////////////////////////////////////////////////////\n\n");
char varFileName[256] = { 0 };
#if !defined(RAUDIO_STANDALONE)
// Get file name from path and convert variable name to uppercase
strcpy(varFileName, GetFileNameWithoutExt(fileName));
for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; }
#else
strcpy(varFileName, fileName);
#endif
bytesCount += sprintf(txtData + bytesCount, "// Wave data information\n");
bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_COUNT %u\n", varFileName, wave.sampleCount);
bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_RATE %u\n", varFileName, wave.sampleRate);
bytesCount += sprintf(txtData + bytesCount, "#define %s_SAMPLE_SIZE %u\n", varFileName, wave.sampleSize);
bytesCount += sprintf(txtData + bytesCount, "#define %s_CHANNELS %u\n\n", varFileName, wave.channels);
// Write byte data as hexadecimal text
bytesCount += sprintf(txtData + bytesCount, "static unsigned char %s_DATA[%i] = { ", varFileName, waveDataSize);
for (int i = 0; i < waveDataSize - 1; i++) bytesCount += sprintf(txtData + bytesCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), ((unsigned char *)wave.data)[i]);
bytesCount += sprintf(txtData + bytesCount, "0x%x };\n", ((unsigned char *)wave.data)[waveDataSize - 1]);
// NOTE: Text data length exported is determined by '\0' (NULL) character
SaveFileText(fileName, txtData);
RL_FREE(txtData);
} }
// Play a sound // Play a sound
@ -1041,6 +1083,27 @@ Music LoadMusicStream(const char *fileName)
bool musicLoaded = false; bool musicLoaded = false;
if (false) { } if (false) { }
#if defined(SUPPORT_FILEFORMAT_WAV)
else if (IsFileExtension(fileName, ".wav"))
{
drwav *ctxWav = RL_MALLOC(sizeof(drwav));
bool success = drwav_init_file(ctxWav, fileName, NULL);
if (success)
{
music.ctxType = MUSIC_AUDIO_WAV;
music.ctxData = ctxWav;
int sampleSize = ctxWav->bitsPerSample;
if (ctxWav->bitsPerSample == 24) sampleSize = 16; // Forcing conversion to s16 on UpdateMusicStream()
music.stream = InitAudioStream(ctxWav->sampleRate, sampleSize, ctxWav->channels);
music.sampleCount = (unsigned int)ctxWav->totalPCMFrameCount*ctxWav->channels;
music.looping = true; // Looping enabled by default
musicLoaded = true;
}
}
#endif
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
else if (IsFileExtension(fileName, ".ogg")) else if (IsFileExtension(fileName, ".ogg"))
{ {
@ -1055,7 +1118,7 @@ Music LoadMusicStream(const char *fileName)
// OGG bit rate defaults to 16 bit, it's enough for compressed format // OGG bit rate defaults to 16 bit, it's enough for compressed format
music.stream = InitAudioStream(info.sample_rate, 16, info.channels); music.stream = InitAudioStream(info.sample_rate, 16, info.channels);
music.sampleCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData)*info.channels; music.sampleCount = (unsigned int)stb_vorbis_stream_length_in_samples((stb_vorbis *)music.ctxData)*info.channels;
music.loopCount = 0; // Infinite loop by default music.looping = true; // Looping enabled by default
musicLoaded = true; musicLoaded = true;
} }
} }
@ -1072,7 +1135,7 @@ Music LoadMusicStream(const char *fileName)
music.stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels); music.stream = InitAudioStream(ctxFlac->sampleRate, ctxFlac->bitsPerSample, ctxFlac->channels);
music.sampleCount = (unsigned int)ctxFlac->totalSampleCount; music.sampleCount = (unsigned int)ctxFlac->totalSampleCount;
music.loopCount = 0; // Infinite loop by default music.looping = true; // Looping enabled by default
musicLoaded = true; musicLoaded = true;
} }
} }
@ -1091,7 +1154,7 @@ Music LoadMusicStream(const char *fileName)
music.stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels); music.stream = InitAudioStream(ctxMp3->sampleRate, 32, ctxMp3->channels);
music.sampleCount = (unsigned int)drmp3_get_pcm_frame_count(ctxMp3)*ctxMp3->channels; music.sampleCount = (unsigned int)drmp3_get_pcm_frame_count(ctxMp3)*ctxMp3->channels;
music.loopCount = 0; // Infinite loop by default music.looping = true; // Looping enabled by default
musicLoaded = true; musicLoaded = true;
} }
} }
@ -1111,7 +1174,7 @@ Music LoadMusicStream(const char *fileName)
// NOTE: Only stereo is supported for XM // NOTE: Only stereo is supported for XM
music.stream = InitAudioStream(48000, 16, 2); music.stream = InitAudioStream(48000, 16, 2);
music.sampleCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm)*2; music.sampleCount = (unsigned int)jar_xm_get_remaining_samples(ctxXm)*2;
music.loopCount = 0; // Infinite loop by default music.looping = true; // Looping enabled by default
jar_xm_reset(ctxXm); // make sure we start at the beginning of the song jar_xm_reset(ctxXm); // make sure we start at the beginning of the song
musicLoaded = true; musicLoaded = true;
@ -1134,17 +1197,21 @@ Music LoadMusicStream(const char *fileName)
// NOTE: Only stereo is supported for MOD // NOTE: Only stereo is supported for MOD
music.stream = InitAudioStream(48000, 16, 2); music.stream = InitAudioStream(48000, 16, 2);
music.sampleCount = (unsigned int)jar_mod_max_samples(ctxMod)*2; music.sampleCount = (unsigned int)jar_mod_max_samples(ctxMod)*2;
music.loopCount = 0; // Infinite loop by default music.looping = true; // Looping enabled by default
musicLoaded = true; musicLoaded = true;
music.ctxData = ctxMod; music.ctxData = ctxMod;
} }
} }
#endif #endif
else TRACELOG(LOG_WARNING, "STREAM: [%s] Fileformat not supported", fileName);
if (!musicLoaded) if (!musicLoaded)
{ {
if (false) { } if (false) { }
#if defined(SUPPORT_FILEFORMAT_WAV)
else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData);
#endif
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData); else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
#endif #endif
@ -1182,6 +1249,9 @@ void UnloadMusicStream(Music music)
CloseAudioStream(music.stream); CloseAudioStream(music.stream);
if (false) { } if (false) { }
#if defined(SUPPORT_FILEFORMAT_WAV)
else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData);
#endif
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData); else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData);
#endif #endif
@ -1233,6 +1303,9 @@ void StopMusicStream(Music music)
switch (music.ctxType) switch (music.ctxType)
{ {
#if defined(SUPPORT_FILEFORMAT_WAV)
case MUSIC_AUDIO_WAV: drwav_seek_to_pcm_frame((drwav *)music.ctxData, 0); break;
#endif
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break; case MUSIC_AUDIO_OGG: stb_vorbis_seek_start((stb_vorbis *)music.ctxData); break;
#endif #endif
@ -1277,6 +1350,15 @@ void UpdateMusicStream(Music music)
switch (music.ctxType) switch (music.ctxType)
{ {
#if defined(SUPPORT_FILEFORMAT_WAV)
case MUSIC_AUDIO_WAV:
{
// NOTE: Returns the number of samples to process (not required)
if (music.stream.sampleSize == 16) drwav_read_pcm_frames_s16((drwav *)music.ctxData, samplesCount/music.stream.channels, (short *)pcm);
else if (music.stream.sampleSize == 32) drwav_read_pcm_frames_f32((drwav *)music.ctxData, samplesCount/music.stream.channels, (float *)pcm);
} break;
#endif
#if defined(SUPPORT_FILEFORMAT_OGG) #if defined(SUPPORT_FILEFORMAT_OGG)
case MUSIC_AUDIO_OGG: case MUSIC_AUDIO_OGG:
{ {
@ -1340,15 +1422,8 @@ void UpdateMusicStream(Music music)
// Reset audio stream for looping // Reset audio stream for looping
if (streamEnding) if (streamEnding)
{ {
StopMusicStream(music); // Stop music (and reset) StopMusicStream(music); // Stop music (and reset)
if (music.looping) PlayMusicStream(music); // Play again
// Decrease loopCount to stop when required
if (music.loopCount > 1)
{
music.loopCount--; // Decrease loop count
PlayMusicStream(music); // Play again
}
else if (music.loopCount == 0) PlayMusicStream(music);
} }
else else
{ {
@ -1376,13 +1451,6 @@ void SetMusicPitch(Music music, float pitch)
SetAudioStreamPitch(music.stream, pitch); SetAudioStreamPitch(music.stream, pitch);
} }
// Set music loop count (loop repeats)
// NOTE: If set to 0, means infinite loop
void SetMusicLoopCount(Music music, int count)
{
music.loopCount = count;
}
// Get music time length (in seconds) // Get music time length (in seconds)
float GetMusicTimeLength(Music music) float GetMusicTimeLength(Music music)
{ {
@ -1663,7 +1731,7 @@ static ma_uint32 ReadAudioBufferFramesInMixingFormat(AudioBuffer *audioBuffer, f
// detail to remember here is that we never, ever attempt to read more input data than is required for the specified number of output // detail to remember here is that we never, ever attempt to read more input data than is required for the specified number of output
// frames. This can be achieved with ma_data_converter_get_required_input_frame_count(). // frames. This can be achieved with ma_data_converter_get_required_input_frame_count().
ma_uint8 inputBuffer[4096]; ma_uint8 inputBuffer[4096];
ma_uint32 inputBufferFrameCap = sizeof(inputBuffer) / ma_get_bytes_per_frame(audioBuffer->converter.config.formatIn, audioBuffer->converter.config.channelsIn); ma_uint32 inputBufferFrameCap = sizeof(inputBuffer)/ma_get_bytes_per_frame(audioBuffer->converter.config.formatIn, audioBuffer->converter.config.channelsIn);
ma_uint32 totalOutputFramesProcessed = 0; ma_uint32 totalOutputFramesProcessed = 0;
while (totalOutputFramesProcessed < frameCount) while (totalOutputFramesProcessed < frameCount)
@ -1806,6 +1874,7 @@ static void InitAudioBufferPool(void)
// Dummy buffers // Dummy buffers
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++)
{ {
// WARNING: An empty audioBuffer is created (data = 0)
AUDIO.MultiChannel.pool[i] = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO_DEVICE_SAMPLE_RATE, 0, AUDIO_BUFFER_USAGE_STATIC); AUDIO.MultiChannel.pool[i] = LoadAudioBuffer(AUDIO_DEVICE_FORMAT, AUDIO_DEVICE_CHANNELS, AUDIO_DEVICE_SAMPLE_RATE, 0, AUDIO_BUFFER_USAGE_STATIC);
} }
@ -1816,133 +1885,36 @@ static void InitAudioBufferPool(void)
// Close the audio buffers pool // Close the audio buffers pool
static void CloseAudioBufferPool(void) static void CloseAudioBufferPool(void)
{ {
for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) for (int i = 0; i < MAX_AUDIO_BUFFER_POOL_CHANNELS; i++) RL_FREE(AUDIO.MultiChannel.pool[i]);
{
RL_FREE(AUDIO.MultiChannel.pool[i]->data);
RL_FREE(AUDIO.MultiChannel.pool[i]);
}
} }
#if defined(SUPPORT_FILEFORMAT_WAV) #if defined(SUPPORT_FILEFORMAT_WAV)
// Load WAV file into Wave structure // Load WAV file into Wave structure
static Wave LoadWAV(const char *fileName) static Wave LoadWAV(const char *fileName)
{ {
// Basic WAV headers structs
typedef struct {
char chunkID[4];
int chunkSize;
char format[4];
} WAVRiffHeader;
typedef struct {
char subChunkID[4];
int subChunkSize;
short audioFormat;
short numChannels;
int sampleRate;
int byteRate;
short blockAlign;
short bitsPerSample;
} WAVFormat;
typedef struct {
char subChunkID[4];
int subChunkSize;
} WAVData;
WAVRiffHeader wavRiffHeader = { 0 };
WAVFormat wavFormat = { 0 };
WAVData wavData = { 0 };
Wave wave = { 0 }; Wave wave = { 0 };
FILE *wavFile = NULL;
wavFile = fopen(fileName, "rb"); // Loading WAV from memory to avoid FILE accesses
unsigned int fileSize = 0;
if (wavFile == NULL) 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.sampleCount = wav.totalPCMFrameCount*wav.channels;
wave.data = NULL; wave.sampleRate = wav.sampleRate;
} wave.sampleSize = 16; // NOTE: We are forcing conversion to 16bit
else wave.channels = wav.channels;
{ wave.data = (short *)RL_MALLOC(wave.sampleCount*sizeof(short));
// Read in the first chunk into the struct drwav_read_pcm_frames_s16(&wav, wav.totalPCMFrameCount, wave.data);
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);
} }
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load WAV data", fileName);
drwav_uninit(&wav);
RL_FREE(fileData);
return wave; return wave;
} }
@ -1950,81 +1922,24 @@ static Wave LoadWAV(const char *fileName)
// Save wave data as WAV file // Save wave data as WAV file
static int SaveWAV(Wave wave, const char *fileName) static int SaveWAV(Wave wave, const char *fileName)
{ {
int success = 0; drwav wav = { 0 };
int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8; drwav_data_format format = { 0 };
format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64.
// Basic WAV headers structs format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes.
typedef struct { format.channels = wave.channels;
char chunkID[4]; format.sampleRate = wave.sampleRate;
int chunkSize; format.bitsPerSample = wave.sampleSize;
char format[4];
} RiffHeader; drwav_init_file_write(&wav, fileName, &format, NULL);
//drwav_init_memory_write(&wav, &fileData, &fileDataSize, &format, NULL); // TODO: Memory version
typedef struct { drwav_write_pcm_frames(&wav, wave.sampleCount/wave.channels, wave.data);
char subChunkID[4];
int subChunkSize; drwav_uninit(&wav);
short audioFormat;
short numChannels; // SaveFileData(fileName, fileData, fileDataSize);
int sampleRate; //drwav_free(fileData, NULL);
int byteRate;
short blockAlign; return true;
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;
} }
#endif #endif
@ -2035,7 +1950,11 @@ static Wave LoadOGG(const char *fileName)
{ {
Wave wave = { 0 }; Wave wave = { 0 };
stb_vorbis *oggFile = stb_vorbis_open_filename(fileName, NULL, NULL); // Loading OGG from memory to avoid FILE accesses
unsigned int fileSize = 0;
unsigned char *fileData = LoadFileData(fileName, &fileSize);
stb_vorbis *oggFile = stb_vorbis_open_memory(fileData, fileSize, NULL, NULL);
if (oggFile == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open OGG file", fileName); if (oggFile == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open OGG file", fileName);
else else
@ -2058,6 +1977,8 @@ static Wave LoadOGG(const char *fileName)
stb_vorbis_close(oggFile); stb_vorbis_close(oggFile);
} }
RL_FREE(fileData);
return wave; return wave;
} }
@ -2069,10 +1990,14 @@ static Wave LoadOGG(const char *fileName)
static Wave LoadFLAC(const char *fileName) static Wave LoadFLAC(const char *fileName)
{ {
Wave wave = { 0 }; Wave wave = { 0 };
// Loading FLAC from memory to avoid FILE accesses
unsigned int fileSize = 0;
unsigned char *fileData = LoadFileData(fileName, &fileSize);
// Decode an entire FLAC file in one go // Decode an entire FLAC file in one go
unsigned long long int totalSampleCount = 0; unsigned long long int totalSampleCount = 0;
wave.data = drflac_open_file_and_read_pcm_frames_s16(fileName, &wave.channels, &wave.sampleRate, &totalSampleCount); wave.data = drflac_open_memory_and_read_pcm_frames_s16(fileData, fileSize, &wave.channels, &wave.sampleRate, &totalSampleCount);
if (wave.data == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load FLAC data", fileName); if (wave.data == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load FLAC data", fileName);
else else
@ -2080,11 +2005,10 @@ static Wave LoadFLAC(const char *fileName)
wave.sampleCount = (unsigned int)totalSampleCount; wave.sampleCount = (unsigned int)totalSampleCount;
wave.sampleSize = 16; wave.sampleSize = 16;
// NOTE: Only support up to 2 channels (mono, stereo)
if (wave.channels > 2) TRACELOG(LOG_WARNING, "WAVE: [%s] FLAC channels number (%i) not supported", fileName, wave.channels);
TRACELOG(LOG_INFO, "WAVE: [%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo"); TRACELOG(LOG_INFO, "WAVE: [%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
} }
RL_FREE(fileData);
return wave; return wave;
} }
@ -2097,10 +2021,14 @@ static Wave LoadMP3(const char *fileName)
{ {
Wave wave = { 0 }; Wave wave = { 0 };
// Loading MP3 from memory to avoid FILE accesses
unsigned int fileSize = 0;
unsigned char *fileData = LoadFileData(fileName, &fileSize);
// Decode an entire MP3 file in one go // Decode an entire MP3 file in one go
unsigned long int totalFrameCount = 0; unsigned long long int totalFrameCount = 0;
drmp3_config config = { 0 }; drmp3_config config = { 0 };
wave.data = drmp3_open_file_and_read_f32(fileName, &config, &totalFrameCount); wave.data = drmp3_open_memory_and_read_f32(fileData, fileSize, &config, &totalFrameCount);
if (wave.data == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load MP3 data", fileName); if (wave.data == NULL) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to load MP3 data", fileName);
else else
@ -2116,6 +2044,8 @@ static Wave LoadMP3(const char *fileName)
TRACELOG(LOG_INFO, "WAVE: [%s] MP3 file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo"); TRACELOG(LOG_INFO, "WAVE: [%s] MP3 file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1)? "Mono" : "Stereo");
} }
RL_FREE(fileData);
return wave; return wave;
} }
#endif #endif
@ -2123,7 +2053,7 @@ static Wave LoadMP3(const char *fileName)
// Some required functions for audio standalone module version // Some required functions for audio standalone module version
#if defined(RAUDIO_STANDALONE) #if defined(RAUDIO_STANDALONE)
// Check file extension // Check file extension
bool IsFileExtension(const char *fileName, const char *ext) static bool IsFileExtension(const char *fileName, const char *ext)
{ {
bool result = false; bool result = false;
const char *fileExt; const char *fileExt;
@ -2135,6 +2065,89 @@ bool IsFileExtension(const char *fileName, const char *ext)
return result; return result;
} }
// Load data from file into a buffer
static unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead)
{
unsigned char *data = NULL;
*bytesRead = 0;
if (fileName != NULL)
{
FILE *file = fopen(fileName, "rb");
if (file != NULL)
{
// WARNING: On binary streams SEEK_END could not be found,
// using fseek() and ftell() could not work in some (rare) cases
fseek(file, 0, SEEK_END);
int size = ftell(file);
fseek(file, 0, SEEK_SET);
if (size > 0)
{
data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char));
// NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements]
unsigned int count = (unsigned int)fread(data, sizeof(unsigned char), size, file);
*bytesRead = count;
if (count != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded", fileName);
else TRACELOG(LOG_INFO, "FILEIO: [%s] File loaded successfully", fileName);
}
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read file", fileName);
fclose(file);
}
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
}
else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
return data;
}
// Save data to file from buffer
static void SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite)
{
if (fileName != NULL)
{
FILE *file = fopen(fileName, "wb");
if (file != NULL)
{
unsigned int count = (unsigned int)fwrite(data, sizeof(unsigned char), bytesToWrite, file);
if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write file", fileName);
else if (count != bytesToWrite) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName);
else TRACELOG(LOG_INFO, "FILEIO: [%s] File saved successfully", fileName);
fclose(file);
}
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName);
}
else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
}
// Save text data to file (write), string must be '\0' terminated
static void SaveFileText(const char *fileName, char *text)
{
if (fileName != NULL)
{
FILE *file = fopen(fileName, "wt");
if (file != NULL)
{
int count = fprintf(file, "%s", text);
if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write text file", fileName);
else TRACELOG(LOG_INFO, "FILEIO: [%s] Text file saved successfully", fileName);
fclose(file);
}
else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName);
}
else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid");
}
#endif #endif
#undef AudioBuffer #undef AudioBuffer

View file

@ -255,14 +255,6 @@ func SetMusicPitch(music Music, pitch float32) {
C.SetMusicPitch(cmusic, cpitch) C.SetMusicPitch(cmusic, cpitch)
} }
// SetMusicLoopCount - Set music loop count (loop repeats)
// NOTE: If set to -1, means infinite loop
func SetMusicLoopCount(music Music, count int32) {
cmusic := *(*C.Music)(unsafe.Pointer(&music))
ccount := (C.int)(count)
C.SetMusicLoopCount(cmusic, ccount)
}
// GetMusicTimeLength - Get music time length (in seconds) // GetMusicTimeLength - Get music time length (in seconds)
func GetMusicTimeLength(music Music) float32 { func GetMusicTimeLength(music Music) float32 {
cmusic := *(*C.Music)(unsafe.Pointer(&music)) cmusic := *(*C.Music)(unsafe.Pointer(&music))

View file

@ -111,8 +111,8 @@ typedef struct Music {
int ctxType; // Type of music context (audio filetype) int ctxType; // Type of music context (audio filetype)
void *ctxData; // Audio context data, depends on type void *ctxData; // Audio context data, depends on type
bool looping; // Music looping enable
unsigned int sampleCount; // Total number of samples unsigned int sampleCount; // Total number of samples
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
AudioStream stream; // Audio stream AudioStream stream; // Audio stream
} Music; } Music;
@ -173,7 +173,6 @@ void ResumeMusicStream(Music music); // Resume playin
bool IsMusicPlaying(Music music); // Check if music is playing bool IsMusicPlaying(Music music); // Check if music is playing
void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
void SetMusicLoopCount(Music music, int count); // Set music loop count (loop repeats)
float GetMusicTimeLength(Music music); // Get music time length (in seconds) float GetMusicTimeLength(Music music); // Get music time length (in seconds)
float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)

View file

@ -35,6 +35,11 @@ Example:
*/ */
package rl package rl
/*
#include "raylib.h"
#include <stdlib.h>
*/
import "C"
import ( import (
"image" "image"
"io" "io"
@ -108,7 +113,7 @@ type AudioStream struct {
// Number of channels (1-mono, 2-stereo) // Number of channels (1-mono, 2-stereo)
Channels uint32 Channels uint32
// Buffer // Buffer
Buffer *_Ctype_struct_rAudioBuffer Buffer *C.rAudioBuffer
} }
// newAudioStreamFromPointer - Returns new AudioStream from pointer // newAudioStreamFromPointer - Returns new AudioStream from pointer
@ -910,9 +915,12 @@ type BlendMode int32
// Color blending modes (pre-defined) // Color blending modes (pre-defined)
const ( const (
BlendAlpha BlendMode = iota BlendAlpha BlendMode = iota // Blend textures considering alpha (default)
BlendAdditive BlendAdditive // Blend textures adding colors
BlendMultiplied BlendMultiplied // Blend textures multiplying colors
BlendAddColors // Blend textures adding colors (alternative)
BlendSubtractColors // Blend textures subtracting colors (alternative)
BlendCustom // Blend textures using custom src/dst factors (use SetBlendModeCustom())
) )
// Shader type (generic shader) // Shader type (generic shader)
@ -1086,17 +1094,26 @@ func newImageFromPointer(ptr unsafe.Pointer) *Image {
// NewImageFromImage - Returns new Image from Go image.Image // NewImageFromImage - Returns new Image from Go image.Image
func NewImageFromImage(img image.Image) *Image { func NewImageFromImage(img image.Image) *Image {
size := img.Bounds().Size() size := img.Bounds().Size()
pixels := make([]Color, size.X*size.Y)
cx := (C.int)(size.X)
cy := (C.int)(size.Y)
ccolor := White.cptr()
ret := C.GenImageColor(cx, cy, *ccolor)
for y := 0; y < size.Y; y++ { for y := 0; y < size.Y; y++ {
for x := 0; x < size.X; x++ { for x := 0; x < size.X; x++ {
color := img.At(x, y) color := img.At(x, y)
r, g, b, a := color.RGBA() r, g, b, a := color.RGBA()
pixels[x+y*size.X] = NewColor(uint8(r), uint8(g), uint8(b), uint8(a)) rcolor := NewColor(uint8(r), uint8(g), uint8(b), uint8(a))
ccolor = rcolor.cptr()
cx = (C.int)(x)
cy = (C.int)(y)
C.ImageDrawPixel(&ret, cx, cy, *ccolor)
} }
} }
v := newImageFromPointer(unsafe.Pointer(&ret))
return LoadImageEx(pixels, int32(size.X), int32(size.Y)) return v
} }
// Texture2D type, bpp always RGBA (32bit) // Texture2D type, bpp always RGBA (32bit)

View file

@ -99,8 +99,6 @@
#define DEG2RAD (PI/180.0f) #define DEG2RAD (PI/180.0f)
#define RAD2DEG (180.0f/PI) #define RAD2DEG (180.0f/PI)
#define MAX_TOUCH_POINTS 10 // Maximum number of touch points supported
// Allow custom memory allocators // Allow custom memory allocators
#ifndef RL_MALLOC #ifndef RL_MALLOC
#define RL_MALLOC(sz) malloc(sz) #define RL_MALLOC(sz) malloc(sz)
@ -159,6 +157,7 @@
#define SubText TextSubtext #define SubText TextSubtext
#define ShowWindow UnhideWindow #define ShowWindow UnhideWindow
#define LoadText LoadFileText #define LoadText LoadFileText
//#define Fade(c, a) ColorAlpha(c, a)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Structures Definition // Structures Definition
@ -442,8 +441,8 @@ typedef struct Music {
int ctxType; // Type of music context (audio filetype) int ctxType; // Type of music context (audio filetype)
void *ctxData; // Audio context data, depends on type void *ctxData; // Audio context data, depends on type
bool looping; // Music looping enable
unsigned int sampleCount; // Total number of samples unsigned int sampleCount; // Total number of samples
unsigned int loopCount; // Loops count (times music will play), 0 means infinite loop
AudioStream stream; // Audio stream AudioStream stream; // Audio stream
} Music; } Music;
@ -665,20 +664,17 @@ typedef enum {
} GamepadButton; } GamepadButton;
typedef enum { typedef enum {
// This is here just for error checking
GAMEPAD_AXIS_UNKNOWN = 0,
// Left stick // Left stick
GAMEPAD_AXIS_LEFT_X, GAMEPAD_AXIS_LEFT_X = 0,
GAMEPAD_AXIS_LEFT_Y, GAMEPAD_AXIS_LEFT_Y = 1,
// Right stick // Right stick
GAMEPAD_AXIS_RIGHT_X, GAMEPAD_AXIS_RIGHT_X = 2,
GAMEPAD_AXIS_RIGHT_Y, GAMEPAD_AXIS_RIGHT_Y = 3,
// Pressure levels for the back triggers // Pressure levels for the back triggers
GAMEPAD_AXIS_LEFT_TRIGGER, // [1..-1] (pressure-level) GAMEPAD_AXIS_LEFT_TRIGGER = 4, // [1..-1] (pressure-level)
GAMEPAD_AXIS_RIGHT_TRIGGER // [1..-1] (pressure-level) GAMEPAD_AXIS_RIGHT_TRIGGER = 5 // [1..-1] (pressure-level)
} GamepadAxis; } GamepadAxis;
// Shader location point type // Shader location point type
@ -811,7 +807,10 @@ typedef enum {
typedef enum { typedef enum {
BLEND_ALPHA = 0, // Blend textures considering alpha (default) BLEND_ALPHA = 0, // Blend textures considering alpha (default)
BLEND_ADDITIVE, // Blend textures adding colors BLEND_ADDITIVE, // Blend textures adding colors
BLEND_MULTIPLIED // Blend textures multiplying colors BLEND_MULTIPLIED, // Blend textures multiplying colors
BLEND_ADD_COLORS, // Blend textures adding colors (alternative)
BLEND_SUBTRACT_COLORS, // Blend textures subtracting colors (alternative)
BLEND_CUSTOM // Belnd textures using custom src/dst factors (use SetBlendModeCustom())
} BlendMode; } BlendMode;
// Gestures type // Gestures type
@ -873,13 +872,19 @@ RLAPI void InitWindow(int width, int height, const char *title); // Initialize
RLAPI bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed RLAPI bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed
RLAPI void CloseWindow(void); // Close window and unload OpenGL context RLAPI void CloseWindow(void); // Close window and unload OpenGL context
RLAPI bool IsWindowReady(void); // Check if window has been initialized successfully RLAPI bool IsWindowReady(void); // Check if window has been initialized successfully
RLAPI bool IsWindowMinimized(void); // Check if window has been minimized (or lost focus) RLAPI bool IsWindowMinimized(void); // Check if window has been minimized
RLAPI bool IsWindowMaximized(void); // Check if window has been maximized (only PLATFORM_DESKTOP)
RLAPI bool IsWindowFocused(void); // Check if window has been focused
RLAPI bool IsWindowResized(void); // Check if window has been resized RLAPI bool IsWindowResized(void); // Check if window has been resized
RLAPI bool IsWindowHidden(void); // Check if window is currently hidden RLAPI bool IsWindowHidden(void); // Check if window is currently hidden
RLAPI bool IsWindowFullscreen(void); // Check if window is currently fullscreen RLAPI bool IsWindowFullscreen(void); // Check if window is currently fullscreen
RLAPI void ToggleFullscreen(void); // Toggle fullscreen mode (only PLATFORM_DESKTOP) RLAPI void ToggleFullscreen(void); // Toggle fullscreen mode (only PLATFORM_DESKTOP)
RLAPI void UnhideWindow(void); // Show the window RLAPI void UnhideWindow(void); // Show the window
RLAPI void HideWindow(void); // Hide the window RLAPI void HideWindow(void); // Hide the window
RLAPI void DecorateWindow(void); // Decorate the window (only PLATFORM_DESKTOP)
RLAPI void UndecorateWindow(void); // Undecorate the window (only PLATFORM_DESKTOP)
RLAPI void MaximizeWindow(void); // Maximize the window, if resizable (only PLATFORM_DESKTOP)
RLAPI void RestoreWindow(void); // Restore the window, if resizable (only PLATFORM_DESKTOP)
RLAPI void SetWindowIcon(Image image); // Set icon for window (only PLATFORM_DESKTOP) RLAPI void SetWindowIcon(Image image); // Set icon for window (only PLATFORM_DESKTOP)
RLAPI void SetWindowTitle(const char *title); // Set title for window (only PLATFORM_DESKTOP) RLAPI void SetWindowTitle(const char *title); // Set title for window (only PLATFORM_DESKTOP)
RLAPI void SetWindowPosition(int x, int y); // Set window position on screen (only PLATFORM_DESKTOP) RLAPI void SetWindowPosition(int x, int y); // Set window position on screen (only PLATFORM_DESKTOP)
@ -894,7 +899,9 @@ RLAPI int GetMonitorWidth(int monitor); // Get primary
RLAPI int GetMonitorHeight(int monitor); // Get primary monitor height RLAPI int GetMonitorHeight(int monitor); // Get primary monitor height
RLAPI int GetMonitorPhysicalWidth(int monitor); // Get primary monitor physical width in millimetres RLAPI int GetMonitorPhysicalWidth(int monitor); // Get primary monitor physical width in millimetres
RLAPI int GetMonitorPhysicalHeight(int monitor); // Get primary monitor physical height in millimetres RLAPI int GetMonitorPhysicalHeight(int monitor); // Get primary monitor physical height in millimetres
RLAPI int GetMonitorRefreshRate(int monitor); // Get primary monitor refresh rate
RLAPI Vector2 GetWindowPosition(void); // Get window position XY on monitor RLAPI Vector2 GetWindowPosition(void); // Get window position XY on monitor
RLAPI Vector2 GetWindowScaleDPI(void); // Get window scale DPI factor
RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the primary monitor RLAPI const char *GetMonitorName(int monitor); // Get the human-readable, UTF-8 encoded name of the primary monitor
RLAPI const char *GetClipboardText(void); // Get clipboard text content RLAPI const char *GetClipboardText(void); // Get clipboard text content
RLAPI void SetClipboardText(const char *text); // Set clipboard text content RLAPI void SetClipboardText(const char *text); // Set clipboard text content
@ -905,6 +912,7 @@ RLAPI void HideCursor(void); // Hides curso
RLAPI bool IsCursorHidden(void); // Check if cursor is not visible RLAPI bool IsCursorHidden(void); // Check if cursor is not visible
RLAPI void EnableCursor(void); // Enables cursor (unlock cursor) RLAPI void EnableCursor(void); // Enables cursor (unlock cursor)
RLAPI void DisableCursor(void); // Disables cursor (lock cursor) RLAPI void DisableCursor(void); // Disables cursor (lock cursor)
RLAPI bool IsCursorOnScreen(void); // Check if cursor is on the current screen.
// Drawing-related functions // Drawing-related functions
RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color) RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color)
@ -934,15 +942,6 @@ RLAPI int GetFPS(void); // Returns cur
RLAPI float GetFrameTime(void); // Returns time in seconds for last frame drawn RLAPI float GetFrameTime(void); // Returns time in seconds for last frame drawn
RLAPI double GetTime(void); // Returns elapsed time in seconds since InitWindow() RLAPI double GetTime(void); // Returns elapsed time in seconds since InitWindow()
// Color-related functions
RLAPI int ColorToInt(Color color); // Returns hexadecimal value for a Color
RLAPI Vector4 ColorNormalize(Color color); // Returns color normalized as float [0..1]
RLAPI Color ColorFromNormalized(Vector4 normalized); // Returns color from normalized values [0..1]
RLAPI Vector3 ColorToHSV(Color color); // Returns HSV values for a Color
RLAPI Color ColorFromHSV(Vector3 hsv); // Returns a Color from HSV values
RLAPI Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value
RLAPI Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
// Misc. functions // Misc. functions
RLAPI void SetConfigFlags(unsigned int flags); // Setup window configuration flags (view FLAGS) RLAPI void SetConfigFlags(unsigned int flags); // Setup window configuration flags (view FLAGS)
RLAPI void SetTraceLogLevel(int logType); // Set the current threshold (minimum) log level RLAPI void SetTraceLogLevel(int logType); // Set the current threshold (minimum) log level
@ -1105,14 +1104,11 @@ RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Ve
// Image loading functions // Image loading functions
// NOTE: This functions do not require GPU access // NOTE: This functions do not require GPU access
RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM) RLAPI Image LoadImage(const char *fileName); // Load image from file into CPU memory (RAM)
RLAPI Image LoadImageEx(Color *pixels, int width, int height); // Load image from Color array data (RGBA - 32bit)
RLAPI Image LoadImagePro(void *data, int width, int height, int format); // Load image from raw data with parameters
RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data
RLAPI Image LoadImageAnim(const char *fileName, int *frames); // Load image sequence from file (frames appended to image.data)
RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM) RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM)
RLAPI void ExportImage(Image image, const char *fileName); // Export image data to file RLAPI void ExportImage(Image image, const char *fileName); // Export image data to file
RLAPI void ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes RLAPI void ExportImageAsCode(Image image, const char *fileName); // Export image as code file defining an array of bytes
RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array
RLAPI Vector4 *GetImageDataNormalized(Image image); // Get pixel data from image as Vector4 array (float normalized)
// Image generation functions // Image generation functions
RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color
@ -1129,16 +1125,16 @@ RLAPI Image ImageCopy(Image image);
RLAPI Image ImageFromImage(Image image, Rectangle rec); // Create an image from another image piece RLAPI Image ImageFromImage(Image image, Rectangle rec); // Create an image from another image piece
RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font) RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font)
RLAPI Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint); // Create an image from text (custom sprite font) RLAPI Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Color tint); // Create an image from text (custom sprite font)
RLAPI void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two)
RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format
RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image RLAPI void ImageToPOT(Image *image, Color fill); // Convert image to POT (power-of-two)
RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color
RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value
RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel
RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle
RLAPI void ImageAlphaCrop(Image *image, float threshold); // Crop image depending on alpha value
RLAPI void ImageAlphaClear(Image *image, Color color, float threshold); // Clear alpha channel to desired color
RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image
RLAPI void ImageAlphaPremultiply(Image *image); // Premultiply alpha channel
RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (Bicubic scaling algorithm) RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize image (Bicubic scaling algorithm)
RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); // Resize image (Nearest-Neighbor scaling algorithm) RLAPI void ImageResizeNN(Image *image, int newWidth,int newHeight); // Resize image (Nearest-Neighbor scaling algorithm)
RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color color); // Resize canvas and fill with color RLAPI void ImageResizeCanvas(Image *image, int newWidth, int newHeight, int offsetX, int offsetY, Color fill); // Resize canvas and fill with color
RLAPI void ImageMipmaps(Image *image); // Generate all mipmap levels for a provided image RLAPI void ImageMipmaps(Image *image); // Generate all mipmap levels for a provided image
RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering) RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
RLAPI void ImageFlipVertical(Image *image); // Flip image vertically RLAPI void ImageFlipVertical(Image *image); // Flip image vertically
@ -1151,7 +1147,10 @@ RLAPI void ImageColorGrayscale(Image *image);
RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100) RLAPI void ImageColorContrast(Image *image, float contrast); // Modify image color: contrast (-100 to 100)
RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255) RLAPI void ImageColorBrightness(Image *image, int brightness); // Modify image color: brightness (-255 to 255)
RLAPI void ImageColorReplace(Image *image, Color color, Color replace); // Modify image color: replace color RLAPI void ImageColorReplace(Image *image, Color color, Color replace); // Modify image color: replace color
RLAPI Color *ImageExtractPalette(Image image, int maxPaletteSize, int *extractCount); // Extract color palette from image to maximum size (memory should be freed)
RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array
RLAPI Color *GetImagePalette(Image image, int maxPaletteSize, int *extractCount); // Get color palette from image to maximum size (memory should be freed)
RLAPI Vector4 *GetImageDataNormalized(Image image); // Get pixel data from image as Vector4 array (float normalized)
RLAPI Rectangle GetImageAlphaBorder(Image image, float threshold); // Get image alpha border rectangle RLAPI Rectangle GetImageAlphaBorder(Image image, float threshold); // Get image alpha border rectangle
// Image drawing functions // Image drawing functions
@ -1168,8 +1167,8 @@ RLAPI void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color
RLAPI void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color); // Draw rectangle within an image RLAPI void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color); // Draw rectangle within an image
RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color); // Draw rectangle lines within an image RLAPI void ImageDrawRectangleLines(Image *dst, Rectangle rec, int thick, Color color); // Draw rectangle lines within an image
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source) RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Color tint); // Draw a source image within a destination image (tint applied to source)
RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (default font) within an image (destination) RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination)
RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, Font font, const char *text, float fontSize, float spacing, Color color); // Draw text (custom sprite font) within an image (destination) RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination)
// Texture loading functions // Texture loading functions
// NOTE: These functions require GPU access // NOTE: These functions require GPU access
@ -1180,6 +1179,7 @@ RLAPI RenderTexture2D LoadRenderTexture(int width, int height);
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM) RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM) RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM)
RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data
RLAPI void UpdateTextureRec(Texture2D texture, Rectangle rec, const void *pixels); // Update GPU texture rectangle with new data
RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image
RLAPI Image GetScreenData(void); // Get pixel data from screen buffer and return an Image (screenshot) RLAPI Image GetScreenData(void); // Get pixel data from screen buffer and return an Image (screenshot)
@ -1194,11 +1194,23 @@ RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint);
RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters
RLAPI void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle RLAPI void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle
RLAPI void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint); // Draw texture quad with tiling and offset parameters RLAPI void DrawTextureQuad(Texture2D texture, Vector2 tiling, Vector2 offset, Rectangle quad, Color tint); // Draw texture quad with tiling and offset parameters
RLAPI void DrawTextureTiled(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, float scale, Color tint); // Draw part of a texture (defined by a rectangle) with rotation and scale tiled into destRec.
RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters
RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely RLAPI void DrawTextureNPatch(Texture2D texture, NPatchInfo nPatchInfo, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draws a texture (or part of it) that stretches or shrinks nicely
// Image/Texture misc functions // Color/pixel related functions
RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes (image or texture) RLAPI Color Fade(Color color, float alpha); // Returns color with alpha applied, alpha goes from 0.0f to 1.0f
RLAPI int ColorToInt(Color color); // Returns hexadecimal value for a Color
RLAPI Vector4 ColorNormalize(Color color); // Returns Color normalized as float [0..1]
RLAPI Color ColorFromNormalized(Vector4 normalized); // Returns Color from normalized values [0..1]
RLAPI Vector3 ColorToHSV(Color color); // Returns HSV values for a Color
RLAPI Color ColorFromHSV(Vector3 hsv); // Returns a Color from HSV values
RLAPI Color ColorAlpha(Color color, float alpha); // Returns color with alpha applied, alpha goes from 0.0f to 1.0f
RLAPI Color ColorAlphaBlend(Color dst, Color src, Color tint); // Returns src alpha-blended into dst color with tint
RLAPI Color GetColor(int hexValue); // Get Color structure from hexadecimal value
RLAPI Color GetPixelColor(void *srcPtr, int format); // Get Color from a source pixel pointer of certain format
RLAPI void SetPixelColor(void *dstPtr, Color color, int format); // Set color formatted into destination pixel pointer
RLAPI int GetPixelDataSize(int width, int height, int format); // Get pixel data size in bytes for certain format
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Font Loading and Text Drawing Functions (Module: text) // Font Loading and Text Drawing Functions (Module: text)
@ -1260,6 +1272,8 @@ RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength); // Encode
RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space
RLAPI void DrawPoint3D(Vector3 position, Color color); // Draw a point in 3D space, actually a small line RLAPI void DrawPoint3D(Vector3 position, Color color); // Draw a point in 3D space, actually a small line
RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color); // Draw a circle in 3D world space RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color); // Draw a circle in 3D world space
RLAPI void DrawTriangle3D(Vector3 v1, Vector3 v2, Vector3 v3, Color color); // Draw a color-filled triangle (vertex in counter-clockwise order!)
RLAPI void DrawTriangleStrip3D(Vector3 *points, int pointsCount, Color color); // Draw a triangle strip defined by points
RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color); // Draw cube RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color); // Draw cube
RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version) RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version)
RLAPI void DrawCubeWires(Vector3 position, float width, float height, float length, Color color); // Draw cube wires RLAPI void DrawCubeWires(Vector3 position, float width, float height, float length, Color color); // Draw cube wires
@ -1274,7 +1288,6 @@ RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color);
RLAPI void DrawRay(Ray ray, Color color); // Draw a ray line RLAPI void DrawRay(Ray ray, Color color); // Draw a ray line
RLAPI void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0)) RLAPI void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0))
RLAPI void DrawGizmo(Vector3 position); // Draw simple gizmo RLAPI void DrawGizmo(Vector3 position); // Draw simple gizmo
//DrawTorus(), DrawTeapot() could be useful?
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Model 3d Loading and Drawing Functions (Module: models) // Model 3d Loading and Drawing Functions (Module: models)
@ -1319,6 +1332,7 @@ RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
RLAPI BoundingBox MeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits RLAPI BoundingBox MeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits
RLAPI void MeshTangents(Mesh *mesh); // Compute mesh tangents RLAPI void MeshTangents(Mesh *mesh); // Compute mesh tangents
RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals RLAPI void MeshBinormals(Mesh *mesh); // Compute mesh binormals
RLAPI void MeshNormalsSmooth(Mesh *mesh); // Smooth (average) vertex normals
// Model drawing functions // Model drawing functions
RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set) RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set)
@ -1437,7 +1451,6 @@ RLAPI void ResumeMusicStream(Music music); // Resume
RLAPI bool IsMusicPlaying(Music music); // Check if music is playing RLAPI bool IsMusicPlaying(Music music); // Check if music is playing
RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level) RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level) RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
RLAPI void SetMusicLoopCount(Music music, int count); // Set music loop count (loop repeats)
RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds) RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds)
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds) RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)

View file

@ -154,6 +154,18 @@ RMDEF float Lerp(float start, float end, float amount)
return start + amount*(end - start); return start + amount*(end - start);
} }
// Normalize input value within input range
RMDEF float Normalize(float value, float start, float end)
{
return (value - start) / (end - start);
}
// Remap input value within input range to output range
RMDEF float Remap(float value, float inputStart, float inputEnd, float outputStart, float outputEnd)
{
return (value - inputStart) / (inputEnd - inputStart) * (outputEnd - outputStart) + outputStart;
}
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition - Vector2 math // Module Functions Definition - Vector2 math
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -179,6 +191,13 @@ RMDEF Vector2 Vector2Add(Vector2 v1, Vector2 v2)
return result; return result;
} }
// Add vector and float value
RMDEF Vector2 Vector2AddValue(Vector2 v, float add)
{
Vector2 result = { v.x + add, v.y + add };
return result;
}
// Subtract two vectors (v1 - v2) // Subtract two vectors (v1 - v2)
RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2) RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)
{ {
@ -186,6 +205,13 @@ RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)
return result; return result;
} }
// Subtract vector by float value
RMDEF Vector2 Vector2SubtractValue(Vector2 v, float sub)
{
Vector2 result = { v.x - sub, v.y - sub };
return result;
}
// Calculate vector length // Calculate vector length
RMDEF float Vector2Length(Vector2 v) RMDEF float Vector2Length(Vector2 v)
{ {
@ -193,6 +219,13 @@ RMDEF float Vector2Length(Vector2 v)
return result; return result;
} }
// Calculate vector square length
RMDEF float Vector2LengthSqr(Vector2 v)
{
float result = (v.x*v.x) + (v.y*v.y);
return result;
}
// Calculate two vectors dot product // Calculate two vectors dot product
RMDEF float Vector2DotProduct(Vector2 v1, Vector2 v2) RMDEF float Vector2DotProduct(Vector2 v1, Vector2 v2)
{ {
@ -223,7 +256,7 @@ RMDEF Vector2 Vector2Scale(Vector2 v, float scale)
} }
// Multiply vector by vector // Multiply vector by vector
RMDEF Vector2 Vector2MultiplyV(Vector2 v1, Vector2 v2) RMDEF Vector2 Vector2Multiply(Vector2 v1, Vector2 v2)
{ {
Vector2 result = { v1.x*v2.x, v1.y*v2.y }; Vector2 result = { v1.x*v2.x, v1.y*v2.y };
return result; return result;
@ -236,15 +269,8 @@ RMDEF Vector2 Vector2Negate(Vector2 v)
return result; return result;
} }
// Divide vector by a float value
RMDEF Vector2 Vector2Divide(Vector2 v, float div)
{
Vector2 result = { v.x/div, v.y/div };
return result;
}
// Divide vector by vector // Divide vector by vector
RMDEF Vector2 Vector2DivideV(Vector2 v1, Vector2 v2) RMDEF Vector2 Vector2Divide(Vector2 v1, Vector2 v2)
{ {
Vector2 result = { v1.x/v2.x, v1.y/v2.y }; Vector2 result = { v1.x/v2.x, v1.y/v2.y };
return result; return result;
@ -253,7 +279,7 @@ RMDEF Vector2 Vector2DivideV(Vector2 v1, Vector2 v2)
// Normalize provided vector // Normalize provided vector
RMDEF Vector2 Vector2Normalize(Vector2 v) RMDEF Vector2 Vector2Normalize(Vector2 v)
{ {
Vector2 result = Vector2Divide(v, Vector2Length(v)); Vector2 result = Vector2Scale(v, 1/Vector2Length(v));
return result; return result;
} }
@ -276,6 +302,24 @@ RMDEF Vector2 Vector2Rotate(Vector2 v, float degs)
return result; return result;
} }
// Move Vector towards target
RMDEF Vector2 Vector2MoveTowards(Vector2 v, Vector2 target, float maxDistance)
{
Vector2 result = { 0 };
float dx = target.x - v.x;
float dy = target.y - v.y;
float value = (dx*dx) + (dy*dy);
if ((value == 0) || ((maxDistance >= 0) && (value <= maxDistance*maxDistance))) result = target;
float dist = sqrtf(value);
result.x = v.x + dx/dist*maxDistance;
result.y = v.y + dy/dist*maxDistance;
return result;
}
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition - Vector3 math // Module Functions Definition - Vector3 math
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -301,6 +345,13 @@ RMDEF Vector3 Vector3Add(Vector3 v1, Vector3 v2)
return result; return result;
} }
// Add vector and float value
RMDEF Vector3 Vector3AddValue(Vector3 v, float add)
{
Vector3 result = { v.x + add, v.y + add, v.z + add };
return result;
}
// Subtract two vectors // Subtract two vectors
RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2) RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
{ {
@ -308,6 +359,13 @@ RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
return result; return result;
} }
// Subtract vector by float value
RMDEF Vector3 Vector3SubtractValue(Vector3 v, float sub)
{
Vector3 result = { v.x - sub, v.y - sub, v.z - sub };
return result;
}
// Multiply vector by scalar // Multiply vector by scalar
RMDEF Vector3 Vector3Scale(Vector3 v, float scalar) RMDEF Vector3 Vector3Scale(Vector3 v, float scalar)
{ {
@ -362,6 +420,13 @@ RMDEF float Vector3Length(const Vector3 v)
return result; return result;
} }
// Calculate vector square length
RMDEF float Vector3LengthSqr(const Vector3 v)
{
float result = v.x*v.x + v.y*v.y + v.z*v.z;
return result;
}
// Calculate two vectors dot product // Calculate two vectors dot product
RMDEF float Vector3DotProduct(Vector3 v1, Vector3 v2) RMDEF float Vector3DotProduct(Vector3 v1, Vector3 v2)
{ {
@ -386,15 +451,8 @@ RMDEF Vector3 Vector3Negate(Vector3 v)
return result; return result;
} }
// Divide vector by a float value
RMDEF Vector3 Vector3Divide(Vector3 v, float div)
{
Vector3 result = { v.x / div, v.y / div, v.z / div };
return result;
}
// Divide vector by vector // Divide vector by vector
RMDEF Vector3 Vector3DivideV(Vector3 v1, Vector3 v2) RMDEF Vector3 Vector3Divide(Vector3 v1, Vector3 v2)
{ {
Vector3 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z }; Vector3 result = { v1.x/v2.x, v1.y/v2.y, v1.z/v2.z };
return result; return result;
@ -737,6 +795,32 @@ RMDEF Matrix MatrixSubtract(Matrix left, Matrix right)
return result; return result;
} }
// Returns two matrix multiplication
// NOTE: When multiplying matrices... the order matters!
RMDEF Matrix MatrixMultiply(Matrix left, Matrix right)
{
Matrix result = { 0 };
result.m0 = left.m0*right.m0 + left.m1*right.m4 + left.m2*right.m8 + left.m3*right.m12;
result.m1 = left.m0*right.m1 + left.m1*right.m5 + left.m2*right.m9 + left.m3*right.m13;
result.m2 = left.m0*right.m2 + left.m1*right.m6 + left.m2*right.m10 + left.m3*right.m14;
result.m3 = left.m0*right.m3 + left.m1*right.m7 + left.m2*right.m11 + left.m3*right.m15;
result.m4 = left.m4*right.m0 + left.m5*right.m4 + left.m6*right.m8 + left.m7*right.m12;
result.m5 = left.m4*right.m1 + left.m5*right.m5 + left.m6*right.m9 + left.m7*right.m13;
result.m6 = left.m4*right.m2 + left.m5*right.m6 + left.m6*right.m10 + left.m7*right.m14;
result.m7 = left.m4*right.m3 + left.m5*right.m7 + left.m6*right.m11 + left.m7*right.m15;
result.m8 = left.m8*right.m0 + left.m9*right.m4 + left.m10*right.m8 + left.m11*right.m12;
result.m9 = left.m8*right.m1 + left.m9*right.m5 + left.m10*right.m9 + left.m11*right.m13;
result.m10 = left.m8*right.m2 + left.m9*right.m6 + left.m10*right.m10 + left.m11*right.m14;
result.m11 = left.m8*right.m3 + left.m9*right.m7 + left.m10*right.m11 + left.m11*right.m15;
result.m12 = left.m12*right.m0 + left.m13*right.m4 + left.m14*right.m8 + left.m15*right.m12;
result.m13 = left.m12*right.m1 + left.m13*right.m5 + left.m14*right.m9 + left.m15*right.m13;
result.m14 = left.m12*right.m2 + left.m13*right.m6 + left.m14*right.m10 + left.m15*right.m14;
result.m15 = left.m12*right.m3 + left.m13*right.m7 + left.m14*right.m11 + left.m15*right.m15;
return result;
}
// Returns translation matrix // Returns translation matrix
RMDEF Matrix MatrixTranslate(float x, float y, float z) RMDEF Matrix MatrixTranslate(float x, float y, float z)
{ {
@ -793,33 +877,6 @@ RMDEF Matrix MatrixRotate(Vector3 axis, float angle)
return result; return result;
} }
// Returns xyz-rotation matrix (angles in radians)
RMDEF Matrix MatrixRotateXYZ(Vector3 ang)
{
Matrix result = MatrixIdentity();
float cosz = cosf(-ang.z);
float sinz = sinf(-ang.z);
float cosy = cosf(-ang.y);
float siny = sinf(-ang.y);
float cosx = cosf(-ang.x);
float sinx = sinf(-ang.x);
result.m0 = cosz * cosy;
result.m4 = (cosz * siny * sinx) - (sinz * cosx);
result.m8 = (cosz * siny * cosx) + (sinz * sinx);
result.m1 = sinz * cosy;
result.m5 = (sinz * siny * sinx) + (cosz * cosx);
result.m9 = (sinz * siny * cosx) - (cosz * sinx);
result.m2 = -siny;
result.m6 = cosy * sinx;
result.m10= cosy * cosx;
return result;
}
// Returns x-rotation matrix (angle in radians) // Returns x-rotation matrix (angle in radians)
RMDEF Matrix MatrixRotateX(float angle) RMDEF Matrix MatrixRotateX(float angle)
{ {
@ -868,6 +925,46 @@ RMDEF Matrix MatrixRotateZ(float angle)
return result; return result;
} }
// Returns xyz-rotation matrix (angles in radians)
RMDEF Matrix MatrixRotateXYZ(Vector3 ang)
{
Matrix result = MatrixIdentity();
float cosz = cosf(-ang.z);
float sinz = sinf(-ang.z);
float cosy = cosf(-ang.y);
float siny = sinf(-ang.y);
float cosx = cosf(-ang.x);
float sinx = sinf(-ang.x);
result.m0 = cosz * cosy;
result.m4 = (cosz * siny * sinx) - (sinz * cosx);
result.m8 = (cosz * siny * cosx) + (sinz * sinx);
result.m1 = sinz * cosy;
result.m5 = (sinz * siny * sinx) + (cosz * cosx);
result.m9 = (sinz * siny * cosx) - (cosz * sinx);
result.m2 = -siny;
result.m6 = cosy * sinx;
result.m10= cosy * cosx;
return result;
}
// Returns zyx-rotation matrix (angles in radians)
// TODO: This solution is suboptimal, it should be possible to create this matrix in one go
// instead of using a 3 matrix multiplication
RMDEF Matrix MatrixRotateZYX(Vector3 ang)
{
Matrix result = MatrixRotateZ(ang.z);
result = MatrixMultiply(result, MatrixRotateY(ang.y));
result = MatrixMultiply(result, MatrixRotateX(ang.x));
return result;
}
// Returns scaling matrix // Returns scaling matrix
RMDEF Matrix MatrixScale(float x, float y, float z) RMDEF Matrix MatrixScale(float x, float y, float z)
{ {
@ -879,32 +976,6 @@ RMDEF Matrix MatrixScale(float x, float y, float z)
return result; return result;
} }
// Returns two matrix multiplication
// NOTE: When multiplying matrices... the order matters!
RMDEF Matrix MatrixMultiply(Matrix left, Matrix right)
{
Matrix result = { 0 };
result.m0 = left.m0*right.m0 + left.m1*right.m4 + left.m2*right.m8 + left.m3*right.m12;
result.m1 = left.m0*right.m1 + left.m1*right.m5 + left.m2*right.m9 + left.m3*right.m13;
result.m2 = left.m0*right.m2 + left.m1*right.m6 + left.m2*right.m10 + left.m3*right.m14;
result.m3 = left.m0*right.m3 + left.m1*right.m7 + left.m2*right.m11 + left.m3*right.m15;
result.m4 = left.m4*right.m0 + left.m5*right.m4 + left.m6*right.m8 + left.m7*right.m12;
result.m5 = left.m4*right.m1 + left.m5*right.m5 + left.m6*right.m9 + left.m7*right.m13;
result.m6 = left.m4*right.m2 + left.m5*right.m6 + left.m6*right.m10 + left.m7*right.m14;
result.m7 = left.m4*right.m3 + left.m5*right.m7 + left.m6*right.m11 + left.m7*right.m15;
result.m8 = left.m8*right.m0 + left.m9*right.m4 + left.m10*right.m8 + left.m11*right.m12;
result.m9 = left.m8*right.m1 + left.m9*right.m5 + left.m10*right.m9 + left.m11*right.m13;
result.m10 = left.m8*right.m2 + left.m9*right.m6 + left.m10*right.m10 + left.m11*right.m14;
result.m11 = left.m8*right.m3 + left.m9*right.m7 + left.m10*right.m11 + left.m11*right.m15;
result.m12 = left.m12*right.m0 + left.m13*right.m4 + left.m14*right.m8 + left.m15*right.m12;
result.m13 = left.m12*right.m1 + left.m13*right.m5 + left.m14*right.m9 + left.m15*right.m13;
result.m14 = left.m12*right.m2 + left.m13*right.m6 + left.m14*right.m10 + left.m15*right.m14;
result.m15 = left.m12*right.m3 + left.m13*right.m7 + left.m14*right.m11 + left.m15*right.m15;
return result;
}
// Returns perspective projection matrix // Returns perspective projection matrix
RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far) RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far)
{ {
@ -1040,6 +1111,34 @@ RMDEF float16 MatrixToFloatV(Matrix mat)
// Module Functions Definition - Quaternion math // Module Functions Definition - Quaternion math
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Add two quaternions
RMDEF Quaternion QuaternionAdd(Quaternion q1, Quaternion q2)
{
Quaternion result = {q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w};
return result;
}
// Add quaternion and float value
RMDEF Quaternion QuaternionAddValue(Quaternion q, float add)
{
Quaternion result = {q.x + add, q.y + add, q.z + add, q.w + add};
return result;
}
// Subtract two quaternions
RMDEF Quaternion QuaternionSubtract(Quaternion q1, Quaternion q2)
{
Quaternion result = {q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w};
return result;
}
// Subtract quaternion and float value
RMDEF Quaternion QuaternionSubtractValue(Quaternion q, float sub)
{
Quaternion result = {q.x - sub, q.y - sub, q.z - sub, q.w - sub};
return result;
}
// Returns identity quaternion // Returns identity quaternion
RMDEF Quaternion QuaternionIdentity(void) RMDEF Quaternion QuaternionIdentity(void)
{ {
@ -1108,6 +1207,28 @@ RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2)
return result; return result;
} }
// Scale quaternion by float value
RMDEF Quaternion QuaternionScale(Quaternion q, float mul)
{
Quaternion result = { 0 };
float qax = q.x, qay = q.y, qaz = q.z, qaw = q.w;
result.x = qax * mul + qaw * mul + qay * mul - qaz * mul;
result.y = qay * mul + qaw * mul + qaz * mul - qax * mul;
result.z = qaz * mul + qaw * mul + qax * mul - qay * mul;
result.w = qaw * mul - qax * mul - qay * mul - qaz * mul;
return result;
}
// Divide two quaternions
RMDEF Quaternion QuaternionDivide(Quaternion q1, Quaternion q2)
{
Quaternion result = {q1.x / q2.x, q1.y / q2.y, q1.z / q2.z, q1.w / q2.w};
return result;
}
// Calculate linear interpolation between two quaternions // Calculate linear interpolation between two quaternions
RMDEF Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount) RMDEF Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount)
{ {
@ -1176,7 +1297,7 @@ RMDEF Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to)
result.x = cross.x; result.x = cross.x;
result.y = cross.y; result.y = cross.y;
result.z = cross.y; result.z = cross.z;
result.w = 1.0f + cos2Theta; // NOTE: Added QuaternioIdentity() result.w = 1.0f + cos2Theta; // NOTE: Added QuaternioIdentity()
// Normalize to essentially nlerp the original and identity to 0.5 // Normalize to essentially nlerp the original and identity to 0.5
@ -1191,101 +1312,58 @@ RMDEF Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to)
// Returns a quaternion for a given rotation matrix // Returns a quaternion for a given rotation matrix
RMDEF Quaternion QuaternionFromMatrix(Matrix mat) RMDEF Quaternion QuaternionFromMatrix(Matrix mat)
{ {
Quaternion result = { 0 }; Quaternion result = { 0.0f };
float trace = MatrixTrace(mat); if ((mat.m0 > mat.m5) && (mat.m0 > mat.m10))
if (trace > 0.0f)
{ {
float s = sqrtf(trace + 1)*2.0f; float s = sqrtf(1.0f + mat.m0 - mat.m5 - mat.m10)*2;
float invS = 1.0f/s;
result.x = 0.25f*s;
result.w = s*0.25f; result.y = (mat.m4 + mat.m1)/s;
result.x = (mat.m6 - mat.m9)*invS; result.z = (mat.m2 + mat.m8)/s;
result.y = (mat.m8 - mat.m2)*invS; result.w = (mat.m9 - mat.m6)/s;
result.z = (mat.m1 - mat.m4)*invS; }
} else if (mat.m5 > mat.m10)
{
float s = sqrtf(1.0f + mat.m5 - mat.m0 - mat.m10)*2;
result.x = (mat.m4 + mat.m1)/s;
result.y = 0.25f*s;
result.z = (mat.m9 + mat.m6)/s;
result.w = (mat.m2 - mat.m8)/s;
}
else else
{ {
float m00 = mat.m0, m11 = mat.m5, m22 = mat.m10; float s = sqrtf(1.0f + mat.m10 - mat.m0 - mat.m5)*2;
result.x = (mat.m2 + mat.m8)/s;
if (m00 > m11 && m00 > m22) result.y = (mat.m9 + mat.m6)/s;
{ result.z = 0.25f*s;
float s = (float)sqrt(1.0f + m00 - m11 - m22)*2.0f; result.w = (mat.m4 - mat.m1)/s;
float invS = 1.0f/s;
result.w = (mat.m6 - mat.m9)*invS;
result.x = s*0.25f;
result.y = (mat.m4 + mat.m1)*invS;
result.z = (mat.m8 + mat.m2)*invS;
}
else if (m11 > m22)
{
float s = sqrtf(1.0f + m11 - m00 - m22)*2.0f;
float invS = 1.0f/s;
result.w = (mat.m8 - mat.m2)*invS;
result.x = (mat.m4 + mat.m1)*invS;
result.y = s*0.25f;
result.z = (mat.m9 + mat.m6)*invS;
}
else
{
float s = sqrtf(1.0f + m22 - m00 - m11)*2.0f;
float invS = 1.0f/s;
result.w = (mat.m1 - mat.m4)*invS;
result.x = (mat.m8 + mat.m2)*invS;
result.y = (mat.m9 + mat.m6)*invS;
result.z = s*0.25f;
}
} }
return result; return result;
} }
// Returns a matrix for a given quaternion // Returns a matrix for a given quaternion
RMDEF Matrix QuaternionToMatrix(Quaternion q) RMDEF Matrix QuaternionToMatrix(Quaternion q)
{ {
Matrix result = { 0 }; Matrix result = MatrixIdentity();
float 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; result.m0 = 1 - b2 - c2;
result.m1 = ab - cd;
float x2 = x + x; result.m2 = ac + bd;
float y2 = y + y;
float z2 = z + z; result.m4 = ab + cd;
result.m5 = 1 - a2 - c2;
float length = QuaternionLength(q); result.m6 = bc - ad;
float lengthSquared = length*length;
result.m8 = ac - bd;
float xx = x*x2/lengthSquared; result.m9 = bc + ad;
float xy = x*y2/lengthSquared; result.m10 = 1 - a2 - b2;
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;
return result; return result;
} }
@ -1399,4 +1477,27 @@ RMDEF Quaternion QuaternionTransform(Quaternion q, Matrix mat)
return result; return result;
} }
// Projects a Vector3 from screen space into object space
RMDEF Vector3 Vector3Unproject(Vector3 source, Matrix projection, Matrix view)
{
Vector3 result = { 0.0f, 0.0f, 0.0f };
// Calculate unproject matrix (multiply view patrix by projection matrix) and invert it
Matrix matViewProj = MatrixMultiply(view, projection);
matViewProj = MatrixInvert(matViewProj);
// Create quaternion from source point
Quaternion quat = { source.x, source.y, source.z, 1.0f };
// Multiply quat point by unproject matrix
quat = QuaternionTransform(quat, matViewProj);
// Normalized world points in vectors
result.x = quat.x/quat.w;
result.y = quat.y/quat.w;
result.z = quat.z/quat.w;
return result;
}
#endif // RAYMATH_H #endif // RAYMATH_H

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
* *
* rmem - raylib memory pool and objects pool * rmem - raylib memory pool and objects pool
* *
* A quick, efficient, and minimal free list and stack-based allocator * A quick, efficient, and minimal free list and arena-based allocator
* *
* PURPOSE: * PURPOSE:
* - A quicker, efficient memory allocator alternative to 'malloc' and friends. * - A quicker, efficient memory allocator alternative to 'malloc' and friends.
@ -55,6 +55,8 @@
#define RMEMAPI // We are building or using library as a static library (or Linux shared library) #define RMEMAPI // We are building or using library as a static library (or Linux shared library)
#endif #endif
#define RMEM_VERSION "v1.3" // changelog at bottom of header.
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -66,39 +68,45 @@ struct MemNode {
MemNode *next, *prev; MemNode *next, *prev;
}; };
// Freelist implementation
typedef struct AllocList { typedef struct AllocList {
MemNode *head, *tail; MemNode *head, *tail;
size_t len, maxNodes; size_t len;
bool autoDefrag : 1;
} AllocList; } AllocList;
typedef struct Stack { // Arena allocator.
uint8_t *mem, *base; typedef struct Arena {
uintptr_t mem, offs;
size_t size; size_t size;
} Stack; } Arena;
#define MEMPOOL_BUCKET_SIZE 8
#define MEMPOOL_BUCKET_BITS 3 enum {
MEMPOOL_BUCKET_SIZE = 8,
MEMPOOL_BUCKET_BITS = (sizeof(uintptr_t) >> 1) + 1,
MEM_SPLIT_THRESHOLD = sizeof(uintptr_t) * 4
};
typedef struct MemPool { typedef struct MemPool {
AllocList freeList; AllocList large, buckets[MEMPOOL_BUCKET_SIZE];
Stack stack; Arena arena;
MemNode *buckets[MEMPOOL_BUCKET_SIZE];
} MemPool; } MemPool;
// Object Pool // Object Pool
typedef struct ObjPool { typedef struct ObjPool {
Stack stack; uintptr_t mem, offs;
size_t objSize, freeBlocks; size_t objSize, freeBlocks, memSize;
} ObjPool; } ObjPool;
// Double-Ended Stack aka Deque // Double-Ended Stack aka Deque
typedef struct BiStack { typedef struct BiStack {
uint8_t *mem, *front, *back; uintptr_t mem, front, back;
size_t size; size_t size;
} BiStack; } BiStack;
#if defined(__cplusplus) #if defined(__cplusplus)
extern "C" { // Prevents name mangling of functions extern "C" { // Prevents name mangling of functions
#endif #endif
@ -115,10 +123,7 @@ RMEMAPI void *MemPoolRealloc(MemPool *mempool, void *ptr, size_t bytes);
RMEMAPI void MemPoolFree(MemPool *mempool, void *ptr); RMEMAPI void MemPoolFree(MemPool *mempool, void *ptr);
RMEMAPI void MemPoolCleanUp(MemPool *mempool, void **ptrref); RMEMAPI void MemPoolCleanUp(MemPool *mempool, void **ptrref);
RMEMAPI void MemPoolReset(MemPool *mempool); RMEMAPI void MemPoolReset(MemPool *mempool);
RMEMAPI bool MemPoolDefrag(MemPool *mempool);
RMEMAPI size_t GetMemPoolFreeMemory(const MemPool mempool); RMEMAPI size_t GetMemPoolFreeMemory(const MemPool mempool);
RMEMAPI void ToggleMemPoolAutoDefrag(MemPool *mempool);
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Functions Declaration - Object Pool // Functions Declaration - Object Pool
@ -161,7 +166,9 @@ RMEMAPI intptr_t BiStackMargins(BiStack destack);
#if defined(RMEM_IMPLEMENTATION) #if defined(RMEM_IMPLEMENTATION)
#include <stdio.h> // Required for: malloc(), calloc(), free() #include <stdio.h> // Required for:
#include <stdlib.h> // Required for:
#include <string.h> // Required for:
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
@ -188,6 +195,145 @@ static inline size_t __AlignSize(const size_t size, const size_t align)
return (size + (align - 1)) & -align; return (size + (align - 1)) & -align;
} }
static MemNode *__SplitMemNode(MemNode *const node, const size_t bytes)
{
uintptr_t n = ( uintptr_t )node;
MemNode *const r = ( MemNode* )(n + (node->size - bytes));
node->size -= bytes;
r->size = bytes;
return r;
}
static void __InsertMemNodeBefore(AllocList *const list, MemNode *const insert, MemNode *const curr)
{
insert->next = curr;
if (curr->prev==NULL) list->head = insert;
else
{
insert->prev = curr->prev;
curr->prev->next = insert;
}
curr->prev = insert;
}
static void __ReplaceMemNode(MemNode *const old, MemNode *const replace)
{
replace->prev = old->prev;
replace->next = old->next;
if( old->prev != NULL )
old->prev->next = replace;
if( old->next != NULL )
old->next->prev = replace;
}
static MemNode *__RemoveMemNode(AllocList *const list, MemNode *const node)
{
if (node->prev != NULL) node->prev->next = node->next;
else
{
list->head = node->next;
if (list->head != NULL) list->head->prev = NULL;
else list->tail = NULL;
}
if (node->next != NULL) node->next->prev = node->prev;
else
{
list->tail = node->prev;
if (list->tail != NULL) list->tail->next = NULL;
else list->head = NULL;
}
list->len--;
return node;
}
static MemNode *__FindMemNode(AllocList *const list, const size_t bytes)
{
for (MemNode *node = list->head; node != NULL; node = node->next)
{
if (node->size < bytes) continue;
// close in size - reduce fragmentation by not splitting.
else if (node->size <= bytes + MEM_SPLIT_THRESHOLD) return __RemoveMemNode(list, node);
else return __SplitMemNode(node, bytes);
}
return NULL;
}
static void __InsertMemNode(MemPool *const mempool, AllocList *const list, MemNode *const node, const bool is_bucket)
{
if (list->head == NULL)
{
list->head = node;
list->len++;
}
else
{
for (MemNode *iter = list->head; iter != NULL; iter = iter->next)
{
if (( uintptr_t )iter == mempool->arena.offs)
{
mempool->arena.offs += iter->size;
__RemoveMemNode(list, iter);
iter = list->head;
}
const uintptr_t inode = ( uintptr_t )node;
const uintptr_t iiter = ( uintptr_t )iter;
const uintptr_t iter_end = iiter + iter->size;
const uintptr_t node_end = inode + node->size;
if (iter==node) return;
else if (iter < node)
{
// node was coalesced prior.
if (iter_end > inode) return;
else if (iter_end==inode && !is_bucket)
{
// if we can coalesce, do so.
iter->size += node->size;
return;
}
}
else if (iter > node)
{
// Address sort, lowest to highest aka ascending order.
if (iiter < node_end) return;
else if (iter==list->head && !is_bucket)
{
if (iter_end==inode) iter->size += node->size;
else if (node_end==iiter)
{
node->size += list->head->size;
node->next = list->head->next;
node->prev = NULL;
list->head = node;
}
else
{
node->next = iter;
node->prev = NULL;
iter->prev = node;
list->head = node;
list->len++;
}
return;
}
else if (iter_end==inode && !is_bucket)
{
// if we can coalesce, do so.
iter->size += node->size;
return;
}
else
{
__InsertMemNodeBefore(list, iter, node);
list->len++;
return;
}
}
}
}
}
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition - Memory Pool // Module Functions Definition - Memory Pool
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -196,114 +342,77 @@ MemPool CreateMemPool(const size_t size)
{ {
MemPool mempool = { 0 }; MemPool mempool = { 0 };
if (size == 0UL) return mempool; if (size == 0) return mempool;
else else
{ {
// Align the mempool size to at least the size of an alloc node. // Align the mempool size to at least the size of an alloc node.
mempool.stack.size = size; uint8_t *const restrict buf = malloc(size*sizeof *buf);
mempool.stack.mem = malloc(mempool.stack.size*sizeof *mempool.stack.mem); if (buf==NULL) return mempool;
if (mempool.stack.mem == NULL)
{
mempool.stack.size = 0UL;
return mempool;
}
else else
{ {
mempool.stack.base = mempool.stack.mem + mempool.stack.size; mempool.arena.size = size;
mempool.arena.mem = ( uintptr_t )buf;
mempool.arena.offs = mempool.arena.mem + mempool.arena.size;
return mempool; return mempool;
} }
} }
} }
MemPool CreateMemPoolFromBuffer(void *buf, const size_t size) MemPool CreateMemPoolFromBuffer(void *const restrict buf, const size_t size)
{ {
MemPool mempool = { 0 }; MemPool mempool = { 0 };
if ((size == 0) || (buf == NULL) || (size <= sizeof(MemNode))) return mempool;
if ((size == 0UL) || (buf == NULL) || (size <= sizeof(MemNode))) return mempool;
else else
{ {
mempool.stack.size = size; mempool.arena.size = size;
mempool.stack.mem = buf; mempool.arena.mem = ( uintptr_t )buf;
mempool.stack.base = mempool.stack.mem + mempool.stack.size; mempool.arena.offs = mempool.arena.mem + mempool.arena.size;
return mempool; return mempool;
} }
} }
void DestroyMemPool(MemPool *const mempool) void DestroyMemPool(MemPool *const restrict mempool)
{ {
if ((mempool == NULL) || (mempool->stack.mem == NULL)) return; if (mempool->arena.mem == 0) return;
else else
{ {
free(mempool->stack.mem); void *const restrict ptr = ( void* )mempool->arena.mem;
free(ptr);
*mempool = (MemPool){ 0 }; *mempool = (MemPool){ 0 };
} }
} }
void *MemPoolAlloc(MemPool *const mempool, const size_t size) void *MemPoolAlloc(MemPool *const mempool, const size_t size)
{ {
if ((mempool == NULL) || (size == 0UL) || (size > mempool->stack.size)) return NULL; if ((size == 0) || (size > mempool->arena.size)) return NULL;
else else
{ {
MemNode *new_mem = NULL; MemNode *new_mem = NULL;
const size_t ALLOC_SIZE = __AlignSize(size + sizeof *new_mem, sizeof(intptr_t)); const size_t ALLOC_SIZE = __AlignSize(size + sizeof *new_mem, sizeof(intptr_t));
const size_t BUCKET_INDEX = (ALLOC_SIZE >> MEMPOOL_BUCKET_BITS) - 1; const size_t BUCKET_SLOT = (ALLOC_SIZE >> MEMPOOL_BUCKET_BITS) - 1;
// If the size is small enough, let's check if our buckets has a fitting memory block. // If the size is small enough, let's check if our buckets has a fitting memory block.
if ((BUCKET_INDEX < MEMPOOL_BUCKET_SIZE) && if (BUCKET_SLOT < MEMPOOL_BUCKET_SIZE)
(mempool->buckets[BUCKET_INDEX] != NULL) &&
(mempool->buckets[BUCKET_INDEX]->size >= ALLOC_SIZE))
{ {
new_mem = mempool->buckets[BUCKET_INDEX]; new_mem = __FindMemNode(&mempool->buckets[BUCKET_SLOT], ALLOC_SIZE);
mempool->buckets[BUCKET_INDEX] = mempool->buckets[BUCKET_INDEX]->next;
if( mempool->buckets[BUCKET_INDEX] != NULL )
mempool->buckets[BUCKET_INDEX]->prev = NULL;
} }
else if (mempool->freeList.head != NULL) else if (mempool->large.head != NULL)
{ {
const size_t MEM_SPLIT_THRESHOLD = 16; new_mem = __FindMemNode(&mempool->large, ALLOC_SIZE);
// If the freelist is valid, let's allocate FROM the freelist then!
for (MemNode *inode = mempool->freeList.head; inode != NULL; inode = inode->next)
{
if (inode->size < ALLOC_SIZE) continue;
else if (inode->size <= (ALLOC_SIZE + MEM_SPLIT_THRESHOLD))
{
// Close in size - reduce fragmentation by not splitting.
new_mem = inode;
(inode->prev != NULL)? (inode->prev->next = inode->next) : (mempool->freeList.head = inode->next);
(inode->next != NULL)? (inode->next->prev = inode->prev) : (mempool->freeList.tail = inode->prev);
if (mempool->freeList.head != NULL) mempool->freeList.head->prev = NULL;
else mempool->freeList.tail = NULL;
if (mempool->freeList.tail != NULL) mempool->freeList.tail->next = NULL;
mempool->freeList.len--;
break;
}
else
{
// Split the memory chunk.
new_mem = (MemNode *)((uint8_t *)inode + (inode->size - ALLOC_SIZE));
inode->size -= ALLOC_SIZE;
new_mem->size = ALLOC_SIZE;
break;
}
}
} }
if (new_mem == NULL) if (new_mem == NULL)
{ {
// not enough memory to support the size! // not enough memory to support the size!
if ((mempool->stack.base - ALLOC_SIZE) < mempool->stack.mem) return NULL; if ((mempool->arena.offs - ALLOC_SIZE) < mempool->arena.mem) return NULL;
else else
{ {
// Couldn't allocate from a freelist, allocate from available mempool. // Couldn't allocate from a freelist, allocate from available mempool.
// Subtract allocation size from the mempool. // Subtract allocation size from the mempool.
mempool->stack.base -= ALLOC_SIZE; mempool->arena.offs -= ALLOC_SIZE;
// Use the available mempool space as the new node. // Use the available mempool space as the new node.
new_mem = (MemNode *)mempool->stack.base; new_mem = ( MemNode* )mempool->arena.offs;
new_mem->size = ALLOC_SIZE; new_mem->size = ALLOC_SIZE;
} }
} }
@ -313,33 +422,32 @@ void *MemPoolAlloc(MemPool *const mempool, const size_t size)
// | mem size | lowest addr of block // | mem size | lowest addr of block
// | next node | 12 byte (32-bit) header // | next node | 12 byte (32-bit) header
// | prev node | 24 byte (64-bit) header // | prev node | 24 byte (64-bit) header
// -------------- // |------------|
// | alloc'd | // | alloc'd |
// | memory | // | memory |
// | space | highest addr of block // | space | highest addr of block
// -------------- // --------------
new_mem->next = new_mem->prev = NULL; new_mem->next = new_mem->prev = NULL;
uint8_t *const final_mem = (uint8_t *)new_mem + sizeof *new_mem; uint8_t *const restrict final_mem = ( uint8_t* )new_mem + sizeof *new_mem;
return memset(final_mem, 0, new_mem->size - sizeof *new_mem); return memset(final_mem, 0, new_mem->size - sizeof *new_mem);
} }
} }
void *MemPoolRealloc(MemPool *const restrict mempool, void *ptr, const size_t size) void *MemPoolRealloc(MemPool *const restrict mempool, void *const ptr, const size_t size)
{ {
if ((mempool == NULL) || (size > mempool->stack.size)) return NULL; if (size > mempool->arena.size) return NULL;
// NULL ptr should make this work like regular Allocation. // NULL ptr should make this work like regular Allocation.
else if (ptr == NULL) return MemPoolAlloc(mempool, size); else if (ptr == NULL) return MemPoolAlloc(mempool, size);
else if ((uintptr_t)ptr - sizeof(MemNode) < (uintptr_t)mempool->stack.mem) return NULL; else if ((uintptr_t)ptr - sizeof(MemNode) < mempool->arena.mem) return NULL;
else else
{ {
MemNode *const node = (MemNode *)((uint8_t *)ptr - sizeof *node); MemNode *const node = ( MemNode* )(( uint8_t* )ptr - sizeof *node);
const size_t NODE_SIZE = sizeof *node; const size_t NODE_SIZE = sizeof *node;
uint8_t *const resized_block = MemPoolAlloc(mempool, size); uint8_t *const resized_block = MemPoolAlloc(mempool, size);
if (resized_block == NULL) return NULL; if (resized_block == NULL) return NULL;
else else
{ {
MemNode *const resized = (MemNode *)(resized_block - sizeof *resized); MemNode *const resized = ( MemNode* )(resized_block - sizeof *resized);
memmove(resized_block, ptr, (node->size > resized->size)? (resized->size - NODE_SIZE) : (node->size - NODE_SIZE)); memmove(resized_block, ptr, (node->size > resized->size)? (resized->size - NODE_SIZE) : (node->size - NODE_SIZE));
MemPoolFree(mempool, ptr); MemPoolFree(mempool, ptr);
return resized_block; return resized_block;
@ -347,72 +455,39 @@ void *MemPoolRealloc(MemPool *const restrict mempool, void *ptr, const size_t si
} }
} }
void MemPoolFree(MemPool *const restrict mempool, void *ptr) void MemPoolFree(MemPool *const restrict mempool, void *const ptr)
{ {
if ((mempool == NULL) || (ptr == NULL) || ((uintptr_t)ptr - sizeof(MemNode) < (uintptr_t)mempool->stack.mem)) return; const uintptr_t p = ( uintptr_t )ptr;
if ((ptr == NULL) || (p - sizeof(MemNode) < mempool->arena.mem)) return;
else else
{ {
// Behind the actual pointer data is the allocation info. // Behind the actual pointer data is the allocation info.
MemNode *const mem_node = (MemNode *)((uint8_t *)ptr - sizeof *mem_node); const uintptr_t block = p - sizeof(MemNode);
const size_t BUCKET_INDEX = (mem_node->size >> MEMPOOL_BUCKET_BITS) - 1; MemNode *const mem_node = ( MemNode* )block;
const size_t BUCKET_SLOT = (mem_node->size >> MEMPOOL_BUCKET_BITS) - 1;
// Make sure the pointer data is valid. // Make sure the pointer data is valid.
if (((uintptr_t)mem_node < (uintptr_t)mempool->stack.base) || if ((block < mempool->arena.offs) ||
(((uintptr_t)mem_node - (uintptr_t)mempool->stack.mem) > mempool->stack.size) || ((block - mempool->arena.mem) > mempool->arena.size) ||
(mem_node->size == 0UL) || (mem_node->size == 0) ||
(mem_node->size > mempool->stack.size)) return; (mem_node->size > mempool->arena.size)) return;
// If the mem_node is right at the stack base ptr, then add it to the stack. // If the mem_node is right at the arena offs, then merge it back to the arena.
else if ((uintptr_t)mem_node == (uintptr_t)mempool->stack.base) else if (block == mempool->arena.offs)
{ {
mempool->stack.base += mem_node->size; mempool->arena.offs += mem_node->size;
} }
// attempted stack merge failed, try to place it into the memnode buckets else
else if (BUCKET_INDEX < MEMPOOL_BUCKET_SIZE)
{ {
if (mempool->buckets[BUCKET_INDEX] == NULL) mempool->buckets[BUCKET_INDEX] = mem_node; // try to place it into bucket or large freelist.
else struct AllocList *const l = (BUCKET_SLOT < MEMPOOL_BUCKET_SIZE) ? &mempool->buckets[BUCKET_SLOT] : &mempool->large;
{ __InsertMemNode(mempool, l, mem_node, (BUCKET_SLOT < MEMPOOL_BUCKET_SIZE));
for (MemNode *n = mempool->buckets[BUCKET_INDEX]; n != NULL; n = n->next) if( n==mem_node ) return;
mempool->buckets[BUCKET_INDEX]->prev = mem_node;
mem_node->next = mempool->buckets[BUCKET_INDEX];
mempool->buckets[BUCKET_INDEX] = mem_node;
}
}
// Otherwise, we add it to the free list.
// We also check if the freelist already has the pointer so we can prevent double frees.
else /*if ((mempool->freeList.len == 0UL) || ((uintptr_t)mempool->freeList.head >= (uintptr_t)mempool->stack.mem && (uintptr_t)mempool->freeList.head - (uintptr_t)mempool->stack.mem < mempool->stack.size))*/
{
for (MemNode *n = mempool->freeList.head; n != NULL; n = n->next) if (n == mem_node) return;
// This code insertion sorts where largest size is last.
if (mempool->freeList.head == NULL)
{
mempool->freeList.head = mempool->freeList.tail = mem_node;
mempool->freeList.len++;
}
else if (mempool->freeList.head->size >= mem_node->size)
{
mem_node->next = mempool->freeList.head;
mem_node->next->prev = mem_node;
mempool->freeList.head = mem_node;
mempool->freeList.len++;
}
else //if (mempool->freeList.tail->size <= mem_node->size)
{
mem_node->prev = mempool->freeList.tail;
mempool->freeList.tail->next = mem_node;
mempool->freeList.tail = mem_node;
mempool->freeList.len++;
}
if (mempool->freeList.autoDefrag && (mempool->freeList.maxNodes != 0UL) && (mempool->freeList.len > mempool->freeList.maxNodes)) MemPoolDefrag(mempool);
} }
} }
} }
void MemPoolCleanUp(MemPool *const restrict mempool, void **ptrref) void MemPoolCleanUp(MemPool *const restrict mempool, void **const ptrref)
{ {
if ((mempool == NULL) || (ptrref == NULL) || (*ptrref == NULL)) return; if ((ptrref == NULL) || (*ptrref == NULL)) return;
else else
{ {
MemPoolFree(mempool, *ptrref); MemPoolFree(mempool, *ptrref);
@ -422,264 +497,127 @@ void MemPoolCleanUp(MemPool *const restrict mempool, void **ptrref)
size_t GetMemPoolFreeMemory(const MemPool mempool) size_t GetMemPoolFreeMemory(const MemPool mempool)
{ {
size_t total_remaining = (uintptr_t)mempool.stack.base - (uintptr_t)mempool.stack.mem; size_t total_remaining = mempool.arena.offs - mempool.arena.mem;
for (MemNode *n = mempool.freeList.head; n != NULL; n = n->next) total_remaining += n->size; for (MemNode *n=mempool.large.head; n != NULL; n = n->next) total_remaining += n->size;
for (int i = 0; i < MEMPOOL_BUCKET_SIZE; i++) for (MemNode *n = mempool.buckets[i]; n != NULL; n = n->next) total_remaining += n->size; for (size_t i=0; i<MEMPOOL_BUCKET_SIZE; i++) for (MemNode *n = mempool.buckets[i].head; n != NULL; n = n->next) total_remaining += n->size;
return total_remaining; return total_remaining;
} }
void MemPoolReset(MemPool *const mempool) void MemPoolReset(MemPool *const mempool)
{ {
if (mempool == NULL) return; mempool->large.head = mempool->large.tail = NULL;
mempool->freeList.head = mempool->freeList.tail = NULL; mempool->large.len = 0;
mempool->freeList.len = 0; for (size_t i = 0; i < MEMPOOL_BUCKET_SIZE; i++)
for (int i = 0; i < MEMPOOL_BUCKET_SIZE; i++) mempool->buckets[i] = NULL;
mempool->stack.base = mempool->stack.mem + mempool->stack.size;
}
bool MemPoolDefrag(MemPool *const mempool)
{
if (mempool == NULL) return false;
else
{ {
// If the memory pool has been entirely released, fully defrag it. mempool->buckets[i].head = mempool->buckets[i].tail = NULL;
if (mempool->stack.size == GetMemPoolFreeMemory(*mempool)) mempool->buckets[i].len = 0;
{
MemPoolReset(mempool);
return true;
}
else
{
for (int i = 0; i < MEMPOOL_BUCKET_SIZE; i++)
{
while (mempool->buckets[i] != NULL)
{
if ((uintptr_t)mempool->buckets[i] == (uintptr_t)mempool->stack.base)
{
mempool->stack.base += mempool->buckets[i]->size;
mempool->buckets[i]->size = 0;
mempool->buckets[i] = mempool->buckets[i]->next;
if (mempool->buckets[i] != NULL) mempool->buckets[i]->prev = NULL;
}
else break;
}
}
const size_t PRE_DEFRAG_LEN = mempool->freeList.len;
MemNode **node = &mempool->freeList.head;
while (*node != NULL)
{
if ((uintptr_t)*node == (uintptr_t)mempool->stack.base)
{
// If node is right at the stack, merge it back into the stack.
mempool->stack.base += (*node)->size;
(*node)->size = 0UL;
((*node)->prev != NULL)? ((*node)->prev->next = (*node)->next) : (mempool->freeList.head = (*node)->next);
((*node)->next != NULL)? ((*node)->next->prev = (*node)->prev) : (mempool->freeList.tail = (*node)->prev);
if (mempool->freeList.head != NULL) mempool->freeList.head->prev = NULL;
else mempool->freeList.tail = NULL;
if (mempool->freeList.tail != NULL) mempool->freeList.tail->next = NULL;
mempool->freeList.len--;
node = &mempool->freeList.head;
}
else if (((uintptr_t)*node + (*node)->size) == (uintptr_t)(*node)->next)
{
// Next node is at a higher address.
(*node)->size += (*node)->next->size;
(*node)->next->size = 0UL;
// <-[P Curr N]-> <-[P Next N]-> <-[P NextNext N]->
//
// |--------------------|
// <-[P Curr N]-> <-[P Next N]-> [P NextNext N]->
if ((*node)->next->next != NULL) (*node)->next->next->prev = *node;
// <-[P Curr N]-> <-[P NextNext N]->
(*node)->next = (*node)->next->next;
mempool->freeList.len--;
node = &mempool->freeList.head;
}
else if ((((uintptr_t)*node + (*node)->size) == (uintptr_t)(*node)->prev) && ((*node)->prev->prev != NULL))
{
// Prev node is at a higher address.
(*node)->size += (*node)->prev->size;
(*node)->prev->size = 0UL;
// <-[P PrevPrev N]-> <-[P Prev N]-> <-[P Curr N]->
//
// |--------------------|
// <-[P PrevPrev N] <-[P Prev N]-> <-[P Curr N]->
(*node)->prev->prev->next = *node;
// <-[P PrevPrev N]-> <-[P Curr N]->
(*node)->prev = (*node)->prev->prev;
mempool->freeList.len--;
node = &mempool->freeList.head;
}
else if ((*node)->prev != NULL && (*node)->next != NULL && (uintptr_t)*node - (*node)->next->size == (uintptr_t)(*node)->next)
{
// Next node is at a lower address.
(*node)->next->size += (*node)->size;
(*node)->size = 0UL;
(*node)->next->prev = (*node)->prev;
(*node)->prev->next = (*node)->next;
*node = (*node)->next;
mempool->freeList.len--;
node = &mempool->freeList.head;
}
else if ((*node)->prev != NULL && (*node)->next != NULL && (uintptr_t)*node - (*node)->prev->size == (uintptr_t)(*node)->prev)
{
// Prev node is at a lower address.
(*node)->prev->size += (*node)->size;
(*node)->size = 0UL;
(*node)->next->prev = (*node)->prev;
(*node)->prev->next = (*node)->next;
*node = (*node)->prev;
mempool->freeList.len--;
node = &mempool->freeList.head;
}
else
{
node = &(*node)->next;
}
}
return PRE_DEFRAG_LEN > mempool->freeList.len;
}
} }
} mempool->arena.offs = mempool->arena.mem + mempool->arena.size;
void ToggleMemPoolAutoDefrag(MemPool *const mempool)
{
if (mempool == NULL) return;
else mempool->freeList.autoDefrag ^= true;
} }
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition - Object Pool // Module Functions Definition - Object Pool
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
union ObjInfo {
uint8_t *const byte;
size_t *const index;
};
ObjPool CreateObjPool(const size_t objsize, const size_t len) ObjPool CreateObjPool(const size_t objsize, const size_t len)
{ {
ObjPool objpool = { 0 }; ObjPool objpool = { 0 };
if ((len == 0) || (objsize == 0)) return objpool;
if ((len == 0UL) || (objsize == 0UL)) return objpool;
else else
{ {
objpool.objSize = __AlignSize(objsize, sizeof(size_t)); const size_t aligned_size = __AlignSize(objsize, sizeof(size_t));
objpool.stack.size = objpool.freeBlocks = len; uint8_t *const restrict buf = calloc(len, aligned_size);
objpool.stack.mem = calloc(objpool.stack.size, objpool.objSize); if (buf == NULL) return objpool;
objpool.objSize = aligned_size;
if (objpool.stack.mem == NULL) objpool.memSize = objpool.freeBlocks = len;
objpool.mem = ( uintptr_t )buf;
for (size_t i=0; i<objpool.freeBlocks; i++)
{ {
objpool.stack.size = 0UL; size_t *const restrict index = ( size_t* )(objpool.mem + (i*aligned_size));
return objpool; *index = i + 1;
}
else
{
for (int i = 0; i < objpool.freeBlocks; i++)
{
union ObjInfo block = { .byte = &objpool.stack.mem[i*objpool.objSize] };
*block.index = i + 1;
}
objpool.stack.base = objpool.stack.mem;
return objpool;
}
}
}
ObjPool CreateObjPoolFromBuffer(void *const buf, const size_t objsize, const size_t len)
{
ObjPool objpool = { 0 };
// If the object size isn't large enough to align to a size_t, then we can't use it.
if ((buf == NULL) || (len == 0UL) || (objsize < sizeof(size_t)) || (objsize*len != __AlignSize(objsize, sizeof(size_t))*len)) return objpool;
else
{
objpool.objSize = __AlignSize(objsize, sizeof(size_t));
objpool.stack.size = objpool.freeBlocks = len;
objpool.stack.mem = buf;
for (int i = 0; i < objpool.freeBlocks; i++)
{
union ObjInfo block = { .byte = &objpool.stack.mem[i*objpool.objSize] };
*block.index = i + 1;
} }
objpool.stack.base = objpool.stack.mem; objpool.offs = objpool.mem;
return objpool; return objpool;
} }
} }
void DestroyObjPool(ObjPool *const objpool) ObjPool CreateObjPoolFromBuffer(void *const restrict buf, const size_t objsize, const size_t len)
{ {
if ((objpool == NULL) || (objpool->stack.mem == NULL)) return; ObjPool objpool = { 0 };
// If the object size isn't large enough to align to a size_t, then we can't use it.
const size_t aligned_size = __AlignSize(objsize, sizeof(size_t));
if ((buf == NULL) || (len == 0) || (objsize < sizeof(size_t)) || (objsize*len != aligned_size*len)) return objpool;
else else
{ {
free(objpool->stack.mem); objpool.objSize = aligned_size;
objpool.memSize = objpool.freeBlocks = len;
objpool.mem = (uintptr_t)buf;
for (size_t i=0; i<objpool.freeBlocks; i++)
{
size_t *const restrict index = ( size_t* )(objpool.mem + (i*aligned_size));
*index = i + 1;
}
objpool.offs = objpool.mem;
return objpool;
}
}
void DestroyObjPool(ObjPool *const restrict objpool)
{
if (objpool->mem == 0) return;
else
{
void *const restrict ptr = ( void* )objpool->mem;
free(ptr);
*objpool = (ObjPool){0}; *objpool = (ObjPool){0};
} }
} }
void *ObjPoolAlloc(ObjPool *const objpool) void *ObjPoolAlloc(ObjPool *const objpool)
{ {
if (objpool == NULL) return NULL; if (objpool->freeBlocks > 0)
else
{ {
if (objpool->freeBlocks > 0UL) // For first allocation, head points to the very first index.
{ // Head = &pool[0];
// For first allocation, head points to the very first index. // ret = Head == ret = &pool[0];
// Head = &pool[0]; size_t *const restrict block = ( size_t* )objpool->offs;
// ret = Head == ret = &pool[0]; objpool->freeBlocks--;
union ObjInfo ret = { .byte = objpool->stack.base };
objpool->freeBlocks--;
// after allocating, we set head to the address of the index that *Head holds. // after allocating, we set head to the address of the index that *Head holds.
// Head = &pool[*Head * pool.objsize]; // Head = &pool[*Head * pool.objsize];
objpool->stack.base = (objpool->freeBlocks != 0UL)? objpool->stack.mem + (*ret.index*objpool->objSize) : NULL; objpool->offs = (objpool->freeBlocks != 0)? objpool->mem + (*block*objpool->objSize) : 0;
memset(ret.byte, 0, objpool->objSize); return memset(block, 0, objpool->objSize);
return ret.byte;
}
else return NULL;
} }
else return NULL;
} }
void ObjPoolFree(ObjPool *const restrict objpool, void *ptr) void ObjPoolFree(ObjPool *const restrict objpool, void *const ptr)
{ {
union ObjInfo p = { .byte = ptr }; uintptr_t block = (uintptr_t)ptr;
if ((objpool == NULL) || (ptr == NULL) || (p.byte < objpool->stack.mem) || (p.byte > objpool->stack.mem + objpool->stack.size*objpool->objSize)) return; if ((ptr == NULL) || (block < objpool->mem) || (block > objpool->mem + objpool->memSize*objpool->objSize)) return;
else else
{ {
// When we free our pointer, we recycle the pointer space to store the previous index and then we push it as our new head. // When we free our pointer, we recycle the pointer space to store the previous index and then we push it as our new head.
// *p = index of Head in relation to the buffer; // *p = index of Head in relation to the buffer;
// Head = p; // Head = p;
*p.index = (objpool->stack.base != NULL)? (objpool->stack.base - objpool->stack.mem)/objpool->objSize : objpool->stack.size; size_t *const restrict index = ( size_t* )block;
objpool->stack.base = p.byte; *index = (objpool->offs != 0)? (objpool->offs - objpool->mem)/objpool->objSize : objpool->memSize;
objpool->offs = block;
objpool->freeBlocks++; objpool->freeBlocks++;
} }
} }
void ObjPoolCleanUp(ObjPool *const restrict objpool, void **ptrref) void ObjPoolCleanUp(ObjPool *const restrict objpool, void **const restrict ptrref)
{ {
if ((objpool == NULL) || (ptrref == NULL) || (*ptrref == NULL)) return; if (ptrref == NULL) return;
else else
{ {
ObjPoolFree(objpool, *ptrref); ObjPoolFree(objpool, *ptrref);
@ -694,71 +632,85 @@ void ObjPoolCleanUp(ObjPool *const restrict objpool, void **ptrref)
BiStack CreateBiStack(const size_t len) BiStack CreateBiStack(const size_t len)
{ {
BiStack destack = { 0 }; BiStack destack = { 0 };
if (len == 0UL) return destack; if (len == 0) return destack;
uint8_t *const buf = malloc(len*sizeof *buf);
if (buf==NULL) return destack;
destack.size = len; destack.size = len;
destack.mem = malloc(len*sizeof *destack.mem); destack.mem = ( uintptr_t )buf;
if (destack.mem==NULL) destack.size = 0UL; destack.front = destack.mem;
else destack.back = destack.mem + len;
{
destack.front = destack.mem;
destack.back = destack.mem + len;
}
return destack; return destack;
} }
BiStack CreateBiStackFromBuffer(void *const buf, const size_t len) BiStack CreateBiStackFromBuffer(void *const buf, const size_t len)
{ {
BiStack destack = { 0 }; BiStack destack = { 0 };
if (len == 0UL || buf == NULL) return destack; if (len == 0 || buf == NULL) return destack;
destack.size = len; else
destack.mem = destack.front = buf; {
destack.back = destack.mem + len; destack.size = len;
return destack; destack.mem = destack.front = ( uintptr_t )buf;
destack.back = destack.mem + len;
return destack;
}
} }
void DestroyBiStack(BiStack *const destack) void DestroyBiStack(BiStack *const restrict destack)
{ {
if ((destack == NULL) || (destack->mem == NULL)) return; if (destack->mem == 0) return;
free(destack->mem); else
*destack = (BiStack){0}; {
uint8_t *const restrict buf = ( uint8_t* )destack->mem;
free(buf);
*destack = (BiStack){0};
}
} }
void *BiStackAllocFront(BiStack *const destack, const size_t len) void *BiStackAllocFront(BiStack *const restrict destack, const size_t len)
{ {
if ((destack == NULL) || (destack->mem == NULL)) return NULL; if (destack->mem == 0) return NULL;
else
const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t)); {
// front end stack is too high! const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t));
if (destack->front + ALIGNED_LEN >= destack->back) return NULL; // front end arena is too high!
if (destack->front + ALIGNED_LEN >= destack->back) return NULL;
uint8_t *ptr = destack->front; else
destack->front += ALIGNED_LEN; {
return ptr; uint8_t *const restrict ptr = ( uint8_t* )destack->front;
destack->front += ALIGNED_LEN;
return ptr;
}
}
} }
void *BiStackAllocBack(BiStack *const destack, const size_t len) void *BiStackAllocBack(BiStack *const restrict destack, const size_t len)
{ {
if ((destack == NULL) || (destack->mem == NULL)) return NULL; if (destack->mem == 0) return NULL;
else
const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t)); {
// back end stack is too low const size_t ALIGNED_LEN = __AlignSize(len, sizeof(uintptr_t));
if (destack->back - ALIGNED_LEN <= destack->front) return NULL; // back end arena is too low
if (destack->back - ALIGNED_LEN <= destack->front) return NULL;
destack->back -= ALIGNED_LEN; else
return destack->back; {
destack->back -= ALIGNED_LEN;
uint8_t *const restrict ptr = ( uint8_t* )destack->back;
return ptr;
}
}
} }
void BiStackResetFront(BiStack *const destack) void BiStackResetFront(BiStack *const destack)
{ {
if ((destack == NULL) || (destack->mem == NULL)) return; if (destack->mem == 0) return;
destack->front = destack->mem; else destack->front = destack->mem;
} }
void BiStackResetBack(BiStack *const destack) void BiStackResetBack(BiStack *const destack)
{ {
if ((destack == NULL) || (destack->mem == NULL)) return; if (destack->mem == 0) return;
destack->back = destack->mem + destack->size; else destack->back = destack->mem + destack->size;
} }
void BiStackResetAll(BiStack *const destack) void BiStackResetAll(BiStack *const destack)
@ -767,9 +719,21 @@ void BiStackResetAll(BiStack *const destack)
BiStackResetFront(destack); BiStackResetFront(destack);
} }
intptr_t BiStackMargins(const BiStack destack) inline intptr_t BiStackMargins(const BiStack destack)
{ {
return destack.back - destack.front; return destack.back - destack.front;
} }
#endif // RMEM_IMPLEMENTATION #endif // RMEM_IMPLEMENTATION
/*******
* Changelog
* v1.0: First Creation.
* v1.1: bug patches for the mempool and addition of object pool.
* v1.2: addition of bidirectional arena.
* v1.3:
* optimizations of allocators.
* renamed 'Stack' to 'Arena'.
* replaced certain define constants with an anonymous enum.
* refactored MemPool to no longer require active or deferred defragging.
********/

2252
raylib/rnet.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -47,7 +47,12 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Nop...
// Error rate to calculate how many segments we need to draw a smooth circle,
// taken from https://stackoverflow.com/a/2244088
#ifndef SMOOTH_CIRCLE_ERROR_RATE
#define SMOOTH_CIRCLE_ERROR_RATE 0.5f
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Types and Structures Definition // Types and Structures Definition
@ -155,17 +160,19 @@ void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
// Draw line using cubic-bezier curves in-out // Draw line using cubic-bezier curves in-out
void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color) void DrawLineBezier(Vector2 startPos, Vector2 endPos, float thick, Color color)
{ {
#define LINE_DIVISIONS 24 // Bezier line divisions #ifndef BEZIER_LINE_DIVISIONS
#define BEZIER_LINE_DIVISIONS 24 // Bezier line divisions
#endif
Vector2 previous = startPos; Vector2 previous = startPos;
Vector2 current; Vector2 current;
for (int i = 1; i <= LINE_DIVISIONS; i++) for (int i = 1; i <= BEZIER_LINE_DIVISIONS; i++)
{ {
// Cubic easing in-out // Cubic easing in-out
// NOTE: Easing is calculated only for y position value // NOTE: Easing is calculated only for y position value
current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)LINE_DIVISIONS); current.y = EaseCubicInOut((float)i, startPos.y, endPos.y - startPos.y, (float)BEZIER_LINE_DIVISIONS);
current.x = previous.x + (endPos.x - startPos.x)/ (float)LINE_DIVISIONS; current.x = previous.x + (endPos.x - startPos.x)/ (float)BEZIER_LINE_DIVISIONS;
DrawLineEx(previous, current, thick, color); DrawLineEx(previous, current, thick, color);
@ -214,18 +221,15 @@ void DrawCircleSector(Vector2 center, float radius, int startAngle, int endAngle
if (segments < 4) if (segments < 4)
{ {
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088 // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
#define CIRCLE_ERROR_RATE 0.5f float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
// Calculate the maximum angle between segments based on the error rate.
float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = (endAngle - startAngle)*ceilf(2*PI/th)/360;
if (segments <= 0) segments = 4; if (segments <= 0) segments = 4;
} }
float stepLength = (float)(endAngle - startAngle)/(float)segments; float stepLength = (float)(endAngle - startAngle)/(float)segments;
float angle = startAngle; float angle = (float)startAngle;
#if defined(SUPPORT_QUADS_DRAW_MODE) #if defined(SUPPORT_QUADS_DRAW_MODE)
if (rlCheckBufferLimit(4*segments/2)) rlglDraw(); if (rlCheckBufferLimit(4*segments/2)) rlglDraw();
@ -306,20 +310,15 @@ void DrawCircleSectorLines(Vector2 center, float radius, int startAngle, int end
if (segments < 4) if (segments < 4)
{ {
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088 // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
#ifndef CIRCLE_ERROR_RATE float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
#define CIRCLE_ERROR_RATE 0.5f segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
#endif
// Calculate the maximum angle between segments based on the error rate.
float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = (endAngle - startAngle)*ceilf(2*PI/th)/360;
if (segments <= 0) segments = 4; if (segments <= 0) segments = 4;
} }
float stepLength = (float)(endAngle - startAngle)/(float)segments; float stepLength = (float)(endAngle - startAngle)/(float)segments;
float angle = startAngle; float angle = (float)startAngle;
// Hide the cap lines when the circle is full // Hide the cap lines when the circle is full
bool showCapLines = true; bool showCapLines = true;
@ -365,11 +364,11 @@ void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Co
for (int i = 0; i < 360; i += 10) for (int i = 0; i < 360; i += 10)
{ {
rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlColor4ub(color1.r, color1.g, color1.b, color1.a);
rlVertex2f(centerX, centerY); rlVertex2f((float)centerX, (float)centerY);
rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlColor4ub(color2.r, color2.g, color2.b, color2.a);
rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius); rlVertex2f((float)centerX + sinf(DEG2RAD*i)*radius, (float)centerY + cosf(DEG2RAD*i)*radius);
rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlColor4ub(color2.r, color2.g, color2.b, color2.a);
rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius); rlVertex2f((float)centerX + sinf(DEG2RAD*(i + 10))*radius, (float)centerY + cosf(DEG2RAD*(i + 10))*radius);
} }
rlEnd(); rlEnd();
} }
@ -407,9 +406,9 @@ void DrawEllipse(int centerX, int centerY, float radiusH, float radiusV, Color c
for (int i = 0; i < 360; i += 10) for (int i = 0; i < 360; i += 10)
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(centerX, centerY); rlVertex2f((float)centerX, (float)centerY);
rlVertex2f(centerX + sinf(DEG2RAD*i)*radiusH, centerY + cosf(DEG2RAD*i)*radiusV); rlVertex2f((float)centerX + sinf(DEG2RAD*i)*radiusH, (float)centerY + cosf(DEG2RAD*i)*radiusV);
rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radiusH, centerY + cosf(DEG2RAD*(i + 10))*radiusV); rlVertex2f((float)centerX + sinf(DEG2RAD*(i + 10))*radiusH, (float)centerY + cosf(DEG2RAD*(i + 10))*radiusV);
} }
rlEnd(); rlEnd();
} }
@ -454,14 +453,9 @@ void DrawRing(Vector2 center, float innerRadius, float outerRadius, int startAng
if (segments < 4) if (segments < 4)
{ {
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088 // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
#ifndef CIRCLE_ERROR_RATE float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
#define CIRCLE_ERROR_RATE 0.5f segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
#endif
// Calculate the maximum angle between segments based on the error rate.
float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
segments = (endAngle - startAngle)*ceilf(2*PI/th)/360;
if (segments <= 0) segments = 4; if (segments <= 0) segments = 4;
} }
@ -474,7 +468,7 @@ void DrawRing(Vector2 center, float innerRadius, float outerRadius, int startAng
} }
float stepLength = (float)(endAngle - startAngle)/(float)segments; float stepLength = (float)(endAngle - startAngle)/(float)segments;
float angle = startAngle; float angle = (float)startAngle;
#if defined(SUPPORT_QUADS_DRAW_MODE) #if defined(SUPPORT_QUADS_DRAW_MODE)
if (rlCheckBufferLimit(4*segments)) rlglDraw(); if (rlCheckBufferLimit(4*segments)) rlglDraw();
@ -550,14 +544,9 @@ void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, int sta
if (segments < 4) if (segments < 4)
{ {
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088 // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
#ifndef CIRCLE_ERROR_RATE float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
#define CIRCLE_ERROR_RATE 0.5f segments = (int)((endAngle - startAngle)*ceilf(2*PI/th)/360);
#endif
// Calculate the maximum angle between segments based on the error rate.
float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/outerRadius, 2) - 1);
segments = (endAngle - startAngle)*ceilf(2*PI/th)/360;
if (segments <= 0) segments = 4; if (segments <= 0) segments = 4;
} }
@ -569,7 +558,7 @@ void DrawRingLines(Vector2 center, float innerRadius, float outerRadius, int sta
} }
float stepLength = (float)(endAngle - startAngle)/(float)segments; float stepLength = (float)(endAngle - startAngle)/(float)segments;
float angle = startAngle; float angle = (float)startAngle;
bool showCapLines = true; bool showCapLines = true;
int limit = 4*(segments + 1); int limit = 4*(segments + 1);
@ -629,6 +618,8 @@ void DrawRectangleRec(Rectangle rec, Color color)
// Draw a color-filled rectangle with pro parameters // Draw a color-filled rectangle with pro parameters
void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color) void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color)
{ {
if (rlCheckBufferLimit(4)) rlglDraw();
rlEnableTexture(GetShapesTexture().id); rlEnableTexture(GetShapesTexture().id);
rlPushMatrix(); rlPushMatrix();
@ -764,13 +755,9 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co
// Calculate number of segments to use for the corners // Calculate number of segments to use for the corners
if (segments < 4) if (segments < 4)
{ {
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088 // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
#ifndef CIRCLE_ERROR_RATE float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
#define CIRCLE_ERROR_RATE 0.5f segments = (int)(ceilf(2*PI/th)/4.0f);
#endif
// Calculate the maximum angle between segments based on the error rate.
float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = ceilf(2*PI/th)/4;
if (segments <= 0) segments = 4; if (segments <= 0) segments = 4;
} }
@ -988,13 +975,9 @@ void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, int
// Calculate number of segments to use for the corners // Calculate number of segments to use for the corners
if (segments < 4) if (segments < 4)
{ {
// Calculate how many segments we need to draw a smooth circle, taken from https://stackoverflow.com/a/2244088 // Calculate the maximum angle between segments based on the error rate (usually 0.5f)
#ifndef CIRCLE_ERROR_RATE float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1);
#define CIRCLE_ERROR_RATE 0.5f segments = (int)(ceilf(2*PI/th)/2.0f);
#endif
// Calculate the maximum angle between segments based on the error rate.
float th = acosf(2*powf(1 - CIRCLE_ERROR_RATE/radius, 2) - 1);
segments = ceilf(2*PI/th)/2;
if (segments <= 0) segments = 4; if (segments <= 0) segments = 4;
} }
@ -1263,6 +1246,7 @@ void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
// Draw a triangle fan defined by points // Draw a triangle fan defined by points
// NOTE: First vertex provided is the center, shared by all triangles // NOTE: First vertex provided is the center, shared by all triangles
// By default, following vertex should be provided in counter-clockwise order
void DrawTriangleFan(Vector2 *points, int pointsCount, Color color) void DrawTriangleFan(Vector2 *points, int pointsCount, Color color)
{ {
if (pointsCount >= 3) if (pointsCount >= 3)
@ -1298,7 +1282,7 @@ void DrawTriangleStrip(Vector2 *points, int pointsCount, Color color)
{ {
if (pointsCount >= 3) if (pointsCount >= 3)
{ {
if (rlCheckBufferLimit(pointsCount)) rlglDraw(); if (rlCheckBufferLimit(3*(pointsCount - 2))) rlglDraw();
rlBegin(RL_TRIANGLES); rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);

View file

@ -16,7 +16,7 @@
* #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH * #define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH
* TextSplit() function static buffer max size * TextSplit() function static buffer max size
* *
* #define TEXTSPLIT_MAX_SUBSTRINGS_COUNT * #define MAX_TEXTSPLIT_COUNT
* TextSplit() function static substrings pointers array (pointing to static buffer) * TextSplit() function static substrings pointers array (pointing to static buffer)
* *
* *
@ -54,12 +54,12 @@
#endif #endif
#include <stdlib.h> // Required for: malloc(), free() #include <stdlib.h> // Required for: malloc(), free()
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fgets() #include <stdio.h> // Required for: vsprintf()
#include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy(), strcat(), strncat(), sscanf() #include <string.h> // Required for: strcmp(), strstr(), strcpy(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()]
#include <stdarg.h> // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()] #include <stdarg.h> // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()]
#include <ctype.h> // Requried for: toupper(), tolower() [Used in TextToUpper(), TextToLower()] #include <ctype.h> // Requried for: toupper(), tolower() [Used in TextToUpper(), TextToLower()]
#include "utils.h" // Required for: fopen() Android mapping #include "utils.h" // Required for: LoadFileText()
#if defined(SUPPORT_FILEFORMAT_TTF) #if defined(SUPPORT_FILEFORMAT_TTF)
#define STB_RECT_PACK_IMPLEMENTATION #define STB_RECT_PACK_IMPLEMENTATION
@ -73,17 +73,15 @@
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Defines and Macros // Defines and Macros
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions: #ifndef MAX_TEXT_BUFFER_LENGTH
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal() #define MAX_TEXT_BUFFER_LENGTH 1024 // Size of internal static buffers used on some functions:
// TextFormat(), TextSubtext(), TextToUpper(), TextToLower(), TextToPascal(), TextSplit()
#define MAX_TEXT_UNICODE_CHARS 512 // Maximum number of unicode codepoints
#if !defined(TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH)
#define TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH 1024 // Size of static buffer: TextSplit()
#endif #endif
#ifndef MAX_TEXT_UNICODE_CHARS
#if !defined(TEXTSPLIT_MAX_SUBSTRINGS_COUNT) #define MAX_TEXT_UNICODE_CHARS 512 // Maximum number of unicode codepoints: GetCodepoints()
#define TEXTSPLIT_MAX_SUBSTRINGS_COUNT 128 // Size of static pointers array: TextSplit() #endif
#ifndef MAX_TEXTSPLIT_COUNT
#define MAX_TEXTSPLIT_COUNT 128 // Maximum number of substrings to split: TextSplit()
#endif #endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -95,8 +93,9 @@
// Global variables // Global variables
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(SUPPORT_DEFAULT_FONT) #if defined(SUPPORT_DEFAULT_FONT)
static Font defaultFont = { 0 }; // Default font provided by raylib // Default font provided by raylib
// NOTE: defaultFont is loaded on InitWindow and disposed on CloseWindow [module: core] // NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core]
static Font defaultFont = { 0 };
#endif #endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -192,33 +191,31 @@ extern void LoadFontDefault(void)
// Re-construct image from defaultFontData and generate OpenGL texture // Re-construct image from defaultFontData and generate OpenGL texture
//---------------------------------------------------------------------- //----------------------------------------------------------------------
int imWidth = 128; Image imFont = {
int imHeight = 128; .data = calloc(128*128, 2), // 2 bytes per pixel (gray + alpha)
.width = 128,
.height = 128,
.format = UNCOMPRESSED_GRAY_ALPHA,
.mipmaps = 1
};
Color *imagePixels = (Color *)RL_MALLOC(imWidth*imHeight*sizeof(Color)); // Fill image.data with defaultFontData (convert from bit to pixel!)
for (int i = 0, counter = 0; i < imFont.width*imFont.height; i += 32)
for (int i = 0; i < imWidth*imHeight; i++) imagePixels[i] = BLANK; // Initialize array
int counter = 0; // Font data elements counter
// Fill imgData with defaultFontData (convert from bit to pixel!)
for (int i = 0; i < imWidth*imHeight; i += 32)
{ {
for (int j = 31; j >= 0; j--) for (int j = 31; j >= 0; j--)
{ {
if (BIT_CHECK(defaultFontData[counter], j)) imagePixels[i+j] = WHITE; if (BIT_CHECK(defaultFontData[counter], j))
{
// NOTE: We are unreferencing data as short, so,
// we must consider data as little-endian order (alpha + gray)
((unsigned short *)imFont.data)[i + j] = 0xffff;
}
else ((unsigned short *)imFont.data)[i + j] = 0x00ff;
} }
counter++; counter++;
if (counter > 512) counter = 0; // Security check...
} }
Image imFont = LoadImageEx(imagePixels, imWidth, imHeight);
ImageFormat(&imFont, UNCOMPRESSED_GRAY_ALPHA);
RL_FREE(imagePixels);
defaultFont.texture = LoadTextureFromImage(imFont); defaultFont.texture = LoadTextureFromImage(imFont);
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount
@ -295,15 +292,21 @@ Font GetFontDefault()
// Load Font from file into GPU memory (VRAM) // Load Font from file into GPU memory (VRAM)
Font LoadFont(const char *fileName) Font LoadFont(const char *fileName)
{ {
// Default hardcoded values for ttf file loading // Default values for ttf font generation
#define DEFAULT_TTF_FONTSIZE 32 // Font first character (32 - space) #ifndef FONT_TTF_DEFAULT_SIZE
#define DEFAULT_TTF_NUMCHARS 95 // ASCII 32..126 is 95 glyphs #define FONT_TTF_DEFAULT_SIZE 32 // TTF font generation default char size (char-height)
#define DEFAULT_FIRST_CHAR 32 // Expected first char for image sprite font #endif
#ifndef FONT_TTF_DEFAULT_NUMCHARS
#define FONT_TTF_DEFAULT_NUMCHARS 95 // TTF font generation default charset: 95 glyphs (ASCII 32..126)
#endif
#ifndef FONT_TTF_DEFAULT_FIRST_CHAR
#define FONT_TTF_DEFAULT_FIRST_CHAR 32 // TTF font generation default first char for image sprite font (32-Space)
#endif
Font font = { 0 }; Font font = { 0 };
#if defined(SUPPORT_FILEFORMAT_TTF) #if defined(SUPPORT_FILEFORMAT_TTF)
if (IsFileExtension(fileName, ".ttf;.otf")) font = LoadFontEx(fileName, DEFAULT_TTF_FONTSIZE, NULL, DEFAULT_TTF_NUMCHARS); if (IsFileExtension(fileName, ".ttf;.otf")) font = LoadFontEx(fileName, FONT_TTF_DEFAULT_SIZE, NULL, FONT_TTF_DEFAULT_NUMCHARS);
else else
#endif #endif
#if defined(SUPPORT_FILEFORMAT_FNT) #if defined(SUPPORT_FILEFORMAT_FNT)
@ -312,7 +315,7 @@ Font LoadFont(const char *fileName)
#endif #endif
{ {
Image image = LoadImage(fileName); Image image = LoadImage(fileName);
if (image.data != NULL) font = LoadFontFromImage(image, MAGENTA, DEFAULT_FIRST_CHAR); if (image.data != NULL) font = LoadFontFromImage(image, MAGENTA, FONT_TTF_DEFAULT_FIRST_CHAR);
UnloadImage(image); UnloadImage(image);
} }
@ -363,6 +366,10 @@ Font LoadFontEx(const char *fileName, int fontSize, int *fontChars, int charsCou
// Load an Image font file (XNA style) // Load an Image font file (XNA style)
Font LoadFontFromImage(Image image, Color key, int firstChar) Font LoadFontFromImage(Image image, Color key, int firstChar)
{ {
#ifndef MAX_GLYPHS_FROM_IMAGE
#define MAX_GLYPHS_FROM_IMAGE 256 // Maximum number of glyphs supported on image scan
#endif
#define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a)) #define COLOR_EQUAL(col1, col2) ((col1.r == col2.r)&&(col1.g == col2.g)&&(col1.b == col2.b)&&(col1.a == col2.a))
int charSpacing = 0; int charSpacing = 0;
@ -371,13 +378,10 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
int x = 0; int x = 0;
int y = 0; int y = 0;
// Default number of characters supported
#define MAX_FONTCHARS 256
// We allocate a temporal arrays for chars data measures, // We allocate a temporal arrays for chars data measures,
// once we get the actual number of chars, we copy data to a sized arrays // once we get the actual number of chars, we copy data to a sized arrays
int tempCharValues[MAX_FONTCHARS]; int tempCharValues[MAX_GLYPHS_FROM_IMAGE];
Rectangle tempCharRecs[MAX_FONTCHARS]; Rectangle tempCharRecs[MAX_GLYPHS_FROM_IMAGE];
Color *pixels = GetImageData(image); Color *pixels = GetImageData(image);
@ -439,9 +443,13 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK; for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK;
// Create a new image with the processed color data (key color replaced by BLANK) // Create a new image with the processed color data (key color replaced by BLANK)
Image fontClear = LoadImageEx(pixels, image.width, image.height); Image fontClear = {
.data = pixels,
RL_FREE(pixels); // Free pixels array memory .width = image.width,
.height = image.height,
.format = UNCOMPRESSED_R8G8B8A8,
.mipmaps = 1
};
// Create spritefont with all data parsed from image // Create spritefont with all data parsed from image
Font font = { 0 }; Font font = { 0 };
@ -483,11 +491,18 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
{ {
// NOTE: Using some SDF generation default values, // NOTE: Using some SDF generation default values,
// trades off precision with ability to handle *smaller* sizes // trades off precision with ability to handle *smaller* sizes
#define SDF_CHAR_PADDING 4 #ifndef FONT_SDF_CHAR_PADDING
#define SDF_ON_EDGE_VALUE 128 #define FONT_SDF_CHAR_PADDING 4 // SDF font generation char padding
#define SDF_PIXEL_DIST_SCALE 64.0f #endif
#ifndef FONT_SDF_ON_EDGE_VALUE
#define BITMAP_ALPHA_THRESHOLD 80 #define FONT_SDF_ON_EDGE_VALUE 128 // SDF font generation on edge value
#endif
#ifndef FONT_SDF_PIXEL_DIST_SCALE
#define FONT_SDF_PIXEL_DIST_SCALE 64.0f // SDF font generation pixel distance scale
#endif
#ifndef FONT_BITMAP_ALPHA_THRESHOLD
#define FONT_BITMAP_ALPHA_THRESHOLD 80 // Bitmap (B&W) font generation alpha threshold
#endif
CharInfo *chars = NULL; CharInfo *chars = NULL;
@ -541,7 +556,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide // stbtt_MakeCodepointBitmap() -- renders into bitmap you provide
if (type != FONT_SDF) chars[i].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); if (type != FONT_SDF) chars[i].image.data = stbtt_GetCodepointBitmap(&fontInfo, scaleFactor, scaleFactor, ch, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
else if (ch != 32) chars[i].image.data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, SDF_CHAR_PADDING, SDF_ON_EDGE_VALUE, SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY); else if (ch != 32) chars[i].image.data = stbtt_GetCodepointSDF(&fontInfo, scaleFactor, ch, FONT_SDF_CHAR_PADDING, FONT_SDF_ON_EDGE_VALUE, FONT_SDF_PIXEL_DIST_SCALE, &chw, &chh, &chars[i].offsetX, &chars[i].offsetY);
else chars[i].image.data = NULL; else chars[i].image.data = NULL;
stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL); stbtt_GetCodepointHMetrics(&fontInfo, ch, &chars[i].advanceX, NULL);
@ -558,8 +573,15 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
// NOTE: We create an empty image for space character, it could be further required for atlas packing // NOTE: We create an empty image for space character, it could be further required for atlas packing
if (ch == 32) if (ch == 32)
{ {
chars[i].image = GenImageColor(chars[i].advanceX, fontSize, BLANK); Image imSpace = {
ImageFormat(&chars[i].image, UNCOMPRESSED_GRAYSCALE); .data = calloc(chars[i].advanceX*fontSize, 2),
.width = chars[i].advanceX,
.height = fontSize,
.format = UNCOMPRESSED_GRAYSCALE,
.mipmaps = 1
};
chars[i].image = imSpace;
} }
if (type == FONT_BITMAP) if (type == FONT_BITMAP)
@ -568,7 +590,7 @@ CharInfo *LoadFontData(const char *fileName, int fontSize, int *fontChars, int c
// NOTE: For optimum results, bitmap font should be generated at base pixel size // NOTE: For optimum results, bitmap font should be generated at base pixel size
for (int p = 0; p < chw*chh; p++) for (int p = 0; p < chw*chh; p++)
{ {
if (((unsigned char *)chars[i].image.data)[p] < BITMAP_ALPHA_THRESHOLD) ((unsigned char *)chars[i].image.data)[p] = 0; if (((unsigned char *)chars[i].image.data)[p] < FONT_BITMAP_ALPHA_THRESHOLD) ((unsigned char *)chars[i].image.data)[p] = 0;
else ((unsigned char *)chars[i].image.data)[p] = 255; else ((unsigned char *)chars[i].image.data)[p] = 255;
} }
} }
@ -600,6 +622,12 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
{ {
Image atlas = { 0 }; Image atlas = { 0 };
if (chars == NULL)
{
TraceLog(LOG_WARNING, "FONT: Provided chars info not valid, returning empty image atlas");
return atlas;
}
*charRecs = NULL; *charRecs = NULL;
// In case no chars count provided we suppose default of 95 // In case no chars count provided we suppose default of 95
@ -652,7 +680,7 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
// Move atlas position X for next character drawing // Move atlas position X for next character drawing
offsetX += (chars[i].image.width + 2*padding); offsetX += (chars[i].image.width + 2*padding);
if (offsetX >= (atlas.width - chars[i].image.width - padding)) if (offsetX >= (atlas.width - chars[i].image.width - 2*padding))
{ {
offsetX = padding; offsetX = padding;
@ -714,7 +742,6 @@ Image GenImageFontAtlas(const CharInfo *chars, Rectangle **charRecs, int charsCo
// TODO: Crop image if required for smaller size // TODO: Crop image if required for smaller size
// Convert image data from GRAYSCALE to GRAY_ALPHA // Convert image data from GRAYSCALE to GRAY_ALPHA
// WARNING: ImageAlphaMask(&atlas, atlas) does not work in this case, requires manual operation
unsigned char *dataGrayAlpha = (unsigned char *)RL_MALLOC(atlas.width*atlas.height*sizeof(unsigned char)*2); // Two channels unsigned char *dataGrayAlpha = (unsigned char *)RL_MALLOC(atlas.width*atlas.height*sizeof(unsigned char)*2); // Two channels
for (int i = 0, k = 0; i < atlas.width*atlas.height; i++, k += 2) for (int i = 0, k = 0; i < atlas.width*atlas.height; i++, k += 2)
@ -799,7 +826,7 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor float scaleFactor = fontSize/font.baseSize; // Character quad scaling factor
for (int i = 0; i < length; i++) for (int i = 0; i < length;)
{ {
// Get next codepoint from byte string and glyph index in font // Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0; int codepointByteCount = 0;
@ -833,7 +860,7 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f
else textOffsetX += ((float)font.chars[index].advanceX*scaleFactor + spacing); else textOffsetX += ((float)font.chars[index].advanceX*scaleFactor + spacing);
} }
i += (codepointByteCount - 1); // Move text bytes counter to next codepoint i += codepointByteCount; // Move text bytes counter to next codepoint
} }
} }
@ -945,7 +972,7 @@ void DrawTextRecEx(Font font, const char *text, Rectangle rec, float fontSize, f
bool isGlyphSelected = false; bool isGlyphSelected = false;
if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength))) if ((selectStart >= 0) && (k >= selectStart) && (k < (selectStart + selectLength)))
{ {
DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, glyphWidth, (int)((float)font.baseSize*scaleFactor) }, selectBackTint); DrawRectangleRec((Rectangle){ rec.x + textOffsetX - 1, rec.y + textOffsetY, (float)glyphWidth, (float)font.baseSize*scaleFactor }, selectBackTint);
isGlyphSelected = true; isGlyphSelected = true;
} }
@ -1053,11 +1080,14 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
// Returns index position for a unicode character on spritefont // Returns index position for a unicode character on spritefont
int GetGlyphIndex(Font font, int codepoint) int GetGlyphIndex(Font font, int codepoint)
{ {
#define TEXT_CHARACTER_NOTFOUND 63 // Character: '?' #ifndef GLYPH_NOTFOUND_CHAR_FALLBACK
#define GLYPH_NOTFOUND_CHAR_FALLBACK 63 // Character used if requested codepoint is not found: '?'
#endif
#define UNORDERED_CHARSET // Support charsets with any characters order
#if defined(UNORDERED_CHARSET) #define SUPPORT_UNORDERED_CHARSET
int index = TEXT_CHARACTER_NOTFOUND; #if defined(SUPPORT_UNORDERED_CHARSET)
int index = GLYPH_NOTFOUND_CHAR_FALLBACK;
for (int i = 0; i < font.charsCount; i++) for (int i = 0; i < font.charsCount; i++)
{ {
@ -1077,7 +1107,64 @@ int GetGlyphIndex(Font font, int codepoint)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Text strings management functions // Text strings management functions
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Get text length in bytes, check for \0 character
unsigned int TextLength(const char *text)
{
unsigned int length = 0; //strlen(text)
if (text != NULL)
{
while (*text++) length++;
}
return length;
}
// Formatting of text with variables to 'embed'
// WARNING: String returned will expire after this function is called MAX_TEXTFORMAT_BUFFERS times
const char *TextFormat(const char *text, ...)
{
#ifndef MAX_TEXTFORMAT_BUFFERS
#define MAX_TEXTFORMAT_BUFFERS 4 // Maximum number of static buffers for text formatting
#endif
// We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations
static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 };
static int index = 0;
char *currentBuffer = buffers[index];
memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using
va_list args;
va_start(args, text);
vsprintf(currentBuffer, text, args);
va_end(args);
index += 1; // Move to next buffer for next function call
if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
return currentBuffer;
}
// Get integer value from text
// NOTE: This function replaces atoi() [stdlib.h]
int TextToInteger(const char *text)
{
int value = 0;
int sign = 1;
if ((text[0] == '+') || (text[0] == '-'))
{
if (text[0] == '-') sign = -1;
text++;
}
for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0');
return value*sign;
}
#if defined(SUPPORT_TEXT_MANIPULATION)
// Copy one string to another, returns bytes copied // Copy one string to another, returns bytes copied
int TextCopy(char *dst, const char *src) int TextCopy(char *dst, const char *src)
{ {
@ -1111,43 +1198,6 @@ bool TextIsEqual(const char *text1, const char *text2)
return result; return result;
} }
// Get text length in bytes, check for \0 character
unsigned int TextLength(const char *text)
{
unsigned int length = 0; //strlen(text)
if (text != NULL)
{
while (*text++) length++;
}
return length;
}
// Formatting of text with variables to 'embed'
// WARNING: String returned will expire after this function is called MAX_TEXTFORMAT_BUFFERS times
const char *TextFormat(const char *text, ...)
{
#define MAX_TEXTFORMAT_BUFFERS 4
// We create an array of buffers so strings don't expire until MAX_TEXTFORMAT_BUFFERS invocations
static char buffers[MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH] = { 0 };
static int index = 0;
char *currentBuffer = buffers[index];
memset(currentBuffer, 0, MAX_TEXT_BUFFER_LENGTH); // Clear buffer before using
va_list args;
va_start(args, text);
vsprintf(currentBuffer, text, args);
va_end(args);
index += 1; // Move to next buffer for next function call
if (index >= MAX_TEXTFORMAT_BUFFERS) index = 0;
return currentBuffer;
}
// Get a piece of a text string // Get a piece of a text string
const char *TextSubtext(const char *text, int position, int length) const char *TextSubtext(const char *text, int position, int length)
{ {
@ -1179,6 +1229,9 @@ const char *TextSubtext(const char *text, int position, int length)
// WARNING: Internally allocated memory must be freed by the user (if return != NULL) // WARNING: Internally allocated memory must be freed by the user (if return != NULL)
char *TextReplace(char *text, const char *replace, const char *by) char *TextReplace(char *text, const char *replace, const char *by)
{ {
// Sanity checks and initialization
if (!text || !replace || !by) return NULL;
char *result; char *result;
char *insertPoint; // Next insert point char *insertPoint; // Next insert point
@ -1188,13 +1241,9 @@ char *TextReplace(char *text, const char *replace, const char *by)
int lastReplacePos; // Distance between replace and end of last replace int lastReplacePos; // Distance between replace and end of last replace
int count; // Number of replacements int count; // Number of replacements
// Sanity checks and initialization
if (!text || !replace) return NULL;
replaceLen = TextLength(replace); replaceLen = TextLength(replace);
if (replaceLen == 0) return NULL; // Empty replace causes infinite loop during count if (replaceLen == 0) return NULL; // Empty replace causes infinite loop during count
if (!by) by = ""; // Replace by nothing if not provided
byLen = TextLength(by); byLen = TextLength(by);
// Count the number of replacements needed // Count the number of replacements needed
@ -1213,7 +1262,7 @@ char *TextReplace(char *text, const char *replace, const char *by)
while (count--) while (count--)
{ {
insertPoint = strstr(text, replace); insertPoint = strstr(text, replace);
lastReplacePos = insertPoint - text; lastReplacePos = (int)(insertPoint - text);
temp = strncpy(temp, text, lastReplacePos) + lastReplacePos; temp = strncpy(temp, text, lastReplacePos) + lastReplacePos;
temp = strcpy(temp, by) + byLen; temp = strcpy(temp, by) + byLen;
text += lastReplacePos + replaceLen; // Move to next "end of replace" text += lastReplacePos + replaceLen; // Move to next "end of replace"
@ -1244,29 +1293,32 @@ char *TextInsert(const char *text, const char *insert, int position)
} }
// Join text strings with delimiter // Join text strings with delimiter
// REQUIRES: strcat() // REQUIRES: memset(), memcpy()
const char *TextJoin(const char **textList, int count, const char *delimiter) const char *TextJoin(const char **textList, int count, const char *delimiter)
{ {
static char text[MAX_TEXT_BUFFER_LENGTH] = { 0 }; static char text[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(text, 0, MAX_TEXT_BUFFER_LENGTH); memset(text, 0, MAX_TEXT_BUFFER_LENGTH);
char *textPtr = text;
int totalLength = 0; int totalLength = 0;
int delimiterLen = TextLength(delimiter); int delimiterLen = TextLength(delimiter);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
int textListLength = TextLength(textList[i]); int textLength = TextLength(textList[i]);
// Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH // Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH
if ((totalLength + textListLength) < MAX_TEXT_BUFFER_LENGTH) if ((totalLength + textLength) < MAX_TEXT_BUFFER_LENGTH)
{ {
strcat(text, textList[i]); memcpy(textPtr, textList[i], textLength);
totalLength += textListLength; totalLength += textLength;
textPtr += textLength;
if ((delimiterLen > 0) && (i < (count - 1))) if ((delimiterLen > 0) && (i < (count - 1)))
{ {
strcat(text, delimiter); memcpy(textPtr, delimiter, delimiterLen);
totalLength += delimiterLen; totalLength += delimiterLen;
textPtr += delimiterLen;
} }
} }
} }
@ -1280,12 +1332,12 @@ const char **TextSplit(const char *text, char delimiter, int *count)
// NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter)
// inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated,
// all used memory is static... it has some limitations: // all used memory is static... it has some limitations:
// 1. Maximum number of possible split strings is set by TEXTSPLIT_MAX_SUBSTRINGS_COUNT // 1. Maximum number of possible split strings is set by MAX_TEXTSPLIT_COUNT
// 2. Maximum size of text to split is TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH // 2. Maximum size of text to split is MAX_TEXT_BUFFER_LENGTH
static const char *result[TEXTSPLIT_MAX_SUBSTRINGS_COUNT] = { NULL }; static const char *result[MAX_TEXTSPLIT_COUNT] = { NULL };
static char buffer[TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH] = { 0 }; static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 };
memset(buffer, 0, TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH); memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH);
result[0] = buffer; result[0] = buffer;
int counter = 0; int counter = 0;
@ -1295,7 +1347,7 @@ const char **TextSplit(const char *text, char delimiter, int *count)
counter = 1; counter = 1;
// Count how many substrings we have on text and point to every one // Count how many substrings we have on text and point to every one
for (int i = 0; i < TEXTSPLIT_MAX_TEXT_BUFFER_LENGTH; i++) for (int i = 0; i < MAX_TEXT_BUFFER_LENGTH; i++)
{ {
buffer[i] = text[i]; buffer[i] = text[i];
if (buffer[i] == '\0') break; if (buffer[i] == '\0') break;
@ -1305,7 +1357,7 @@ const char **TextSplit(const char *text, char delimiter, int *count)
result[counter] = buffer + i + 1; result[counter] = buffer + i + 1;
counter++; counter++;
if (counter == TEXTSPLIT_MAX_SUBSTRINGS_COUNT) break; if (counter == MAX_TEXTSPLIT_COUNT) break;
} }
} }
} }
@ -1330,7 +1382,7 @@ int TextFindIndex(const char *text, const char *find)
char *ptr = strstr(text, find); char *ptr = strstr(text, find);
if (ptr != NULL) position = ptr - text; if (ptr != NULL) position = (int)(ptr - text);
return position; return position;
} }
@ -1398,24 +1450,6 @@ const char *TextToPascal(const char *text)
return buffer; return buffer;
} }
// Get integer value from text
// NOTE: This function replaces atoi() [stdlib.h]
int TextToInteger(const char *text)
{
int value = 0;
int sign = 1;
if ((text[0] == '+') || (text[0] == '-'))
{
if (text[0] == '-') sign = -1;
text++;
}
for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); ++i) value = value*10 + (int)(text[i] - '0');
return value*sign;
}
// Encode text codepoint into utf8 text (memory must be freed!) // Encode text codepoint into utf8 text (memory must be freed!)
char *TextToUtf8(int *codepoints, int length) char *TextToUtf8(int *codepoints, int length)
{ {
@ -1428,7 +1462,7 @@ char *TextToUtf8(int *codepoints, int length)
for (int i = 0, bytes = 0; i < length; i++) for (int i = 0, bytes = 0; i < length; i++)
{ {
utf8 = CodepointToUtf8(codepoints[i], &bytes); utf8 = CodepointToUtf8(codepoints[i], &bytes);
strncpy(text + size, utf8, bytes); memcpy(text + size, utf8, bytes);
size += bytes; size += bytes;
} }
@ -1440,6 +1474,44 @@ char *TextToUtf8(int *codepoints, int length)
return text; return text;
} }
// Encode codepoint into utf8 text (char array length returned as parameter)
RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength)
{
static char utf8[6] = { 0 };
int length = 0;
if (codepoint <= 0x7f)
{
utf8[0] = (char)codepoint;
length = 1;
}
else if (codepoint <= 0x7ff)
{
utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
utf8[1] = (char)((codepoint & 0x3f) | 0x80);
length = 2;
}
else if (codepoint <= 0xffff)
{
utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
utf8[2] = (char)((codepoint & 0x3f) | 0x80);
length = 3;
}
else if (codepoint <= 0x10ffff)
{
utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0);
utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
utf8[3] = (char)((codepoint & 0x3f) | 0x80);
length = 4;
}
*byteLength = length;
return utf8;
}
// Get all codepoints in a string, codepoints count returned by parameters // Get all codepoints in a string, codepoints count returned by parameters
int *GetCodepoints(const char *text, int *count) int *GetCodepoints(const char *text, int *count)
{ {
@ -1481,7 +1553,7 @@ int GetCodepointsCount(const char *text)
return len; return len;
} }
#endif // SUPPORT_TEXT_MANIPULATION
// Returns next codepoint in a UTF8 encoded text, scanning until '\0' is found // Returns next codepoint in a UTF8 encoded text, scanning until '\0' is found
// When a invalid UTF8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned // When a invalid UTF8 byte is encountered we exit as soon as possible and a '?'(0x3f) codepoint is returned
@ -1595,50 +1667,23 @@ int GetNextCodepoint(const char *text, int *bytesProcessed)
return code; return code;
} }
// Encode codepoint into utf8 text (char array length returned as parameter)
RLAPI const char *CodepointToUtf8(int codepoint, int *byteLength)
{
static char utf8[6] = { 0 };
int length = 0;
if (codepoint <= 0x7f)
{
utf8[0] = (char)codepoint;
length = 1;
}
else if (codepoint <= 0x7ff)
{
utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0);
utf8[1] = (char)((codepoint & 0x3f) | 0x80);
length = 2;
}
else if (codepoint <= 0xffff)
{
utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0);
utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
utf8[2] = (char)((codepoint & 0x3f) | 0x80);
length = 3;
}
else if (codepoint <= 0x10ffff)
{
utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0);
utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80);
utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80);
utf8[3] = (char)((codepoint & 0x3f) | 0x80);
length = 4;
}
*byteLength = length;
return utf8;
}
//----------------------------------------------------------------------------------
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Definition // Module specific Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
#if defined(SUPPORT_FILEFORMAT_FNT) #if defined(SUPPORT_FILEFORMAT_FNT)
// Read a line from memory
// NOTE: Returns the number of bytes read
static int GetLine(const char *origin, char *buffer, int maxLength)
{
int count = 0;
for (; count < maxLength; count++) if (origin[count] == '\n') break;
memcpy(buffer, origin, count);
return count;
}
// Load a BMFont file (AngelCode font file) // Load a BMFont file (AngelCode font file)
// REQUIRES: strstr(), sscanf(), strrchr(), memcpy()
static Font LoadBMFont(const char *fileName) static Font LoadBMFont(const char *fileName)
{ {
#define MAX_BUFFER_SIZE 256 #define MAX_BUFFER_SIZE 256
@ -1649,80 +1694,92 @@ static Font LoadBMFont(const char *fileName)
char *searchPoint = NULL; char *searchPoint = NULL;
int fontSize = 0; int fontSize = 0;
int texWidth = 0;
int texHeight = 0;
char texFileName[129];
int charsCount = 0; int charsCount = 0;
int imWidth = 0;
int imHeight = 0;
char imFileName[129];
int base = 0; // Useless data int base = 0; // Useless data
FILE *fntFile = NULL; char *fileText = LoadFileText(fileName);
fntFile = fopen(fileName, "rt"); if (fileText == NULL) return font;
if (fntFile == NULL)
{
TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open FNT file", fileName);
return font;
}
char *fileTextPtr = fileText;
// NOTE: We skip first line, it contains no useful information // NOTE: We skip first line, it contains no useful information
fgets(buffer, MAX_BUFFER_SIZE, fntFile); int lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
//searchPoint = strstr(buffer, "size"); fileTextPtr += (lineBytes + 1);
//sscanf(searchPoint, "size=%i", &fontSize);
fgets(buffer, MAX_BUFFER_SIZE, fntFile); // Read line data
lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
searchPoint = strstr(buffer, "lineHeight"); searchPoint = strstr(buffer, "lineHeight");
sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &texWidth, &texHeight); sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &imWidth, &imHeight);
fileTextPtr += (lineBytes + 1);
TRACELOGD("FONT: [%s] Loaded font info:", fileName); TRACELOGD("FONT: [%s] Loaded font info:", fileName);
TRACELOGD(" > Base size: %i", fontSize); TRACELOGD(" > Base size: %i", fontSize);
TRACELOGD(" > Texture scale: %ix%i", texWidth, texHeight); TRACELOGD(" > Texture scale: %ix%i", imWidth, imHeight);
fgets(buffer, MAX_BUFFER_SIZE, fntFile); lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
searchPoint = strstr(buffer, "file"); searchPoint = strstr(buffer, "file");
sscanf(searchPoint, "file=\"%128[^\"]\"", texFileName); sscanf(searchPoint, "file=\"%128[^\"]\"", imFileName);
fileTextPtr += (lineBytes + 1);
TRACELOGD(" > Texture filename: %s", texFileName); TRACELOGD(" > Texture filename: %s", imFileName);
fgets(buffer, MAX_BUFFER_SIZE, fntFile); lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
searchPoint = strstr(buffer, "count"); searchPoint = strstr(buffer, "count");
sscanf(searchPoint, "count=%i", &charsCount); sscanf(searchPoint, "count=%i", &charsCount);
fileTextPtr += (lineBytes + 1);
TRACELOGD(" > Chars count: %i", charsCount); TRACELOGD(" > Chars count: %i", charsCount);
// Compose correct path using route of .fnt file (fileName) and texFileName // Compose correct path using route of .fnt file (fileName) and imFileName
char *texPath = NULL; char *imPath = NULL;
char *lastSlash = NULL; char *lastSlash = NULL;
lastSlash = strrchr(fileName, '/'); lastSlash = strrchr(fileName, '/');
if (lastSlash == NULL) if (lastSlash == NULL) lastSlash = strrchr(fileName, '\\');
if (lastSlash != NULL)
{ {
lastSlash = strrchr(fileName, '\\'); // NOTE: We need some extra space to avoid memory corruption on next allocations!
imPath = RL_CALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(imFileName) + 4, 1);
memcpy(imPath, fileName, TextLength(fileName) - TextLength(lastSlash) + 1);
memcpy(imPath + TextLength(fileName) - TextLength(lastSlash) + 1, imFileName, TextLength(imFileName));
} }
else imPath = imFileName;
// NOTE: We need some extra space to avoid memory corruption on next allocations! TRACELOGD(" > Image loading path: %s", imPath);
texPath = RL_MALLOC(TextLength(fileName) - TextLength(lastSlash) + TextLength(texFileName) + 4);
// NOTE: strcat() and strncat() required a '\0' terminated string to work! Image imFont = LoadImage(imPath);
*texPath = '\0';
strncat(texPath, fileName, TextLength(fileName) - TextLength(lastSlash) + 1);
strncat(texPath, texFileName, TextLength(texFileName));
TRACELOGD(" > Texture loading path: %s", texPath);
Image imFont = LoadImage(texPath);
if (imFont.format == UNCOMPRESSED_GRAYSCALE) if (imFont.format == UNCOMPRESSED_GRAYSCALE)
{ {
// Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel // Convert image to GRAYSCALE + ALPHA, using the mask as the alpha channel
ImageAlphaMask(&imFont, imFont); Image imFontAlpha = {
for (int p = 0; p < (imFont.width*imFont.height*2); p += 2) ((unsigned char *)(imFont.data))[p] = 0xff; .data = calloc(imFont.width*imFont.height, 2),
.width = imFont.width,
.height = imFont.height,
.format = UNCOMPRESSED_GRAY_ALPHA,
.mipmaps = 1
};
for (int p = 0, i = 0; p < (imFont.width*imFont.height*2); p += 2, i++)
{
((unsigned char *)(imFontAlpha.data))[p] = 0xff;
((unsigned char *)(imFontAlpha.data))[p + 1] = ((unsigned char *)imFont.data)[i];
}
UnloadImage(imFont);
imFont = imFontAlpha;
} }
font.texture = LoadTextureFromImage(imFont); font.texture = LoadTextureFromImage(imFont);
RL_FREE(texPath); if (lastSlash != NULL) RL_FREE(imPath);
// Fill font characters info data // Fill font characters info data
font.baseSize = fontSize; font.baseSize = fontSize;
@ -1734,9 +1791,10 @@ static Font LoadBMFont(const char *fileName)
for (int i = 0; i < charsCount; i++) for (int i = 0; i < charsCount; i++)
{ {
fgets(buffer, MAX_BUFFER_SIZE, fntFile); lineBytes = GetLine(fileTextPtr, buffer, MAX_BUFFER_SIZE);
sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i", sscanf(buffer, "char id=%i x=%i y=%i width=%i height=%i xoffset=%i yoffset=%i xadvance=%i",
&charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX); &charId, &charX, &charY, &charWidth, &charHeight, &charOffsetX, &charOffsetY, &charAdvanceX);
fileTextPtr += (lineBytes + 1);
// Get character rectangle in the font atlas texture // Get character rectangle in the font atlas texture
font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight }; font.recs[i] = (Rectangle){ (float)charX, (float)charY, (float)charWidth, (float)charHeight };
@ -1752,8 +1810,7 @@ static Font LoadBMFont(const char *fileName)
} }
UnloadImage(imFont); UnloadImage(imFont);
RL_FREE(fileText);
fclose(fntFile);
if (font.texture.id == 0) if (font.texture.id == 0)
{ {

File diff suppressed because it is too large Load diff

View file

@ -49,27 +49,6 @@ func LoadImage(fileName string) *Image {
return v return v
} }
// LoadImageEx - Load image data from Color array data (RGBA - 32bit)
func LoadImageEx(pixels []Color, width, height int32) *Image {
cpixels := pixels[0].cptr()
cwidth := (C.int)(width)
cheight := (C.int)(height)
ret := C.LoadImageEx(cpixels, cwidth, cheight)
v := newImageFromPointer(unsafe.Pointer(&ret))
return v
}
// LoadImagePro - Load image from raw data with parameters
func LoadImagePro(data []byte, width, height int32, format PixelFormat) *Image {
cdata := unsafe.Pointer(&data[0])
cwidth := (C.int)(width)
cheight := (C.int)(height)
cformat := (C.int)(format)
ret := C.LoadImagePro(cdata, cwidth, cheight, cformat)
v := newImageFromPointer(unsafe.Pointer(&ret))
return v
}
// LoadImageRaw - Load image data from RAW file // LoadImageRaw - Load image data from RAW file
func LoadImageRaw(fileName string, width, height int32, format PixelFormat, headerSize int32) *Image { func LoadImageRaw(fileName string, width, height int32, format PixelFormat, headerSize int32) *Image {
cfileName := C.CString(fileName) cfileName := C.CString(fileName)
@ -165,6 +144,14 @@ func UpdateTexture(texture Texture2D, pixels []Color) {
C.UpdateTexture(*ctexture, cpixels) C.UpdateTexture(*ctexture, cpixels)
} }
// UpdateTextureRec - Update GPU texture rectangle with new data
func UpdateTextureRec(texture Texture2D, rec Rectangle, pixels []Color) {
ctexture := texture.cptr()
cpixels := unsafe.Pointer(&pixels[0])
crec := rec.cptr()
C.UpdateTextureRec(*ctexture, *crec, cpixels)
}
// ExportImage - Export image as a PNG file // ExportImage - Export image as a PNG file
func ExportImage(image Image, name string) { func ExportImage(image Image, name string) {
cname := C.CString(name) cname := C.CString(name)
@ -329,14 +316,15 @@ func ImageDrawRectangleLines(dst *Image, rec Rectangle, thick int, color Color)
} }
// ImageDrawText - Draw text (default font) within an image (destination) // ImageDrawText - Draw text (default font) within an image (destination)
func ImageDrawText(dst *Image, position Vector2, text string, fontSize int32, color Color) { func ImageDrawText(dst *Image, posX, posY int32, text string, fontSize int32, color Color) {
cdst := dst.cptr() cdst := dst.cptr()
cposition := position.cptr() posx := (C.int)(posX)
posy := (C.int)(posY)
ctext := C.CString(text) ctext := C.CString(text)
defer C.free(unsafe.Pointer(ctext)) defer C.free(unsafe.Pointer(ctext))
cfontSize := (C.int)(fontSize) cfontSize := (C.int)(fontSize)
ccolor := color.cptr() ccolor := color.cptr()
C.ImageDrawText(cdst, *cposition, ctext, cfontSize, *ccolor) C.ImageDrawText(cdst, ctext, posx, posy, cfontSize, *ccolor)
} }
// ImageDrawTextEx - Draw text (custom sprite font) within an image (destination) // ImageDrawTextEx - Draw text (custom sprite font) within an image (destination)
@ -349,7 +337,7 @@ func ImageDrawTextEx(dst *Image, position Vector2, font Font, text string, fontS
cfontSize := (C.float)(fontSize) cfontSize := (C.float)(fontSize)
cspacing := (C.float)(spacing) cspacing := (C.float)(spacing)
ccolor := color.cptr() ccolor := color.cptr()
C.ImageDrawTextEx(cdst, *cposition, *cfont, ctext, cfontSize, cspacing, *ccolor) C.ImageDrawTextEx(cdst, *cfont, ctext, *cposition, cfontSize, cspacing, *ccolor)
} }
// ImageFlipVertical - Flip image vertically // ImageFlipVertical - Flip image vertically

View file

@ -50,9 +50,15 @@
#include <stdarg.h> // Required for: va_list, va_start(), va_end() #include <stdarg.h> // Required for: va_list, va_start(), va_end()
#include <string.h> // Required for: strcpy(), strcat() #include <string.h> // Required for: strcpy(), strcat()
#define MAX_TRACELOG_BUFFER_SIZE 128 // Max length of one trace-log message //----------------------------------------------------------------------------------
// Defines and Macros
#define MAX_UWP_MESSAGES 512 // Max UWP messages to process //----------------------------------------------------------------------------------
#ifndef MAX_TRACELOG_MSG_LENGTH
#define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message
#endif
#ifndef MAX_UWP_MESSAGES
#define MAX_UWP_MESSAGES 512 // Max UWP messages to process
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Global Variables Definition // Global Variables Definition
@ -68,13 +74,6 @@ static AAssetManager *assetManager = NULL; // Android assets manage
static const char *internalDataPath = NULL; // Android internal data path static const char *internalDataPath = NULL; // Android internal data path
#endif #endif
#if defined(PLATFORM_UWP)
static int UWPOutMessageId = -1; // Last index of output message
static UWPMessage *UWPOutMessages[MAX_UWP_MESSAGES]; // Messages out to UWP
static int UWPInMessageId = -1; // Last index of input message
static UWPMessage *UWPInMessages[MAX_UWP_MESSAGES]; // Messages in from UWP
#endif
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module specific Functions Declaration // Module specific Functions Declaration
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -139,7 +138,7 @@ void TraceLog(int logType, const char *text, ...)
default: break; default: break;
} }
#else #else
char buffer[MAX_TRACELOG_BUFFER_SIZE] = { 0 }; char buffer[MAX_TRACELOG_MSG_LENGTH] = { 0 };
switch (logType) switch (logType)
{ {
@ -184,10 +183,10 @@ unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead)
if (size > 0) if (size > 0)
{ {
data = (unsigned char *)RL_MALLOC(sizeof(unsigned char)*size); data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char));
// NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements] // NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements]
unsigned int count = fread(data, sizeof(unsigned char), size, file); unsigned int count = (unsigned int)fread(data, sizeof(unsigned char), size, file);
*bytesRead = count; *bytesRead = count;
if (count != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded", fileName); if (count != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded", fileName);
@ -213,7 +212,7 @@ void SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite)
if (file != NULL) if (file != NULL)
{ {
unsigned int count = fwrite(data, sizeof(unsigned char), bytesToWrite, file); unsigned int count = (unsigned int)fwrite(data, sizeof(unsigned char), bytesToWrite, file);
if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write file", fileName); if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write file", fileName);
else if (count != bytesToWrite) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName); else if (count != bytesToWrite) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName);
@ -242,13 +241,13 @@ char *LoadFileText(const char *fileName)
// text mode causes carriage return-linefeed translation... // text mode causes carriage return-linefeed translation...
// ...but using fseek() should return correct byte-offset // ...but using fseek() should return correct byte-offset
fseek(textFile, 0, SEEK_END); fseek(textFile, 0, SEEK_END);
int size = ftell(textFile); unsigned int size = (unsigned int)ftell(textFile);
fseek(textFile, 0, SEEK_SET); fseek(textFile, 0, SEEK_SET);
if (size > 0) if (size > 0)
{ {
text = (char *)RL_MALLOC(sizeof(char)*(size + 1)); text = (char *)RL_MALLOC((size + 1)*sizeof(char));
int count = fread(text, sizeof(char), size, textFile); unsigned int count = (unsigned int)fread(text, sizeof(char), size, textFile);
// WARNING: \r\n is converted to \n on reading, so, // WARNING: \r\n is converted to \n on reading, so,
// read bytes count gets reduced by the number of lines // read bytes count gets reduced by the number of lines
@ -318,8 +317,18 @@ FILE *android_fopen(const char *fileName, const char *mode)
// NOTE: AAsset provides access to read-only asset // NOTE: AAsset provides access to read-only asset
AAsset *asset = AAssetManager_open(assetManager, fileName, AASSET_MODE_UNKNOWN); AAsset *asset = AAssetManager_open(assetManager, fileName, AASSET_MODE_UNKNOWN);
if (asset != NULL) return funopen(asset, android_read, android_write, android_seek, android_close); if (asset != NULL)
else return NULL; {
// Return pointer to file in the assets
return funopen(asset, android_read, android_write, android_seek, android_close);
}
else
{
#undef fopen
// Just do a regular open if file is not found in the assets
return fopen(TextFormat("%s/%s", internalDataPath, fileName), mode);
#define fopen(name, mode) android_fopen(name, mode)
}
} }
} }
#endif // PLATFORM_ANDROID #endif // PLATFORM_ANDROID
@ -351,69 +360,3 @@ static int android_close(void *cookie)
return 0; return 0;
} }
#endif // PLATFORM_ANDROID #endif // PLATFORM_ANDROID
#if defined(PLATFORM_UWP)
UWPMessage *CreateUWPMessage(void)
{
UWPMessage *msg = (UWPMessage *)RL_MALLOC(sizeof(UWPMessage));
msg->type = UWP_MSG_NONE;
Vector2 v0 = { 0, 0 };
msg->paramVector0 = v0;
msg->paramInt0 = 0;
msg->paramInt1 = 0;
msg->paramChar0 = 0;
msg->paramFloat0 = 0;
msg->paramDouble0 = 0;
msg->paramBool0 = false;
return msg;
}
void DeleteUWPMessage(UWPMessage *msg)
{
RL_FREE(msg);
}
bool UWPHasMessages(void)
{
return (UWPOutMessageId > -1);
}
UWPMessage *UWPGetMessage(void)
{
if (UWPHasMessages()) return UWPOutMessages[UWPOutMessageId--];
return NULL;
}
void UWPSendMessage(UWPMessage *msg)
{
if ((UWPInMessageId + 1) < MAX_UWP_MESSAGES)
{
UWPInMessageId++;
UWPInMessages[UWPInMessageId] = msg;
}
else TRACELOG(LOG_WARNING, "UWP: Not enough array space to register new inbound message");
}
void SendMessageToUWP(UWPMessage *msg)
{
if ((UWPOutMessageId + 1) < MAX_UWP_MESSAGES)
{
UWPOutMessageId++;
UWPOutMessages[UWPOutMessageId] = msg;
}
else TRACELOG(LOG_WARNING, "UWP: Not enough array space to register new outward message");
}
bool HasMessageFromUWP(void)
{
return UWPInMessageId > -1;
}
UWPMessage *GetMessageFromUWP(void)
{
if (HasMessageFromUWP()) return UWPInMessages[UWPInMessageId--];
return NULL;
}
#endif // PLATFORM_UWP

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! FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen() -> Read-only!
#endif #endif
#if defined(PLATFORM_UWP)
// UWP Messages System
typedef enum {
UWP_MSG_NONE = 0,
// Send
UWP_MSG_SHOW_MOUSE,
UWP_MSG_HIDE_MOUSE,
UWP_MSG_LOCK_MOUSE,
UWP_MSG_UNLOCK_MOUSE,
UWP_MSG_SET_MOUSE_LOCATION, // paramVector0 (pos)
// Receive (Into C)
UWP_MSG_REGISTER_KEY, // paramInt0 (key), paramChar0 (status)
UWP_MSG_REGISTER_CLICK, // paramInt0 (button), paramChar0 (status)
UWP_MSG_SCROLL_WHEEL_UPDATE, // paramInt0 (delta)
UWP_MSG_UPDATE_MOUSE_LOCATION, // paramVector0 (pos)
UWP_MSG_SET_GAMEPAD_ACTIVE, // paramInt0 (gamepad), paramBool0 (active or not)
UWP_MSG_SET_GAMEPAD_BUTTON, // paramInt0 (gamepad), paramInt1 (button), paramChar0 (status)
UWP_MSG_SET_GAMEPAD_AXIS, // paramInt0 (gamepad), int1 (axis), paramFloat0 (value)
UWP_MSG_SET_DISPLAY_DIMS, // paramVector0 (display dimensions)
UWP_MSG_HANDLE_RESIZE, // paramVector0 (new dimensions) - Onresized event
UWP_MSG_SET_GAME_TIME, // paramInt0
} UWPMessageType;
typedef struct UWPMessage {
UWPMessageType type; // Message type
Vector2 paramVector0; // Vector parameters
int paramInt0; // Int parameter
int paramInt1; // Int parameter
char paramChar0; // Char parameters
float paramFloat0; // Float parameters
double paramDouble0; // Double parameters
bool paramBool0; // Bool parameters
// More parameters can be added and fed to functions
} UWPMessage;
// Allocate UWP Message
RLAPI UWPMessage* CreateUWPMessage(void);
// Free UWP Message
RLAPI void DeleteUWPMessage(UWPMessage* msg);
// Get messages into C++
RLAPI bool UWPHasMessages(void);
RLAPI UWPMessage* UWPGetMessage(void);
RLAPI void UWPSendMessage(UWPMessage* msg);
// For C to call
#ifndef __cplusplus // Hide from C++ code
void SendMessageToUWP(UWPMessage* msg);
bool HasMessageFromUWP(void);
UWPMessage* GetMessageFromUWP(void);
#endif
#endif //defined(PLATFORM_UWP)
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

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