Bundle raylib C sources and switch to develop branch

This commit is contained in:
Milan Nikolic 2017-01-28 17:19:06 +01:00
parent e2f3bed444
commit f89d1164a5
36 changed files with 54932 additions and 193 deletions

1230
raylib/audio.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -122,13 +122,12 @@ func LoadWave(fileName string) Wave {
}
// Load wave data from float array data (32bit)
func LoadWaveEx(data []float32, sampleCount int32, sampleRate int32, sampleSize int32, channels int32) Wave {
cdata := (*C.float)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&data)).Data))
func LoadWaveEx(data unsafe.Pointer, sampleCount int32, sampleRate int32, sampleSize int32, channels int32) Wave {
csampleCount := (C.int)(sampleCount)
csampleRate := (C.int)(sampleRate)
csampleSize := (C.int)(sampleSize)
cchannels := (C.int)(channels)
ret := C.LoadWaveEx(cdata, csampleCount, csampleRate, csampleSize, cchannels)
ret := C.LoadWaveEx(data, csampleCount, csampleRate, csampleSize, cchannels)
v := NewWaveFromPointer(unsafe.Pointer(&ret))
return v
}
@ -150,16 +149,6 @@ func LoadSoundFromWave(wave Wave) Sound {
return v
}
// Load sound to memory from rRES file (raylib Resource)
func LoadSoundFromRES(rresName string, resId int32) Sound {
crresName := C.CString(rresName)
defer C.free(unsafe.Pointer(crresName))
cresId := (C.int)(resId)
ret := C.LoadSoundFromRES(crresName, cresId)
v := NewSoundFromPointer(unsafe.Pointer(&ret))
return v
}
// Update sound buffer with new data
func UpdateSound(sound Sound, data unsafe.Pointer, numSamples int32) {
csound := sound.cptr()

159
raylib/audio.h Normal file
View file

@ -0,0 +1,159 @@
/**********************************************************************************************
*
* raylib.audio
*
* This module provides basic functionality to work with audio:
* Manage audio device (init/close)
* Load and Unload audio files (WAV, OGG, FLAC, XM, MOD)
* Play/Stop/Pause/Resume loaded audio
* Manage mixing channels
* Manage raw audio context
*
* External libs:
* OpenAL Soft - Audio device management (http://kcat.strangesoft.net/openal.html)
* stb_vorbis - OGG audio files loading (http://www.nothings.org/stb_vorbis/)
* jar_xm - XM module file loading
* jar_mod - MOD audio file loading
* dr_flac - FLAC audio file loading
*
* Many thanks to Joshua Reisenauer (github: @kd7tck) for the following additions:
* XM audio module support (jar_xm)
* MOD audio module support (jar_mod)
* Mixing channels support
* Raw audio context support
*
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* 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 AUDIO_H
#define AUDIO_H
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Types and Structures Definition
// NOTE: Below types are required for CAMERA_STANDALONE usage
//----------------------------------------------------------------------------------
#ifndef __cplusplus
// Boolean type
#if !defined(_STDBOOL_H)
typedef enum { false, true } bool;
#define _STDBOOL_H
#endif
#endif
// Wave type, defines audio wave data
typedef struct Wave {
unsigned int sampleCount; // Number of samples
unsigned int sampleRate; // Frequency (samples per second)
unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
unsigned int channels; // Number of channels (1-mono, 2-stereo)
void *data; // Buffer data pointer
} Wave;
// Sound source type
typedef struct Sound {
unsigned int source; // OpenAL audio source id
unsigned int buffer; // OpenAL audio buffer id
int format; // OpenAL audio format specifier
} Sound;
// Music type (file streaming from memory)
// NOTE: Anything longer than ~10 seconds should be streamed
typedef struct MusicData *Music;
// Audio stream type
// NOTE: Useful to create custom audio streams not bound to a specific file
typedef struct AudioStream {
unsigned int sampleRate; // Frequency (samples per second)
unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
unsigned int channels; // Number of channels (1-mono, 2-stereo)
int format; // OpenAL audio format specifier
unsigned int source; // OpenAL audio source id
unsigned int buffers[2]; // OpenAL audio buffers (double buffering)
} AudioStream;
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
void InitAudioDevice(void); // Initialize audio device and context
void CloseAudioDevice(void); // Close the audio device and context
bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully
Wave LoadWave(const char *fileName); // Load wave data from file
Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from raw array data
Sound LoadSound(const char *fileName); // Load sound from file
Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
void UpdateSound(Sound sound, const void *data, int numSamples);// Update sound buffer with new data
void UnloadWave(Wave wave); // Unload wave data
void UnloadSound(Sound sound); // Unload sound
void PlaySound(Sound sound); // Play a sound
void PauseSound(Sound sound); // Pause a sound
void ResumeSound(Sound sound); // Resume a paused sound
void StopSound(Sound sound); // Stop playing a sound
bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing
void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level)
void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level)
void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format
Wave WaveCopy(Wave wave); // Copy a wave to a new wave
void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range
float *GetWaveData(Wave wave); // Get samples data from wave as a floats array
Music LoadMusicStream(const char *fileName); // Load music stream from file
void UnloadMusicStream(Music music); // Unload music stream
void PlayMusicStream(Music music); // Start music playing
void UpdateMusicStream(Music music); // Updates buffers for music streaming
void StopMusicStream(Music music); // Stop music playing
void PauseMusicStream(Music music); // Pause music playing
void ResumeMusicStream(Music music); // Resume playing paused music
bool IsMusicPlaying(Music music); // Check if music is playing
void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
float GetMusicTimeLength(Music music); // Get music time length (in seconds)
float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
AudioStream InitAudioStream(unsigned int sampleRate,
unsigned int sampleSize,
unsigned int channels); // Init audio stream (to stream raw audio pcm data)
void UpdateAudioStream(AudioStream stream, void *data, int numSamples); // Update audio stream buffers with data
void CloseAudioStream(AudioStream stream); // Close audio stream and free memory
bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill
void PlayAudioStream(AudioStream stream); // Play audio stream
void PauseAudioStream(AudioStream stream); // Pause audio stream
void ResumeAudioStream(AudioStream stream); // Resume audio stream
void StopAudioStream(AudioStream stream); // Stop audio stream
#ifdef __cplusplus
}
#endif
#endif // AUDIO_H

505
raylib/camera.h Normal file
View file

@ -0,0 +1,505 @@
/*******************************************************************************************
*
* raylib Camera System - Camera Modes Setup and Control Functions
*
* #define CAMERA_IMPLEMENTATION
* Generates the implementation of the library into the included file.
* If not defined, the library is in header only mode and can be included in other headers
* or source files without problems. But only ONE file should hold the implementation.
*
* #define CAMERA_STANDALONE
* If defined, the library can be used as standalone as a camera system but some
* functions must be redefined to manage inputs accordingly.
*
* NOTE: Memory footprint of this library is aproximately 52 bytes (global variables)
*
* Initial design by Marc Palau (2014)
* Reviewed by Ramon Santamaria (2015-2016)
*
* 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 CAMERA_H
#define CAMERA_H
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Types and Structures Definition
// NOTE: Below types are required for CAMERA_STANDALONE usage
//----------------------------------------------------------------------------------
#if defined(CAMERA_STANDALONE)
// Camera modes
typedef enum {
CAMERA_CUSTOM = 0,
CAMERA_FREE,
CAMERA_ORBITAL,
CAMERA_FIRST_PERSON,
CAMERA_THIRD_PERSON
} CameraMode;
// Vector2 type
typedef struct Vector2 {
float x;
float y;
} Vector2;
// Vector3 type
typedef struct Vector3 {
float x;
float y;
float z;
} Vector3;
// Camera type, defines a camera position/orientation in 3d space
typedef struct Camera {
Vector3 position;
Vector3 target;
Vector3 up;
float fovy;
} Camera;
#endif
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
#if defined(CAMERA_STANDALONE)
void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available)
void UpdateCamera(Camera *camera); // Update camera position for selected mode
void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera)
void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera)
void SetCameraSmoothZoomControl(int szKey); // Set camera smooth zoom key to combine with mouse (free camera)
void SetCameraMoveControls(int frontKey, int backKey,
int rightKey, int leftKey,
int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras)
#endif
#ifdef __cplusplus
}
#endif
#endif // CAMERA_H
/***********************************************************************************
*
* CAMERA IMPLEMENTATION
*
************************************************************************************/
#if defined(CAMERA_IMPLEMENTATION)
#include <math.h> // Required for: sqrt(), sin(), cos()
#ifndef PI
#define PI 3.14159265358979323846
#endif
#ifndef DEG2RAD
#define DEG2RAD (PI/180.0f)
#endif
#ifndef RAD2DEG
#define RAD2DEG (180.0f/PI)
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
// Camera mouse movement sensitivity
#define CAMERA_MOUSE_MOVE_SENSITIVITY 0.003f
#define CAMERA_MOUSE_SCROLL_SENSITIVITY 1.5f
// FREE_CAMERA
#define CAMERA_FREE_MOUSE_SENSITIVITY 0.01f
#define CAMERA_FREE_DISTANCE_MIN_CLAMP 0.3f
#define CAMERA_FREE_DISTANCE_MAX_CLAMP 120.0f
#define CAMERA_FREE_MIN_CLAMP 85.0f
#define CAMERA_FREE_MAX_CLAMP -85.0f
#define CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY 0.05f
#define CAMERA_FREE_PANNING_DIVIDER 5.1f
// ORBITAL_CAMERA
#define CAMERA_ORBITAL_SPEED 0.01f // Radians per frame
// FIRST_PERSON
//#define CAMERA_FIRST_PERSON_MOUSE_SENSITIVITY 0.003f
#define CAMERA_FIRST_PERSON_FOCUS_DISTANCE 25.0f
#define CAMERA_FIRST_PERSON_MIN_CLAMP 85.0f
#define CAMERA_FIRST_PERSON_MAX_CLAMP -85.0f
#define CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER 5.0f
#define CAMERA_FIRST_PERSON_STEP_DIVIDER 30.0f
#define CAMERA_FIRST_PERSON_WAVING_DIVIDER 200.0f
// THIRD_PERSON
//#define CAMERA_THIRD_PERSON_MOUSE_SENSITIVITY 0.003f
#define CAMERA_THIRD_PERSON_DISTANCE_CLAMP 1.2f
#define CAMERA_THIRD_PERSON_MIN_CLAMP 5.0f
#define CAMERA_THIRD_PERSON_MAX_CLAMP -85.0f
#define CAMERA_THIRD_PERSON_OFFSET (Vector3){ 0.4f, 0.0f, 0.0f }
// PLAYER (used by camera)
#define PLAYER_MOVEMENT_SENSITIVITY 20.0f
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Camera move modes (first person and third person cameras)
typedef enum { MOVE_FRONT = 0, MOVE_BACK, MOVE_RIGHT, MOVE_LEFT, MOVE_UP, MOVE_DOWN } CameraMove;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
static Vector2 cameraAngle = { 0.0f, 0.0f }; // TODO: Remove! Compute it in UpdateCamera()
static float cameraTargetDistance = 0.0f; // TODO: Remove! Compute it in UpdateCamera()
static float playerEyesPosition = 1.85f; // Default player eyes position from ground (in meters)
static int cameraMoveControl[6] = { 'W', 'S', 'D', 'A', 'E', 'Q' };
static int cameraPanControlKey = 2; // raylib: MOUSE_MIDDLE_BUTTON
static int cameraAltControlKey = 342; // raylib: KEY_LEFT_ALT
static int cameraSmoothZoomControlKey = 341; // raylib: KEY_LEFT_CONTROL
static int cameraMode = CAMERA_CUSTOM; // Current camera mode
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
#if defined(CAMERA_STANDALONE)
// NOTE: Camera controls depend on some raylib input functions
// TODO: Set your own input functions (used in UpdateCamera())
static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; }
static void SetMousePosition(Vector2 pos) {}
static int IsMouseButtonDown(int button) { return 0;}
static int GetMouseWheelMove() { return 0; }
static int GetScreenWidth() { return 1280; }
static int GetScreenHeight() { return 720; }
static void ShowCursor() {}
static void HideCursor() {}
static int IsKeyDown(int key) { return 0; }
#endif
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
// Select camera mode (multiple camera modes available)
void SetCameraMode(Camera camera, int mode)
{
// TODO: cameraTargetDistance and cameraAngle should be
// calculated using camera parameters on UpdateCamera()
Vector3 v1 = camera.position;
Vector3 v2 = camera.target;
float dx = v2.x - v1.x;
float dy = v2.y - v1.y;
float dz = v2.z - v1.z;
cameraTargetDistance = sqrtf(dx*dx + dy*dy + dz*dz);
Vector2 distance = { 0.0f, 0.0f };
distance.x = sqrtf(dx*dx + dz*dz);
distance.y = sqrtf(dx*dx + dy*dy);
// Camera angle calculation
cameraAngle.x = asinf(fabsf(dx)/distance.x); // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
cameraAngle.y = -asinf(fabsf(dy)/distance.y); // Camera angle in plane XY (0 aligned with X, move positive CW)
// NOTE: Just testing what cameraAngle means
//cameraAngle.x = 0.0f*DEG2RAD; // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
//cameraAngle.y = -60.0f*DEG2RAD; // Camera angle in plane XY (0 aligned with X, move positive CW)
playerEyesPosition = camera.position.y;
cameraMode = mode;
}
// Update camera depending on selected mode
// NOTE: Camera controls depend on some raylib functions:
// Mouse: GetMousePosition(), SetMousePosition(), IsMouseButtonDown(), GetMouseWheelMove()
// System: GetScreenWidth(), GetScreenHeight(), ShowCursor(), HideCursor()
// Keys: IsKeyDown()
// TODO: Port to quaternion-based camera
void UpdateCamera(Camera *camera)
{
static int swingCounter = 0; // Used for 1st person swinging movement
static Vector2 previousMousePosition = { 0.0f, 0.0f };
// TODO: Compute cameraTargetDistance and cameraAngle here
// Mouse movement detection
Vector2 mousePositionDelta = { 0.0f, 0.0f };
Vector2 mousePosition = GetMousePosition();
int mouseWheelMove = GetMouseWheelMove();
// Keys input detection
bool panKey = IsMouseButtonDown(cameraPanControlKey);
bool altKey = IsKeyDown(cameraAltControlKey);
bool szoomKey = IsKeyDown(cameraSmoothZoomControlKey);
bool direction[6] = { IsKeyDown(cameraMoveControl[MOVE_FRONT]),
IsKeyDown(cameraMoveControl[MOVE_BACK]),
IsKeyDown(cameraMoveControl[MOVE_RIGHT]),
IsKeyDown(cameraMoveControl[MOVE_LEFT]),
IsKeyDown(cameraMoveControl[MOVE_UP]),
IsKeyDown(cameraMoveControl[MOVE_DOWN]) };
// TODO: Consider touch inputs for camera
if (cameraMode != CAMERA_CUSTOM)
{
// Get screen size
int screenWidth = GetScreenWidth();
int screenHeight = GetScreenHeight();
if ((cameraMode == CAMERA_FIRST_PERSON) ||
(cameraMode == CAMERA_THIRD_PERSON))
{
HideCursor();
if (mousePosition.x < (float)screenHeight/3.0f) SetMousePosition((Vector2){ screenWidth - screenHeight/3, mousePosition.y });
else if (mousePosition.y < (float)screenHeight/3.0f) SetMousePosition((Vector2){ mousePosition.x, screenHeight - screenHeight/3 });
else if (mousePosition.x > (screenWidth - (float)screenHeight/3.0f)) SetMousePosition((Vector2){ screenHeight/3, mousePosition.y });
else if (mousePosition.y > (screenHeight - (float)screenHeight/3.0f)) SetMousePosition((Vector2){ mousePosition.x, screenHeight/3 });
else
{
mousePositionDelta.x = mousePosition.x - previousMousePosition.x;
mousePositionDelta.y = mousePosition.y - previousMousePosition.y;
}
}
else // CAMERA_FREE, CAMERA_ORBITAL
{
ShowCursor();
mousePositionDelta.x = mousePosition.x - previousMousePosition.x;
mousePositionDelta.y = mousePosition.y - previousMousePosition.y;
}
// NOTE: We GetMousePosition() again because it can be modified by a previous SetMousePosition() call
// If using directly mousePosition variable we have problems on CAMERA_FIRST_PERSON and CAMERA_THIRD_PERSON
previousMousePosition = GetMousePosition();
}
// Support for multiple automatic camera modes
switch (cameraMode)
{
case CAMERA_FREE:
{
// Camera zoom
if ((cameraTargetDistance < CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
{
cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
if (cameraTargetDistance > CAMERA_FREE_DISTANCE_MAX_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MAX_CLAMP;
}
// Camera looking down
// TODO: Review, weird comparisson of cameraTargetDistance == 120.0f?
else if ((camera->position.y > camera->target.y) && (cameraTargetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
{
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
}
else if ((camera->position.y > camera->target.y) && (camera->target.y >= 0))
{
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
// if (camera->target.y < 0) camera->target.y = -0.001;
}
else if ((camera->position.y > camera->target.y) && (camera->target.y < 0) && (mouseWheelMove > 0))
{
cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
if (cameraTargetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
}
// Camera looking up
// TODO: Review, weird comparisson of cameraTargetDistance == 120.0f?
else if ((camera->position.y < camera->target.y) && (cameraTargetDistance == CAMERA_FREE_DISTANCE_MAX_CLAMP) && (mouseWheelMove < 0))
{
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
}
else if ((camera->position.y < camera->target.y) && (camera->target.y <= 0))
{
camera->target.x += mouseWheelMove*(camera->target.x - camera->position.x)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.y += mouseWheelMove*(camera->target.y - camera->position.y)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
camera->target.z += mouseWheelMove*(camera->target.z - camera->position.z)*CAMERA_MOUSE_SCROLL_SENSITIVITY/cameraTargetDistance;
// if (camera->target.y > 0) camera->target.y = 0.001;
}
else if ((camera->position.y < camera->target.y) && (camera->target.y > 0) && (mouseWheelMove > 0))
{
cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
if (cameraTargetDistance < CAMERA_FREE_DISTANCE_MIN_CLAMP) cameraTargetDistance = CAMERA_FREE_DISTANCE_MIN_CLAMP;
}
// Input keys checks
if (panKey)
{
if (altKey) // Alternative key behaviour
{
if (szoomKey)
{
// Camera smooth zoom
cameraTargetDistance += (mousePositionDelta.y*CAMERA_FREE_SMOOTH_ZOOM_SENSITIVITY);
}
else
{
// Camera rotation
cameraAngle.x += mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY;
cameraAngle.y += mousePositionDelta.y*-CAMERA_FREE_MOUSE_SENSITIVITY;
// Angle clamp
if (cameraAngle.y > CAMERA_FREE_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FREE_MIN_CLAMP*DEG2RAD;
else if (cameraAngle.y < CAMERA_FREE_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FREE_MAX_CLAMP*DEG2RAD;
}
}
else
{
// Camera panning
camera->target.x += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(cameraAngle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(cameraAngle.x)*sinf(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER);
camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER);
camera->target.z += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*sinf(cameraAngle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cosf(cameraAngle.x)*sinf(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER);
}
}
} break;
case CAMERA_ORBITAL:
{
cameraAngle.x += CAMERA_ORBITAL_SPEED; // Camera orbit angle
cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY); // Camera zoom
// Camera distance clamp
if (cameraTargetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
} break;
case CAMERA_FIRST_PERSON:
case CAMERA_THIRD_PERSON:
{
camera->position.x += (sinf(cameraAngle.x)*direction[MOVE_BACK] -
sinf(cameraAngle.x)*direction[MOVE_FRONT] -
cosf(cameraAngle.x)*direction[MOVE_LEFT] +
cosf(cameraAngle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
camera->position.y += (sinf(cameraAngle.y)*direction[MOVE_FRONT] -
sinf(cameraAngle.y)*direction[MOVE_BACK] +
1.0f*direction[MOVE_UP] - 1.0f*direction[MOVE_DOWN])/PLAYER_MOVEMENT_SENSITIVITY;
camera->position.z += (cosf(cameraAngle.x)*direction[MOVE_BACK] -
cosf(cameraAngle.x)*direction[MOVE_FRONT] +
sinf(cameraAngle.x)*direction[MOVE_LEFT] -
sinf(cameraAngle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
bool isMoving = false; // Required for swinging
for (int i = 0; i < 6; i++) if (direction[i]) { isMoving = true; break; }
// Camera orientation calculation
cameraAngle.x += (mousePositionDelta.x*-CAMERA_MOUSE_MOVE_SENSITIVITY);
cameraAngle.y += (mousePositionDelta.y*-CAMERA_MOUSE_MOVE_SENSITIVITY);
if (cameraMode == CAMERA_THIRD_PERSON)
{
// Angle clamp
if (cameraAngle.y > CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MIN_CLAMP*DEG2RAD;
else if (cameraAngle.y < CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_THIRD_PERSON_MAX_CLAMP*DEG2RAD;
// Camera zoom
cameraTargetDistance -= (mouseWheelMove*CAMERA_MOUSE_SCROLL_SENSITIVITY);
// Camera distance clamp
if (cameraTargetDistance < CAMERA_THIRD_PERSON_DISTANCE_CLAMP) cameraTargetDistance = CAMERA_THIRD_PERSON_DISTANCE_CLAMP;
// Camera is always looking at player
camera->target.x = camera->position.x + CAMERA_THIRD_PERSON_OFFSET.x*cosf(cameraAngle.x) + CAMERA_THIRD_PERSON_OFFSET.z*sinf(cameraAngle.x);
camera->target.y = camera->position.y + CAMERA_THIRD_PERSON_OFFSET.y;
camera->target.z = camera->position.z + CAMERA_THIRD_PERSON_OFFSET.z*sinf(cameraAngle.x) - CAMERA_THIRD_PERSON_OFFSET.x*sinf(cameraAngle.x);
}
else // CAMERA_FIRST_PERSON
{
// Angle clamp
if (cameraAngle.y > CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FIRST_PERSON_MIN_CLAMP*DEG2RAD;
else if (cameraAngle.y < CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD) cameraAngle.y = CAMERA_FIRST_PERSON_MAX_CLAMP*DEG2RAD;
// Camera is always looking at player
camera->target.x = camera->position.x - sinf(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
camera->target.y = camera->position.y + sinf(cameraAngle.y)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
camera->target.z = camera->position.z - cosf(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
if (isMoving) swingCounter++;
// Camera position update
// NOTE: On CAMERA_FIRST_PERSON player Y-movement is limited to player 'eyes position'
camera->position.y = playerEyesPosition - sinf(swingCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER;
camera->up.x = sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
camera->up.z = -sinf(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
}
} break;
default: break;
}
// Update camera position with changes
if ((cameraMode == CAMERA_FREE) ||
(cameraMode == CAMERA_ORBITAL) ||
(cameraMode == CAMERA_THIRD_PERSON))
{
// 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(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.x;
if (cameraAngle.y <= 0.0f) camera->position.y = sinf(cameraAngle.y)*cameraTargetDistance*sinf(cameraAngle.y) + camera->target.y;
else camera->position.y = -sinf(cameraAngle.y)*cameraTargetDistance*sinf(cameraAngle.y) + camera->target.y;
camera->position.z = cosf(cameraAngle.x)*cameraTargetDistance*cosf(cameraAngle.y) + camera->target.z;
}
}
// Set camera pan key to combine with mouse movement (free camera)
void SetCameraPanControl(int panKey) { cameraPanControlKey = panKey; }
// Set camera alt key to combine with mouse movement (free camera)
void SetCameraAltControl(int altKey) { cameraAltControlKey = altKey; }
// Set camera smooth zoom key to combine with mouse (free camera)
void SetCameraSmoothZoomControl(int szKey) { cameraSmoothZoomControlKey = szKey; }
// Set camera move controls (1st person and 3rd person cameras)
void SetCameraMoveControls(int frontKey, int backKey, int rightKey, int leftKey, int upKey, int downKey)
{
cameraMoveControl[MOVE_FRONT] = frontKey;
cameraMoveControl[MOVE_BACK] = backKey;
cameraMoveControl[MOVE_RIGHT] = rightKey;
cameraMoveControl[MOVE_LEFT] = leftKey;
cameraMoveControl[MOVE_UP] = upKey;
cameraMoveControl[MOVE_DOWN] = downKey;
}
#endif // CAMERA_IMPLEMENTATION

View file

@ -1,14 +1,15 @@
package raylib
/*
#cgo linux,!arm LDFLAGS: -lraylib -lglfw3 -lGL -lopenal -lm -pthread -ldl -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor
#cgo linux,arm,!android LDFLAGS: -lraylib -lGLESv2 -lEGL -lpthread -lrt -lm -lbcm_host -lvcos -lvchiq_arm -lopenal
#cgo windows LDFLAGS: -lraylib -lglfw3 -lopengl32 -lgdi32 -lopenal32 -lwinmm
#cgo darwin LDFLAGS: -lraylib -lglfw3 -framework OpenGL -framework OpenAl -framework Cocoa
#cgo android LDFLAGS: -lraylib -llog -landroid -lEGL -lGLESv2 -lOpenSLES -lopenal -lm -landroid_native_app_glue
#cgo linux,!arm LDFLAGS: -lglfw3 -lGL -lopenal -lm -pthread -ldl -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor
#cgo linux,arm,!android LDFLAGS: -lGLESv2 -lEGL -lpthread -lrt -lm -lbcm_host -lvcos -lvchiq_arm -lopenal
#cgo windows LDFLAGS: -lglfw3 -lopengl32 -lgdi32 -lopenal32 -lwinmm
#cgo darwin LDFLAGS: -lglfw3 -framework OpenGL -framework OpenAl -framework Cocoa
#cgo android LDFLAGS: -llog -landroid -lEGL -lGLESv2 -lOpenSLES -lopenal -lm -landroid_native_app_glue
#cgo linux,windows,darwin,!android,!arm CFLAGS: -DPLATFORM_DESKTOP
#cgo linux,arm,!android CFLAGS: -DPLATFORM_RPI
#cgo android CFLAGS: -DPLATFORM_ANDROID
#cgo CFLAGS: -std=gnu99 -fgnu89-inline -Wno-missing-braces -Wno-unused-result
#cgo linux,windows,darwin,!android,!arm CFLAGS: -DPLATFORM_DESKTOP -DGRAPHICS_API_OPENGL_33
#cgo linux,arm,!android CFLAGS: -DPLATFORM_RPI -DGRAPHICS_API_OPENGL_ES2
#cgo android CFLAGS: -DPLATFORM_ANDROID -DGRAPHICS_API_OPENGL_ES2
*/
import "C"

3222
raylib/core.c Normal file

File diff suppressed because it is too large Load diff

4564
raylib/external/dr_flac.h vendored Normal file

File diff suppressed because it is too large Load diff

5441
raylib/external/glad.h vendored Normal file

File diff suppressed because it is too large Load diff

1595
raylib/external/jar_mod.h vendored Normal file

File diff suppressed because it is too large Load diff

2664
raylib/external/jar_xm.h vendored Normal file

File diff suppressed because it is too large Load diff

7110
raylib/external/stb_image.h vendored Normal file

File diff suppressed because it is too large Load diff

2580
raylib/external/stb_image_resize.h vendored Normal file

File diff suppressed because it is too large Load diff

1049
raylib/external/stb_image_write.h vendored Normal file

File diff suppressed because it is too large Load diff

583
raylib/external/stb_rect_pack.h vendored Normal file
View file

@ -0,0 +1,583 @@
// stb_rect_pack.h - v0.10 - public domain - rectangle packing
// Sean Barrett 2014
//
// Useful for e.g. packing rectangular textures into an atlas.
// Does not do rotation.
//
// Not necessarily the awesomest packing method, but better than
// the totally naive one in stb_truetype (which is primarily what
// this is meant to replace).
//
// Has only had a few tests run, may have issues.
//
// More docs to come.
//
// No memory allocations; uses qsort() and assert() from stdlib.
// Can override those by defining STBRP_SORT and STBRP_ASSERT.
//
// This library currently uses the Skyline Bottom-Left algorithm.
//
// Please note: better rectangle packers are welcome! Please
// implement them to the same API, but with a different init
// function.
//
// Credits
//
// Library
// Sean Barrett
// Minor features
// Martins Mozeiko
// Bugfixes / warning fixes
// Jeremy Jaussaud
//
// Version history:
//
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
// 0.09 (2016-08-27) fix compiler warnings
// 0.08 (2015-09-13) really fix bug with empty rects (w=0 or h=0)
// 0.07 (2015-09-13) fix bug with empty rects (w=0 or h=0)
// 0.06 (2015-04-15) added STBRP_SORT to allow replacing qsort
// 0.05: added STBRP_ASSERT to allow replacing assert
// 0.04: fixed minor bug in STBRP_LARGE_RECTS support
// 0.01: initial release
//
// LICENSE
//
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
//////////////////////////////////////////////////////////////////////////////
//
// INCLUDE SECTION
//
#ifndef STB_INCLUDE_STB_RECT_PACK_H
#define STB_INCLUDE_STB_RECT_PACK_H
#define STB_RECT_PACK_VERSION 1
#ifdef STBRP_STATIC
#define STBRP_DEF static
#else
#define STBRP_DEF extern
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct stbrp_context stbrp_context;
typedef struct stbrp_node stbrp_node;
typedef struct stbrp_rect stbrp_rect;
#ifdef STBRP_LARGE_RECTS
typedef int stbrp_coord;
#else
typedef unsigned short stbrp_coord;
#endif
STBRP_DEF void stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);
// Assign packed locations to rectangles. The rectangles are of type
// 'stbrp_rect' defined below, stored in the array 'rects', and there
// are 'num_rects' many of them.
//
// Rectangles which are successfully packed have the 'was_packed' flag
// set to a non-zero value and 'x' and 'y' store the minimum location
// on each axis (i.e. bottom-left in cartesian coordinates, top-left
// if you imagine y increasing downwards). Rectangles which do not fit
// have the 'was_packed' flag set to 0.
//
// You should not try to access the 'rects' array from another thread
// while this function is running, as the function temporarily reorders
// the array while it executes.
//
// To pack into another rectangle, you need to call stbrp_init_target
// again. To continue packing into the same rectangle, you can call
// this function again. Calling this multiple times with multiple rect
// arrays will probably produce worse packing results than calling it
// a single time with the full rectangle array, but the option is
// available.
struct stbrp_rect
{
// reserved for your use:
int id;
// input:
stbrp_coord w, h;
// output:
stbrp_coord x, y;
int was_packed; // non-zero if valid packing
}; // 16 bytes, nominally
STBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);
// Initialize a rectangle packer to:
// pack a rectangle that is 'width' by 'height' in dimensions
// using temporary storage provided by the array 'nodes', which is 'num_nodes' long
//
// You must call this function every time you start packing into a new target.
//
// There is no "shutdown" function. The 'nodes' memory must stay valid for
// the following stbrp_pack_rects() call (or calls), but can be freed after
// the call (or calls) finish.
//
// Note: to guarantee best results, either:
// 1. make sure 'num_nodes' >= 'width'
// or 2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'
//
// If you don't do either of the above things, widths will be quantized to multiples
// of small integers to guarantee the algorithm doesn't run out of temporary storage.
//
// If you do #2, then the non-quantized algorithm will be used, but the algorithm
// may run out of temporary storage and be unable to pack some rectangles.
STBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);
// Optionally call this function after init but before doing any packing to
// change the handling of the out-of-temp-memory scenario, described above.
// If you call init again, this will be reset to the default (false).
STBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);
// Optionally select which packing heuristic the library should use. Different
// heuristics will produce better/worse results for different data sets.
// If you call init again, this will be reset to the default.
enum
{
STBRP_HEURISTIC_Skyline_default=0,
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
STBRP_HEURISTIC_Skyline_BF_sortHeight
};
//////////////////////////////////////////////////////////////////////////////
//
// the details of the following structures don't matter to you, but they must
// be visible so you can handle the memory allocations for them
struct stbrp_node
{
stbrp_coord x,y;
stbrp_node *next;
};
struct stbrp_context
{
int width;
int height;
int align;
int init_mode;
int heuristic;
int num_nodes;
stbrp_node *active_head;
stbrp_node *free_head;
stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'
};
#ifdef __cplusplus
}
#endif
#endif
//////////////////////////////////////////////////////////////////////////////
//
// IMPLEMENTATION SECTION
//
#ifdef STB_RECT_PACK_IMPLEMENTATION
#ifndef STBRP_SORT
#include <stdlib.h>
#define STBRP_SORT qsort
#endif
#ifndef STBRP_ASSERT
#include <assert.h>
#define STBRP_ASSERT assert
#endif
#ifdef _MSC_VER
#define STBRP__NOTUSED(v) (void)(v)
#else
#define STBRP__NOTUSED(v) (void)sizeof(v)
#endif
enum
{
STBRP__INIT_skyline = 1
};
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
{
switch (context->init_mode) {
case STBRP__INIT_skyline:
STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);
context->heuristic = heuristic;
break;
default:
STBRP_ASSERT(0);
}
}
STBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)
{
if (allow_out_of_mem)
// if it's ok to run out of memory, then don't bother aligning them;
// this gives better packing, but may fail due to OOM (even though
// the rectangles easily fit). @TODO a smarter approach would be to only
// quantize once we've hit OOM, then we could get rid of this parameter.
context->align = 1;
else {
// if it's not ok to run out of memory, then quantize the widths
// so that num_nodes is always enough nodes.
//
// I.e. num_nodes * align >= width
// align >= width / num_nodes
// align = ceil(width/num_nodes)
context->align = (context->width + context->num_nodes-1) / context->num_nodes;
}
}
STBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)
{
int i;
#ifndef STBRP_LARGE_RECTS
STBRP_ASSERT(width <= 0xffff && height <= 0xffff);
#endif
for (i=0; i < num_nodes-1; ++i)
nodes[i].next = &nodes[i+1];
nodes[i].next = NULL;
context->init_mode = STBRP__INIT_skyline;
context->heuristic = STBRP_HEURISTIC_Skyline_default;
context->free_head = &nodes[0];
context->active_head = &context->extra[0];
context->width = width;
context->height = height;
context->num_nodes = num_nodes;
stbrp_setup_allow_out_of_mem(context, 0);
// node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)
context->extra[0].x = 0;
context->extra[0].y = 0;
context->extra[0].next = &context->extra[1];
context->extra[1].x = (stbrp_coord) width;
#ifdef STBRP_LARGE_RECTS
context->extra[1].y = (1<<30);
#else
context->extra[1].y = 65535;
#endif
context->extra[1].next = NULL;
}
// find minimum y position if it starts at x1
static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)
{
stbrp_node *node = first;
int x1 = x0 + width;
int min_y, visited_width, waste_area;
STBRP__NOTUSED(c);
STBRP_ASSERT(first->x <= x0);
#if 0
// skip in case we're past the node
while (node->next->x <= x0)
++node;
#else
STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency
#endif
STBRP_ASSERT(node->x <= x0);
min_y = 0;
waste_area = 0;
visited_width = 0;
while (node->x < x1) {
if (node->y > min_y) {
// raise min_y higher.
// we've accounted for all waste up to min_y,
// but we'll now add more waste for everything we've visted
waste_area += visited_width * (node->y - min_y);
min_y = node->y;
// the first time through, visited_width might be reduced
if (node->x < x0)
visited_width += node->next->x - x0;
else
visited_width += node->next->x - node->x;
} else {
// add waste area
int under_width = node->next->x - node->x;
if (under_width + visited_width > width)
under_width = width - visited_width;
waste_area += under_width * (min_y - node->y);
visited_width += under_width;
}
node = node->next;
}
*pwaste = waste_area;
return min_y;
}
typedef struct
{
int x,y;
stbrp_node **prev_link;
} stbrp__findresult;
static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)
{
int best_waste = (1<<30), best_x, best_y = (1 << 30);
stbrp__findresult fr;
stbrp_node **prev, *node, *tail, **best = NULL;
// align to multiple of c->align
width = (width + c->align - 1);
width -= width % c->align;
STBRP_ASSERT(width % c->align == 0);
node = c->active_head;
prev = &c->active_head;
while (node->x + width <= c->width) {
int y,waste;
y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);
if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL
// bottom left
if (y < best_y) {
best_y = y;
best = prev;
}
} else {
// best-fit
if (y + height <= c->height) {
// can only use it if it first vertically
if (y < best_y || (y == best_y && waste < best_waste)) {
best_y = y;
best_waste = waste;
best = prev;
}
}
}
prev = &node->next;
node = node->next;
}
best_x = (best == NULL) ? 0 : (*best)->x;
// if doing best-fit (BF), we also have to try aligning right edge to each node position
//
// e.g, if fitting
//
// ____________________
// |____________________|
//
// into
//
// | |
// | ____________|
// |____________|
//
// then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned
//
// This makes BF take about 2x the time
if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {
tail = c->active_head;
node = c->active_head;
prev = &c->active_head;
// find first node that's admissible
while (tail->x < width)
tail = tail->next;
while (tail) {
int xpos = tail->x - width;
int y,waste;
STBRP_ASSERT(xpos >= 0);
// find the left position that matches this
while (node->next->x <= xpos) {
prev = &node->next;
node = node->next;
}
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
if (y + height < c->height) {
if (y <= best_y) {
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
best_x = xpos;
STBRP_ASSERT(y <= best_y);
best_y = y;
best_waste = waste;
best = prev;
}
}
}
tail = tail->next;
}
}
fr.prev_link = best;
fr.x = best_x;
fr.y = best_y;
return fr;
}
static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)
{
// find best position according to heuristic
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
stbrp_node *node, *cur;
// bail if:
// 1. it failed
// 2. the best node doesn't fit (we don't always check this)
// 3. we're out of memory
if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {
res.prev_link = NULL;
return res;
}
// on success, create new node
node = context->free_head;
node->x = (stbrp_coord) res.x;
node->y = (stbrp_coord) (res.y + height);
context->free_head = node->next;
// insert the new node into the right starting point, and
// let 'cur' point to the remaining nodes needing to be
// stiched back in
cur = *res.prev_link;
if (cur->x < res.x) {
// preserve the existing one, so start testing with the next one
stbrp_node *next = cur->next;
cur->next = node;
cur = next;
} else {
*res.prev_link = node;
}
// from here, traverse cur and free the nodes, until we get to one
// that shouldn't be freed
while (cur->next && cur->next->x <= res.x + width) {
stbrp_node *next = cur->next;
// move the current node to the free list
cur->next = context->free_head;
context->free_head = cur;
cur = next;
}
// stitch the list back in
node->next = cur;
if (cur->x < res.x + width)
cur->x = (stbrp_coord) (res.x + width);
#ifdef _DEBUG
cur = context->active_head;
while (cur->x < context->width) {
STBRP_ASSERT(cur->x < cur->next->x);
cur = cur->next;
}
STBRP_ASSERT(cur->next == NULL);
{
stbrp_node *L1 = NULL, *L2 = NULL;
int count=0;
cur = context->active_head;
while (cur) {
L1 = cur;
cur = cur->next;
++count;
}
cur = context->free_head;
while (cur) {
L2 = cur;
cur = cur->next;
++count;
}
STBRP_ASSERT(count == context->num_nodes+2);
}
#endif
return res;
}
static int rect_height_compare(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
if (p->h > q->h)
return -1;
if (p->h < q->h)
return 1;
return (p->w > q->w) ? -1 : (p->w < q->w);
}
static int rect_width_compare(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
if (p->w > q->w)
return -1;
if (p->w < q->w)
return 1;
return (p->h > q->h) ? -1 : (p->h < q->h);
}
static int rect_original_order(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);
}
#ifdef STBRP_LARGE_RECTS
#define STBRP__MAXVAL 0xffffffff
#else
#define STBRP__MAXVAL 0xffff
#endif
STBRP_DEF void stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)
{
int i;
// we use the 'was_packed' field internally to allow sorting/unsorting
for (i=0; i < num_rects; ++i) {
rects[i].was_packed = i;
#ifndef STBRP_LARGE_RECTS
STBRP_ASSERT(rects[i].w <= 0xffff && rects[i].h <= 0xffff);
#endif
}
// sort according to heuristic
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);
for (i=0; i < num_rects; ++i) {
if (rects[i].w == 0 || rects[i].h == 0) {
rects[i].x = rects[i].y = 0; // empty rect needs no space
} else {
stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);
if (fr.prev_link) {
rects[i].x = (stbrp_coord) fr.x;
rects[i].y = (stbrp_coord) fr.y;
} else {
rects[i].x = rects[i].y = STBRP__MAXVAL;
}
}
}
// unsort
STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);
// set was_packed flags
for (i=0; i < num_rects; ++i)
rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);
}
#endif

4018
raylib/external/stb_truetype.h vendored Normal file

File diff suppressed because it is too large Load diff

393
raylib/external/stb_vorbis.h vendored Normal file
View file

@ -0,0 +1,393 @@
// Ogg Vorbis audio decoder - v1.09 - public domain
// http://nothings.org/stb_vorbis/
//
// Original version written by Sean Barrett in 2007.
//
// Originally sponsored by RAD Game Tools. Seeking sponsored
// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software,
// Aras Pranckevicius, and Sean Barrett.
//
// LICENSE
//
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
//
// No warranty for any purpose is expressed or implied by the author (nor
// by RAD Game Tools). Report bugs and send enhancements to the author.
//
// Limitations:
//
// - floor 0 not supported (used in old ogg vorbis files pre-2004)
// - lossless sample-truncation at beginning ignored
// - cannot concatenate multiple vorbis streams
// - sample positions are 32-bit, limiting seekable 192Khz
// files to around 6 hours (Ogg supports 64-bit)
//
// Feature contributors:
// Dougall Johnson (sample-exact seeking)
//
// Bugfix/warning contributors:
// Terje Mathisen Niklas Frykholm Andy Hill
// Casey Muratori John Bolton Gargaj
// Laurent Gomila Marc LeBlanc Ronny Chevalier
// Bernhard Wodo Evan Balster alxprd@github
// Tom Beaumont Ingo Leitgeb Nicolas Guillemot
// Phillip Bennefall Rohit Thiago Goulart
// manxorist@github saga musix
//
// Partial history:
// 1.09 - 2016/04/04 - back out 'truncation of last frame' fix from previous version
// 1.08 - 2016/04/02 - warnings; setup memory leaks; truncation of last frame
// 1.07 - 2015/01/16 - fixes for crashes on invalid files; warning fixes; const
// 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson)
// some crash fixes when out of memory or with corrupt files
// fix some inappropriately signed shifts
// 1.05 - 2015/04/19 - don't define __forceinline if it's redundant
// 1.04 - 2014/08/27 - fix missing const-correct case in API
// 1.03 - 2014/08/07 - warning fixes
// 1.02 - 2014/07/09 - declare qsort comparison as explicitly _cdecl in Windows
// 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float (interleaved was correct)
// 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel;
// (API change) report sample rate for decode-full-file funcs
//
// See end of file for full version history.
//////////////////////////////////////////////////////////////////////////////
//
// HEADER BEGINS HERE
//
#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H
#define STB_VORBIS_INCLUDE_STB_VORBIS_H
#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
#define STB_VORBIS_NO_STDIO 1
#endif
#ifndef STB_VORBIS_NO_STDIO
#include <stdio.h>
#endif
// NOTE: Added to work with raylib on Android
#if defined(PLATFORM_ANDROID)
#include "utils.h" // Android fopen function map
#endif
#ifdef __cplusplus
extern "C" {
#endif
/////////// THREAD SAFETY
// Individual stb_vorbis* handles are not thread-safe; you cannot decode from
// them from multiple threads at the same time. However, you can have multiple
// stb_vorbis* handles and decode from them independently in multiple thrads.
/////////// MEMORY ALLOCATION
// normally stb_vorbis uses malloc() to allocate memory at startup,
// and alloca() to allocate temporary memory during a frame on the
// stack. (Memory consumption will depend on the amount of setup
// data in the file and how you set the compile flags for speed
// vs. size. In my test files the maximal-size usage is ~150KB.)
//
// You can modify the wrapper functions in the source (setup_malloc,
// setup_temp_malloc, temp_malloc) to change this behavior, or you
// can use a simpler allocation model: you pass in a buffer from
// which stb_vorbis will allocate _all_ its memory (including the
// temp memory). "open" may fail with a VORBIS_outofmem if you
// do not pass in enough data; there is no way to determine how
// much you do need except to succeed (at which point you can
// query get_info to find the exact amount required. yes I know
// this is lame).
//
// If you pass in a non-NULL buffer of the type below, allocation
// will occur from it as described above. Otherwise just pass NULL
// to use malloc()/alloca()
typedef struct
{
char *alloc_buffer;
int alloc_buffer_length_in_bytes;
} stb_vorbis_alloc;
/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES
typedef struct stb_vorbis stb_vorbis;
typedef struct
{
unsigned int sample_rate;
int channels;
unsigned int setup_memory_required;
unsigned int setup_temp_memory_required;
unsigned int temp_memory_required;
int max_frame_size;
} stb_vorbis_info;
// get general information about the file
extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f);
// get the last error detected (clears it, too)
extern int stb_vorbis_get_error(stb_vorbis *f);
// close an ogg vorbis file and free all memory in use
extern void stb_vorbis_close(stb_vorbis *f);
// this function returns the offset (in samples) from the beginning of the
// file that will be returned by the next decode, if it is known, or -1
// otherwise. after a flush_pushdata() call, this may take a while before
// it becomes valid again.
// NOT WORKING YET after a seek with PULLDATA API
extern int stb_vorbis_get_sample_offset(stb_vorbis *f);
// returns the current seek point within the file, or offset from the beginning
// of the memory buffer. In pushdata mode it returns 0.
extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);
/////////// PUSHDATA API
#ifndef STB_VORBIS_NO_PUSHDATA_API
// this API allows you to get blocks of data from any source and hand
// them to stb_vorbis. you have to buffer them; stb_vorbis will tell
// you how much it used, and you have to give it the rest next time;
// and stb_vorbis may not have enough data to work with and you will
// need to give it the same data again PLUS more. Note that the Vorbis
// specification does not bound the size of an individual frame.
extern stb_vorbis *stb_vorbis_open_pushdata(
const unsigned char * datablock, int datablock_length_in_bytes,
int *datablock_memory_consumed_in_bytes,
int *error,
const stb_vorbis_alloc *alloc_buffer);
// create a vorbis decoder by passing in the initial data block containing
// the ogg&vorbis headers (you don't need to do parse them, just provide
// the first N bytes of the file--you're told if it's not enough, see below)
// on success, returns an stb_vorbis *, does not set error, returns the amount of
// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes;
// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed
// if returns NULL and *error is VORBIS_need_more_data, then the input block was
// incomplete and you need to pass in a larger block from the start of the file
extern int stb_vorbis_decode_frame_pushdata(
stb_vorbis *f,
const unsigned char *datablock, int datablock_length_in_bytes,
int *channels, // place to write number of float * buffers
float ***output, // place to write float ** array of float * buffers
int *samples // place to write number of output samples
);
// decode a frame of audio sample data if possible from the passed-in data block
//
// return value: number of bytes we used from datablock
//
// possible cases:
// 0 bytes used, 0 samples output (need more data)
// N bytes used, 0 samples output (resynching the stream, keep going)
// N bytes used, M samples output (one frame of data)
// note that after opening a file, you will ALWAYS get one N-bytes,0-sample
// frame, because Vorbis always "discards" the first frame.
//
// Note that on resynch, stb_vorbis will rarely consume all of the buffer,
// instead only datablock_length_in_bytes-3 or less. This is because it wants
// to avoid missing parts of a page header if they cross a datablock boundary,
// without writing state-machiney code to record a partial detection.
//
// The number of channels returned are stored in *channels (which can be
// NULL--it is always the same as the number of channels reported by
// get_info). *output will contain an array of float* buffers, one per
// channel. In other words, (*output)[0][0] contains the first sample from
// the first channel, and (*output)[1][0] contains the first sample from
// the second channel.
extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
// inform stb_vorbis that your next datablock will not be contiguous with
// previous ones (e.g. you've seeked in the data); future attempts to decode
// frames will cause stb_vorbis to resynchronize (as noted above), and
// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it
// will begin decoding the _next_ frame.
//
// if you want to seek using pushdata, you need to seek in your file, then
// call stb_vorbis_flush_pushdata(), then start calling decoding, then once
// decoding is returning you data, call stb_vorbis_get_sample_offset, and
// if you don't like the result, seek your file again and repeat.
#endif
////////// PULLING INPUT API
#ifndef STB_VORBIS_NO_PULLDATA_API
// This API assumes stb_vorbis is allowed to pull data from a source--
// either a block of memory containing the _entire_ vorbis stream, or a
// FILE * that you or it create, or possibly some other reading mechanism
// if you go modify the source to replace the FILE * case with some kind
// of callback to your code. (But if you don't support seeking, you may
// just want to go ahead and use pushdata.)
#if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
extern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output);
#endif
#if !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output);
#endif
// decode an entire file and output the data interleaved into a malloc()ed
// buffer stored in *output. The return value is the number of samples
// decoded, or -1 if the file could not be opened or was not an ogg vorbis file.
// When you're done with it, just free() the pointer returned in *output.
extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len,
int *error, const stb_vorbis_alloc *alloc_buffer);
// create an ogg vorbis decoder from an ogg vorbis stream in memory (note
// this must be the entire stream!). on failure, returns NULL and sets *error
#ifndef STB_VORBIS_NO_STDIO
extern stb_vorbis * stb_vorbis_open_filename(const char *filename,
int *error, const stb_vorbis_alloc *alloc_buffer);
// create an ogg vorbis decoder from a filename via fopen(). on failure,
// returns NULL and sets *error (possibly to VORBIS_file_open_failure).
extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
int *error, const stb_vorbis_alloc *alloc_buffer);
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
// the _current_ seek point (ftell). on failure, returns NULL and sets *error.
// note that stb_vorbis must "own" this stream; if you seek it in between
// calls to stb_vorbis, it will become confused. Morever, if you attempt to
// perform stb_vorbis_seek_*() operations on this file, it will assume it
// owns the _entire_ rest of the file after the start point. Use the next
// function, stb_vorbis_open_file_section(), to limit it.
extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close,
int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len);
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
// the _current_ seek point (ftell); the stream will be of length 'len' bytes.
// on failure, returns NULL and sets *error. note that stb_vorbis must "own"
// this stream; if you seek it in between calls to stb_vorbis, it will become
// confused.
#endif
extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number);
extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
// these functions seek in the Vorbis file to (approximately) 'sample_number'.
// after calling seek_frame(), the next call to get_frame_*() will include
// the specified sample. after calling stb_vorbis_seek(), the next call to
// stb_vorbis_get_samples_* will start with the specified sample. If you
// do not need to seek to EXACTLY the target sample when using get_samples_*,
// you can also use seek_frame().
extern void stb_vorbis_seek_start(stb_vorbis *f);
// this function is equivalent to stb_vorbis_seek(f,0)
extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);
extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f);
// these functions return the total length of the vorbis stream
extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output);
// decode the next frame and return the number of samples. the number of
// channels returned are stored in *channels (which can be NULL--it is always
// the same as the number of channels reported by get_info). *output will
// contain an array of float* buffers, one per channel. These outputs will
// be overwritten on the next call to stb_vorbis_get_frame_*.
//
// You generally should not intermix calls to stb_vorbis_get_frame_*()
// and stb_vorbis_get_samples_*(), since the latter calls the former.
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);
extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples);
#endif
// decode the next frame and return the number of *samples* per channel.
// Note that for interleaved data, you pass in the number of shorts (the
// size of your array), but the return value is the number of samples per
// channel, not the total number of samples.
//
// The data is coerced to the number of channels you request according to the
// channel coercion rules (see below). You must pass in the size of your
// buffer(s) so that stb_vorbis will not overwrite the end of the buffer.
// The maximum buffer size needed can be gotten from get_info(); however,
// the Vorbis I specification implies an absolute maximum of 4096 samples
// per channel.
// Channel coercion rules:
// Let M be the number of channels requested, and N the number of channels present,
// and Cn be the nth channel; let stereo L be the sum of all L and center channels,
// and stereo R be the sum of all R and center channels (channel assignment from the
// vorbis spec).
// M N output
// 1 k sum(Ck) for all k
// 2 * stereo L, stereo R
// k l k > l, the first l channels, then 0s
// k l k <= l, the first k channels
// Note that this is not _good_ surround etc. mixing at all! It's just so
// you get something useful.
extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats);
extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples);
// gets num_samples samples, not necessarily on a frame boundary--this requires
// buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES.
// Returns the number of samples stored per channel; it may be less than requested
// at the end of the file. If there are no more samples in the file, returns 0.
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts);
extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples);
#endif
// gets num_samples samples, not necessarily on a frame boundary--this requires
// buffering so you have to supply the buffers. Applies the coercion rules above
// to produce 'channels' channels. Returns the number of samples stored per channel;
// it may be less than requested at the end of the file. If there are no more
// samples in the file, returns 0.
#endif
//////// ERROR CODES
enum STBVorbisError
{
VORBIS__no_error,
VORBIS_need_more_data=1, // not a real error
VORBIS_invalid_api_mixing, // can't mix API modes
VORBIS_outofmem, // not enough memory
VORBIS_feature_not_supported, // uses floor 0
VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small
VORBIS_file_open_failure, // fopen() failed
VORBIS_seek_without_length, // can't seek in unknown-length file
VORBIS_unexpected_eof=10, // file is truncated?
VORBIS_seek_invalid, // seek past EOF
// decoding errors (corrupt/invalid stream) -- you probably
// don't care about the exact details of these
// vorbis errors:
VORBIS_invalid_setup=20,
VORBIS_invalid_stream,
// ogg errors:
VORBIS_missing_capture_pattern=30,
VORBIS_invalid_stream_structure_version,
VORBIS_continued_packet_flag_invalid,
VORBIS_incorrect_stream_serial_number,
VORBIS_invalid_first_page,
VORBIS_bad_packet_type,
VORBIS_cant_find_last_page,
VORBIS_seek_failed
};
#ifdef __cplusplus
}
#endif
#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H
//
// HEADER ENDS HERE
//
//////////////////////////////////////////////////////////////////////////////

592
raylib/external/tinfl.c vendored Normal file
View file

@ -0,0 +1,592 @@
/* tinfl.c v1.11 - public domain inflate with zlib header parsing/adler32 checking (inflate-only subset of miniz.c)
See "unlicense" statement at the end of this file.
Rich Geldreich <richgel99@gmail.com>, last updated May 20, 2011
Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
The entire decompressor coroutine is implemented in tinfl_decompress(). The other functions are optional high-level helpers.
*/
#ifndef TINFL_HEADER_INCLUDED
#define TINFL_HEADER_INCLUDED
#include <stdlib.h>
typedef unsigned char mz_uint8;
typedef signed short mz_int16;
typedef unsigned short mz_uint16;
typedef unsigned int mz_uint32;
typedef unsigned int mz_uint;
typedef unsigned long long mz_uint64;
#if defined(_M_IX86) || defined(_M_X64)
// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster).
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
#define MINIZ_LITTLE_ENDIAN 1
#endif
#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
// Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator)
#define MINIZ_HAS_64BIT_REGISTERS 1
#endif
// Works around MSVC's spammy "warning C4127: conditional expression is constant" message.
#ifdef _MSC_VER
#define MZ_MACRO_END while (0, 0)
#else
#define MZ_MACRO_END while (0)
#endif
// Decompression flags used by tinfl_decompress().
// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream.
// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input.
// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB).
// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes.
enum
{
TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
TINFL_FLAG_HAS_MORE_INPUT = 2,
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
TINFL_FLAG_COMPUTE_ADLER32 = 8
};
// High level decompression functions:
// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc().
// On entry:
// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress.
// On return:
// Function returns a pointer to the decompressed data, or NULL on failure.
// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data.
// The caller must free() the returned block when it's no longer needed.
void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory.
// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success.
#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer.
// Returns 1 on success or 0 on failure.
typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor;
// Max size of LZ dictionary.
#define TINFL_LZ_DICT_SIZE 32768
// Return status.
typedef enum
{
TINFL_STATUS_BAD_PARAM = -3,
TINFL_STATUS_ADLER32_MISMATCH = -2,
TINFL_STATUS_FAILED = -1,
TINFL_STATUS_DONE = 0,
TINFL_STATUS_NEEDS_MORE_INPUT = 1,
TINFL_STATUS_HAS_MORE_OUTPUT = 2
} tinfl_status;
// Initializes the decompressor to its initial state.
#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END
#define tinfl_get_adler32(r) (r)->m_check_adler32
// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability.
// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output.
tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);
// Internal/private bits follow.
enum
{
TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19,
TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
};
typedef struct
{
mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
} tinfl_huff_table;
#if MINIZ_HAS_64BIT_REGISTERS
#define TINFL_USE_64BIT_BITBUF 1
#endif
#if TINFL_USE_64BIT_BITBUF
typedef mz_uint64 tinfl_bit_buf_t;
#define TINFL_BITBUF_SIZE (64)
#else
typedef mz_uint32 tinfl_bit_buf_t;
#define TINFL_BITBUF_SIZE (32)
#endif
struct tinfl_decompressor_tag
{
mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
tinfl_bit_buf_t m_bit_buf;
size_t m_dist_from_out_buf_start;
tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
};
#endif // #ifdef TINFL_HEADER_INCLUDED
// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.)
#ifndef TINFL_HEADER_FILE_ONLY
#include <string.h>
// MZ_MALLOC, etc. are only used by the optional high-level helper functions.
#ifdef MINIZ_NO_MALLOC
#define MZ_MALLOC(x) NULL
#define MZ_FREE(x) x, ((void)0)
#define MZ_REALLOC(p, x) NULL
#else
#define MZ_MALLOC(x) malloc(x)
#define MZ_FREE(x) free(x)
#define MZ_REALLOC(p, x) realloc(p, x)
#endif
#define MZ_MAX(a,b) (((a)>(b))?(a):(b))
#define MZ_MIN(a,b) (((a)<(b))?(a):(b))
#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
#define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
#define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
#else
#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
#endif
#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
#define TINFL_MEMSET(p, c, l) memset(p, c, l)
#define TINFL_CR_BEGIN switch(r->m_state) { case 0:
#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END
#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END
#define TINFL_CR_FINISH }
// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never
// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario.
#define TINFL_GET_BYTE(state_index, c) do { \
if (pIn_buf_cur >= pIn_buf_end) { \
for ( ; ; ) { \
if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
if (pIn_buf_cur < pIn_buf_end) { \
c = *pIn_buf_cur++; \
break; \
} \
} else { \
c = 0; \
break; \
} \
} \
} else c = *pIn_buf_cur++; } MZ_MACRO_END
#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n))
#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2.
// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a
// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the
// bit buffer contains >=15 bits (deflate's max. Huffman code size).
#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
do { \
temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
if (temp >= 0) { \
code_len = temp >> 9; \
if ((code_len) && (num_bits >= code_len)) \
break; \
} else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
code_len = TINFL_FAST_LOOKUP_BITS; \
do { \
temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
} while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
} TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
} while (num_bits < 15);
// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read
// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully
// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32.
// The slow path is only executed at the very end of the input buffer.
#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
int temp; mz_uint code_len, c; \
if (num_bits < 15) { \
if ((pIn_buf_end - pIn_buf_cur) < 2) { \
TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
} else { \
bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \
} \
} \
if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
code_len = temp >> 9, temp &= 511; \
else { \
code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
} sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END
tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)
{
static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 };
static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
static const int s_min_table_sizes[3] = { 257, 1, 4 };
tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf;
const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;
// Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter).
if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; }
num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start;
TINFL_CR_BEGIN
bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
{
TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1);
counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); }
}
do
{
TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
if (r->m_type == 0)
{
TINFL_SKIP_BITS(5, num_bits & 7);
for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); }
if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); }
while ((counter) && (num_bits))
{
TINFL_GET_BITS(51, dist, 8);
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); }
*pOut_buf_cur++ = (mz_uint8)dist;
counter--;
}
while (counter)
{
size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); }
while (pIn_buf_cur >= pIn_buf_end)
{
if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
{
TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
}
else
{
TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
}
}
n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n;
}
}
else if (r->m_type == 3)
{
TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
}
else
{
if (r->m_type == 1)
{
mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i;
r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8;
}
else
{
for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; }
r->m_table_sizes[2] = 19;
}
for ( ; (int)r->m_type >= 0; r->m_type--)
{
int tree_next, tree_cur; tinfl_huff_table *pTable;
mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree);
for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
if ((65536 != total) && (used_syms > 1))
{
TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
}
for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
{
mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue;
cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; }
if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)
{
tree_cur -= ((rev_code >>= 1) & 1);
if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1];
}
tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
}
if (r->m_type == 2)
{
for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); )
{
mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; }
if ((dist == 16) && (!counter))
{
TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
}
num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16];
TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s;
}
if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
{
TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
}
TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
}
}
for ( ; ; )
{
mz_uint8 *pSrc;
for ( ; ; )
{
if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
{
TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
if (counter >= 256)
break;
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); }
*pOut_buf_cur++ = (mz_uint8)counter;
}
else
{
int sym2; mz_uint code_len;
#if TINFL_USE_64BIT_BITBUF
if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; }
#else
if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
#endif
if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
code_len = sym2 >> 9;
else
{
code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
}
counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
if (counter & 256)
break;
#if !TINFL_USE_64BIT_BITBUF
if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
#endif
if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
code_len = sym2 >> 9;
else
{
code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
}
bit_buf >>= code_len; num_bits -= code_len;
pOut_buf_cur[0] = (mz_uint8)counter;
if (sym2 & 256)
{
pOut_buf_cur++;
counter = sym2;
break;
}
pOut_buf_cur[1] = (mz_uint8)sym2;
pOut_buf_cur += 2;
}
}
if ((counter &= 511) == 256) break;
num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
{
TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
}
pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
{
while (counter--)
{
while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); }
*pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
}
continue;
}
#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
else if ((counter >= 9) && (counter <= dist))
{
const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
do
{
((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
pOut_buf_cur += 8;
} while ((pSrc += 8) < pSrc_end);
if ((counter &= 7) < 3)
{
if (counter)
{
pOut_buf_cur[0] = pSrc[0];
if (counter > 1)
pOut_buf_cur[1] = pSrc[1];
pOut_buf_cur += counter;
}
continue;
}
}
#endif
do
{
pOut_buf_cur[0] = pSrc[0];
pOut_buf_cur[1] = pSrc[1];
pOut_buf_cur[2] = pSrc[2];
pOut_buf_cur += 3; pSrc += 3;
} while ((int)(counter -= 3) > 2);
if ((int)counter > 0)
{
pOut_buf_cur[0] = pSrc[0];
if ((int)counter > 1)
pOut_buf_cur[1] = pSrc[1];
pOut_buf_cur += counter;
}
}
}
} while (!(r->m_final & 1));
if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
{
TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; }
}
TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
TINFL_CR_FINISH
common_exit:
r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start;
*pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
{
const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size;
mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552;
while (buf_len)
{
for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
{
s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
}
for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
}
r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH;
}
return status;
}
// Higher level helper functions.
void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
{
tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0;
*pOut_len = 0;
tinfl_init(&decomp);
for ( ; ; )
{
size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size,
(flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT))
{
MZ_FREE(pBuf); *pOut_len = 0; return NULL;
}
src_buf_ofs += src_buf_size;
*pOut_len += dst_buf_size;
if (status == TINFL_STATUS_DONE) break;
new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
if (!pNew_buf)
{
MZ_FREE(pBuf); *pOut_len = 0; return NULL;
}
pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity;
}
return pBuf;
}
size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
{
tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp);
status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;
}
int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
{
int result = 0;
tinfl_decompressor decomp;
mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0;
if (!pDict)
return TINFL_STATUS_FAILED;
tinfl_init(&decomp);
for ( ; ; )
{
size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
(flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
in_buf_ofs += in_buf_size;
if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
break;
if (status != TINFL_STATUS_HAS_MORE_OUTPUT)
{
result = (status == TINFL_STATUS_DONE);
break;
}
dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
}
MZ_FREE(pDict);
*pIn_buf_size = in_buf_ofs;
return result;
}
#endif // #ifndef TINFL_HEADER_FILE_ONLY
/*
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
*/

523
raylib/gestures.h Normal file
View file

@ -0,0 +1,523 @@
/**********************************************************************************************
*
* raylib Gestures System - Gestures Processing based on input gesture events (touch/mouse)
*
* #define GESTURES_IMPLEMENTATION
* Generates the implementation of the library into the included file.
* If not defined, the library is in header only mode and can be included in other headers
* or source files without problems. But only ONE file should hold the implementation.
*
* #define GESTURES_STANDALONE
* If defined, the library can be used as standalone to process gesture events with
* no external dependencies.
*
* NOTE: Memory footprint of this library is aproximately 128 bytes
*
* Initial design by Marc Palau (2014)
* Redesigned by Albert Martos and Ian Eito (2015)
* Reviewed by Ramon Santamaria (2015-2016)
*
* 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 GESTURES_H
#define GESTURES_H
#ifndef PI
#define PI 3.14159265358979323846
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Types and Structures Definition
// NOTE: Below types are required for GESTURES_STANDALONE usage
//----------------------------------------------------------------------------------
#if defined(GESTURES_STANDALONE)
#ifndef __cplusplus
// Boolean type
typedef enum { false, true } bool;
#endif
// Vector2 type
typedef struct Vector2 {
float x;
float y;
} Vector2;
// Gestures type
// NOTE: It could be used as flags to enable only some gestures
typedef enum {
GESTURE_NONE = 1,
GESTURE_TAP = 2,
GESTURE_DOUBLETAP = 4,
GESTURE_HOLD = 8,
GESTURE_DRAG = 16,
GESTURE_SWIPE_RIGHT = 32,
GESTURE_SWIPE_LEFT = 64,
GESTURE_SWIPE_UP = 128,
GESTURE_SWIPE_DOWN = 256,
GESTURE_PINCH_IN = 512,
GESTURE_PINCH_OUT = 1024
} Gestures;
#endif
typedef enum { TOUCH_UP, TOUCH_DOWN, TOUCH_MOVE } TouchAction;
// Gesture events
// NOTE: MAX_TOUCH_POINTS fixed to 4
typedef struct {
int touchAction;
int pointCount;
int pointerId[4];
Vector2 position[4];
} GestureEvent;
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
void ProcessGestureEvent(GestureEvent event); // Process gesture event and translate it into gestures
void UpdateGestures(void); // Update gestures detected (must be called every frame)
#if defined(GESTURES_STANDALONE)
void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags
bool IsGestureDetected(int gesture); // Check if a gesture have been detected
int GetGestureDetected(void); // Get latest detected gesture
int GetTouchPointsCount(void); // Get touch points count
float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds
Vector2 GetGestureDragVector(void); // Get gesture drag vector
float GetGestureDragAngle(void); // Get gesture drag angle
Vector2 GetGesturePinchVector(void); // Get gesture pinch delta
float GetGesturePinchAngle(void); // Get gesture pinch angle
#endif
#ifdef __cplusplus
}
#endif
#endif // GESTURES_H
/***********************************************************************************
*
* GESTURES IMPLEMENTATION
*
************************************************************************************/
#if defined(GESTURES_IMPLEMENTATION)
#include <math.h> // Required for: atan2(), sqrt()
#include <stdint.h> // Required for: uint64_t
#if defined(_WIN32)
// Functions required to query time on Windows
int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount);
int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency);
#elif defined(__linux)
#include <sys/time.h> // Required for: timespec
#include <time.h> // Required for: clock_gettime()
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define FORCE_TO_SWIPE 0.0005f // Measured in normalized screen units/time
#define MINIMUM_DRAG 0.015f // Measured in normalized screen units (0.0f to 1.0f)
#define MINIMUM_PINCH 0.005f // Measured in normalized screen units (0.0f to 1.0f)
#define TAP_TIMEOUT 300 // Time in milliseconds
#define PINCH_TIMEOUT 300 // Time in milliseconds
#define DOUBLETAP_RANGE 0.03f // Measured in normalized screen units (0.0f to 1.0f)
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// ...
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
// Touch gesture variables
static Vector2 touchDownPosition = { 0.0f, 0.0f };
static Vector2 touchDownPosition2 = { 0.0f, 0.0f };
static Vector2 touchDownDragPosition = { 0.0f, 0.0f };
static Vector2 touchUpPosition = { 0.0f, 0.0f };
static Vector2 moveDownPosition = { 0.0f, 0.0f };
static Vector2 moveDownPosition2 = { 0.0f, 0.0f };
static int pointCount = 0; // Touch points counter
static int firstTouchId = -1; // Touch id for first touch point
static double eventTime = 0.0; // Time stamp when an event happened
// Tap gesture variables
static int tapCounter = 0; // TAP counter (one tap implies TOUCH_DOWN and TOUCH_UP actions)
// Hold gesture variables
static bool resetHold = false; // HOLD reset to get first touch point again
static double timeHold = 0.0f; // HOLD duration in milliseconds
// Drag gesture variables
static Vector2 dragVector = { 0.0f , 0.0f }; // DRAG vector (between initial and current position)
static float dragAngle = 0.0f; // DRAG angle (relative to x-axis)
static float dragDistance = 0.0f; // DRAG distance (from initial touch point to final) (normalized [0..1])
static float dragIntensity = 0.0f; // DRAG intensity, how far why did the DRAG (pixels per frame)
// Swipe gestures variables
static bool startMoving = false; // SWIPE used to define when start measuring swipeTime
static double swipeTime = 0.0; // SWIPE time to calculate drag intensity
// Pinch gesture variables
static Vector2 pinchVector = { 0.0f , 0.0f }; // PINCH vector (between first and second touch points)
static float pinchAngle = 0.0f; // PINCH angle (relative to x-axis)
static float pinchDistance = 0.0f; // PINCH displacement distance (normalized [0..1])
static int currentGesture = GESTURE_NONE; // Current detected gesture
// Enabled gestures flags, all gestures enabled by default
static unsigned int enabledGestures = 0b0000001111111111;
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition);
static float Vector2Distance(Vector2 v1, Vector2 v2);
static double GetCurrentTime(void);
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
// Enable only desired getures to be detected
void SetGesturesEnabled(unsigned int gestureFlags)
{
enabledGestures = gestureFlags;
}
// Check if a gesture have been detected
bool IsGestureDetected(int gesture)
{
if ((enabledGestures & currentGesture) == gesture) return true;
else return false;
}
// Process gesture event and translate it into gestures
void ProcessGestureEvent(GestureEvent event)
{
// Reset required variables
pointCount = event.pointCount; // Required on UpdateGestures()
if (pointCount < 2)
{
if (event.touchAction == TOUCH_DOWN)
{
tapCounter++; // Tap counter
// Detect GESTURE_DOUBLE_TAP
if ((currentGesture == GESTURE_NONE) && (tapCounter >= 2) && ((GetCurrentTime() - eventTime) < TAP_TIMEOUT) && (Vector2Distance(touchDownPosition, event.position[0]) < DOUBLETAP_RANGE))
{
currentGesture = GESTURE_DOUBLETAP;
tapCounter = 0;
}
else // Detect GESTURE_TAP
{
tapCounter = 1;
currentGesture = GESTURE_TAP;
}
touchDownPosition = event.position[0];
touchDownDragPosition = event.position[0];
touchUpPosition = touchDownPosition;
eventTime = GetCurrentTime();
firstTouchId = event.pointerId[0];
dragVector = (Vector2){ 0.0f, 0.0f };
}
else if (event.touchAction == TOUCH_UP)
{
if (currentGesture == GESTURE_DRAG) touchUpPosition = event.position[0];
// NOTE: dragIntensity dependend on the resolution of the screen
dragDistance = Vector2Distance(touchDownPosition, touchUpPosition);
dragIntensity = dragDistance/(float)((GetCurrentTime() - swipeTime));
startMoving = false;
// Detect GESTURE_SWIPE
if ((dragIntensity > FORCE_TO_SWIPE) && (firstTouchId == event.pointerId[0]))
{
// NOTE: Angle should be inverted in Y
dragAngle = 360.0f - Vector2Angle(touchDownPosition, touchUpPosition);
if ((dragAngle < 30) || (dragAngle > 330)) currentGesture = GESTURE_SWIPE_RIGHT; // Right
else if ((dragAngle > 30) && (dragAngle < 120)) currentGesture = GESTURE_SWIPE_UP; // Up
else if ((dragAngle > 120) && (dragAngle < 210)) currentGesture = GESTURE_SWIPE_LEFT; // Left
else if ((dragAngle > 210) && (dragAngle < 300)) currentGesture = GESTURE_SWIPE_DOWN; // Down
else currentGesture = GESTURE_NONE;
}
else
{
dragDistance = 0.0f;
dragIntensity = 0.0f;
dragAngle = 0.0f;
currentGesture = GESTURE_NONE;
}
touchDownDragPosition = (Vector2){ 0.0f, 0.0f };
pointCount = 0;
}
else if (event.touchAction == TOUCH_MOVE)
{
if (currentGesture == GESTURE_DRAG) eventTime = GetCurrentTime();
if (!startMoving)
{
swipeTime = GetCurrentTime();
startMoving = true;
}
moveDownPosition = event.position[0];
if (currentGesture == GESTURE_HOLD)
{
if (resetHold) touchDownPosition = event.position[0];
resetHold = false;
// Detect GESTURE_DRAG
if (Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_DRAG)
{
eventTime = GetCurrentTime();
currentGesture = GESTURE_DRAG;
}
}
dragVector.x = moveDownPosition.x - touchDownDragPosition.x;
dragVector.y = moveDownPosition.y - touchDownDragPosition.y;
}
}
else // Two touch points
{
if (event.touchAction == TOUCH_DOWN)
{
touchDownPosition = event.position[0];
touchDownPosition2 = event.position[1];
//pinchDistance = Vector2Distance(touchDownPosition, touchDownPosition2);
pinchVector.x = touchDownPosition2.x - touchDownPosition.x;
pinchVector.y = touchDownPosition2.y - touchDownPosition.y;
currentGesture = GESTURE_HOLD;
timeHold = GetCurrentTime();
}
else if (event.touchAction == TOUCH_MOVE)
{
pinchDistance = Vector2Distance(moveDownPosition, moveDownPosition2);
touchDownPosition = moveDownPosition;
touchDownPosition2 = moveDownPosition2;
moveDownPosition = event.position[0];
moveDownPosition2 = event.position[1];
pinchVector.x = moveDownPosition2.x - moveDownPosition.x;
pinchVector.y = moveDownPosition2.y - moveDownPosition.y;
if ((Vector2Distance(touchDownPosition, moveDownPosition) >= MINIMUM_PINCH) || (Vector2Distance(touchDownPosition2, moveDownPosition2) >= MINIMUM_PINCH))
{
if ((Vector2Distance(moveDownPosition, moveDownPosition2) - pinchDistance) < 0) currentGesture = GESTURE_PINCH_IN;
else currentGesture = GESTURE_PINCH_OUT;
}
else
{
currentGesture = GESTURE_HOLD;
timeHold = GetCurrentTime();
}
// NOTE: Angle should be inverted in Y
pinchAngle = 360.0f - Vector2Angle(moveDownPosition, moveDownPosition2);
}
else if (event.touchAction == TOUCH_UP)
{
pinchDistance = 0.0f;
pinchAngle = 0.0f;
pinchVector = (Vector2){ 0.0f, 0.0f };
pointCount = 0;
currentGesture = GESTURE_NONE;
}
}
}
// Update gestures detected (must be called every frame)
void UpdateGestures(void)
{
// NOTE: Gestures are processed through system callbacks on touch events
// Detect GESTURE_HOLD
if (((currentGesture == GESTURE_TAP) || (currentGesture == GESTURE_DOUBLETAP)) && (pointCount < 2))
{
currentGesture = GESTURE_HOLD;
timeHold = GetCurrentTime();
}
if (((GetCurrentTime() - eventTime) > TAP_TIMEOUT) && (currentGesture == GESTURE_DRAG) && (pointCount < 2))
{
currentGesture = GESTURE_HOLD;
timeHold = GetCurrentTime();
resetHold = true;
}
// Detect GESTURE_NONE
if ((currentGesture == GESTURE_SWIPE_RIGHT) || (currentGesture == GESTURE_SWIPE_UP) || (currentGesture == GESTURE_SWIPE_LEFT) || (currentGesture == GESTURE_SWIPE_DOWN))
{
currentGesture = GESTURE_NONE;
}
}
// Get number of touch points
int GetTouchPointsCount(void)
{
// NOTE: point count is calculated when ProcessGestureEvent(GestureEvent event) is called
return pointCount;
}
// Get latest detected gesture
int GetGestureDetected(void)
{
// Get current gesture only if enabled
return (enabledGestures & currentGesture);
}
// Hold time measured in ms
float GetGestureHoldDuration(void)
{
// NOTE: time is calculated on current gesture HOLD
double time = 0.0;
if (currentGesture == GESTURE_HOLD) time = GetCurrentTime() - timeHold;
return (float)time;
}
// Get drag vector (between initial touch point to current)
Vector2 GetGestureDragVector(void)
{
// NOTE: drag vector is calculated on one touch points TOUCH_MOVE
return dragVector;
}
// Get drag angle
// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise
float GetGestureDragAngle(void)
{
// NOTE: drag angle is calculated on one touch points TOUCH_UP
return dragAngle;
}
// Get distance between two pinch points
Vector2 GetGesturePinchVector(void)
{
// NOTE: The position values used for pinchDistance are not modified like the position values of [core.c]-->GetTouchPosition(int index)
// NOTE: pinch distance is calculated on two touch points TOUCH_MOVE
return pinchVector;
}
// Get angle beween two pinch points
// NOTE: Angle in degrees, horizontal-right is 0, counterclock-wise
float GetGesturePinchAngle(void)
{
// NOTE: pinch angle is calculated on two touch points TOUCH_MOVE
return pinchAngle;
}
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
// Returns angle from two-points vector with X-axis
static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition)
{
float angle;
angle = atan2f(finalPosition.y - initialPosition.y, finalPosition.x - initialPosition.x)*(180.0f/PI);
if (angle < 0) angle += 360.0f;
return angle;
}
// Calculate distance between two Vector2
static float Vector2Distance(Vector2 v1, Vector2 v2)
{
float result;
float dx = v2.x - v1.x;
float dy = v2.y - v1.y;
result = (float)sqrt(dx*dx + dy*dy);
return result;
}
// Time measure returned are milliseconds
static double GetCurrentTime(void)
{
double time = 0;
#if defined(_WIN32)
unsigned long long int clockFrequency, currentTime;
QueryPerformanceFrequency(&clockFrequency);
QueryPerformanceCounter(&currentTime);
time = (double)currentTime/clockFrequency*1000.0f; // Time in miliseconds
#endif
#if defined(__linux)
// NOTE: Only for Linux-based systems
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
uint64_t nowTime = (uint64_t)now.tv_sec*1000000000LLU + (uint64_t)now.tv_nsec; // Time in nanoseconds
time = ((double)nowTime/1000000.0); // Time in miliseconds
#endif
return time;
}
#endif // GESTURES_IMPLEMENTATION

2001
raylib/models.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -107,87 +107,6 @@ func NewModelFromPointer(ptr unsafe.Pointer) Model {
return *(*Model)(ptr)
}
// Light type
type Light struct {
// Light unique id
Id uint32
// Light enabled
Enabled uint32
// Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT
Type int32
// Light position
Position Vector3
// Light direction: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target)
Target Vector3
// Light attenuation radius light intensity reduced with distance (world distance)
Radius float32
// Light diffuse color
Diffuse Color
// Light intensity level
Intensity float32
// Light cone max angle: LIGHT_SPOT
ConeAngle float32
}
func (l *Light) cptr() *C.Light {
return (*C.Light)(unsafe.Pointer(l))
}
// Returns new Light
func NewLight(id uint32, enabled uint32, _type int32, position, target Vector3, radius float32, diffuse Color, intensity, coneAngle float32) Light {
return Light{id, enabled, _type, position, target, radius, diffuse, intensity, coneAngle}
}
// Returns new Light from pointer
func NewLightFromPointer(ptr unsafe.Pointer) Light {
return *(*Light)(ptr)
}
type LightType int32
// Light types
const (
LightPoint LightType = C.LIGHT_POINT
LightDirectional LightType = C.LIGHT_DIRECTIONAL
LightSpot LightType = C.LIGHT_SPOT
)
// LightData type
type LightData struct {
// Light unique id
Id uint32
// Light enabled
Enabled uint32
// Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT
Type int32
// Light position
Position Vector3
// Light direction: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target)
Target Vector3
// Light attenuation radius light intensity reduced with distance (world distance)
Radius float32
// Light diffuse color
Diffuse Color
// Light intensity level
Intensity float32
// Light cone max angle: LIGHT_SPOT
ConeAngle float32
}
func (l *LightData) cptr() *C.LightData {
return (*C.LightData)(unsafe.Pointer(l))
}
// Returns new LightData
func NewLightData(l Light) LightData {
return LightData{l.Id, l.Enabled, l.Type, l.Position, l.Target, l.Radius, l.Diffuse, l.Intensity, l.ConeAngle}
}
// Returns new Light from pointer
func NewLightDataFromPointer(ptr unsafe.Pointer) LightData {
return *(*LightData)(ptr)
}
// Ray type (useful for raycast)
type Ray struct {
// Ray position (origin)
@ -345,12 +264,6 @@ func DrawGizmo(position Vector3) {
C.DrawGizmo(*cposition)
}
// Draw light in 3D world
func DrawLight(light Light) {
clightdata := NewLightData(light)
C.DrawLight(clightdata.cptr())
}
// Load a 3d model (.OBJ)
func LoadModel(fileName string) Model {
cfileName := C.CString(fileName)
@ -360,29 +273,6 @@ func LoadModel(fileName string) Model {
return v
}
// Load a 3d model (from mesh data)
func LoadModelEx(data Mesh, dynamic bool) Model {
d := 0
if dynamic {
d = 1
}
cdata := data.cptr()
cdynamic := (C.bool)(d)
ret := C.LoadModelEx(*cdata, cdynamic)
v := NewModelFromPointer(unsafe.Pointer(&ret))
return v
}
// Load a 3d model from rRES file (raylib Resource)
func LoadModelFromRES(rresName string, resId int32) Model {
crresName := C.CString(rresName)
defer C.free(unsafe.Pointer(crresName))
cresId := (C.int)(resId)
ret := C.LoadModelFromRES(crresName, cresId)
v := NewModelFromPointer(unsafe.Pointer(&ret))
return v
}
// Load a heightmap image as a 3d model
func LoadHeightmap(heightmap *Image, size Vector3) Model {
cheightmap := heightmap.cptr()
@ -422,13 +312,6 @@ func LoadDefaultMaterial() Material {
return v
}
// Load standard material (uses material attributes and lighting shader)
func LoadStandardMaterial() Material {
ret := C.LoadStandardMaterial()
v := NewMaterialFromPointer(unsafe.Pointer(&ret))
return v
}
// Unload material textures from VRAM
func UnloadMaterial(material Material) {
cmaterial := material.cptr()

990
raylib/raylib.h Normal file
View file

@ -0,0 +1,990 @@
/**********************************************************************************************
*
* raylib 1.6.0 (www.raylib.com)
*
* A simple and easy-to-use library to learn videogames programming
*
* Features:
* Library written in plain C code (C99)
* Uses PascalCase/camelCase notation
* Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES 2.0)
* Unique OpenGL abstraction layer (usable as standalone module): [rlgl]
* Powerful fonts module with SpriteFonts support (XNA bitmap fonts, AngelCode fonts, TTF)
* Multiple textures support, including compressed formats and mipmaps generation
* Basic 3d support for Shapes, Models, Billboards, Heightmaps and Cubicmaps
* Powerful math module for Vector, Matrix and Quaternion operations: [raymath]
* Audio loading and playing with streaming support and mixing channels [audio]
* VR stereo rendering support with configurable HMD device parameters
* Multiple platforms support: Windows, Linux, Mac, Android, Raspberry Pi, HTML5 and Oculus Rift CV1
* Custom color palette for fancy visuals on raywhite background
* Minimal external dependencies (GLFW3, OpenGL, OpenAL)
* Complete binding for Lua [rlua]
*
* External libs:
* GLFW3 (www.glfw.org) for window/context management and input [core]
* GLAD for OpenGL extensions loading (3.3 Core profile, only PLATFORM_DESKTOP) [rlgl]
* stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA) [textures]
* stb_image_write (Sean Barret) for image writting (PNG) [utils]
* stb_truetype (Sean Barret) for ttf fonts loading [text]
* stb_vorbis (Sean Barret) for ogg audio loading [audio]
* jar_xm (Joshua Reisenauer) for XM audio module loading [audio]
* jar_mod (Joshua Reisenauer) for MOD audio module loading [audio]
* dr_flac (David Reid) for FLAC audio file loading [audio]
* OpenAL Soft for audio device/context management [audio]
* tinfl for data decompression (DEFLATE algorithm) [utils]
*
* Some design decisions:
* 32bit Colors - All defined color are always RGBA (struct Color is 4 byte)
* One custom default font could be loaded automatically when InitWindow() [core]
* If using OpenGL 3.3 or ES2, several vertex buffers (VAO/VBO) are created to manage lines-triangles-quads
* If using OpenGL 3.3 or ES2, two default shaders could be loaded automatically (internally defined)
*
* -- LICENSE --
*
* raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software:
*
* Copyright (c) 2013-2016 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* 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 RAYLIB_H
#define RAYLIB_H
// Choose your platform here or just define it at compile time: -DPLATFORM_DESKTOP
//#define PLATFORM_DESKTOP // Windows, Linux or OSX
//#define PLATFORM_ANDROID // Android device
//#define PLATFORM_RPI // Raspberry Pi
//#define PLATFORM_WEB // HTML5 (emscripten, asm.js)
//#define RLGL_OCULUS_SUPPORT // Oculus Rift CV1 (complementary to PLATFORM_DESKTOP)
// Security check in case no PLATFORM_* defined
#if !defined(PLATFORM_DESKTOP) && !defined(PLATFORM_ANDROID) && !defined(PLATFORM_RPI) && !defined(PLATFORM_WEB)
#define PLATFORM_DESKTOP
#endif
#if defined(_WIN32) && defined(BUILDING_DLL)
#define RLAPI __declspec(dllexport) // We are building raylib as a Win32 DLL
#elif defined(_WIN32) && defined(RAYLIB_DLL)
#define RLAPI __declspec(dllimport) // We are using raylib as a Win32 DLL
#else
#define RLAPI // We are building or using raylib as a static library (or Linux shared library)
#endif
//----------------------------------------------------------------------------------
// Some basic Defines
//----------------------------------------------------------------------------------
#ifndef PI
#define PI 3.14159265358979323846f
#endif
#define DEG2RAD (PI/180.0f)
#define RAD2DEG (180.0f/PI)
// raylib Config Flags
#define FLAG_FULLSCREEN_MODE 1
#define FLAG_RESIZABLE_WINDOW 2
#define FLAG_SHOW_LOGO 4
#define FLAG_SHOW_MOUSE_CURSOR 8
#define FLAG_CENTERED_MODE 16
#define FLAG_MSAA_4X_HINT 32
#define FLAG_VSYNC_HINT 64
// Keyboard Function Keys
#define KEY_SPACE 32
#define KEY_ESCAPE 256
#define KEY_ENTER 257
#define KEY_BACKSPACE 259
#define KEY_RIGHT 262
#define KEY_LEFT 263
#define KEY_DOWN 264
#define KEY_UP 265
#define KEY_F1 290
#define KEY_F2 291
#define KEY_F3 292
#define KEY_F4 293
#define KEY_F5 294
#define KEY_F6 295
#define KEY_F7 296
#define KEY_F8 297
#define KEY_F9 298
#define KEY_F10 299
#define KEY_F11 300
#define KEY_F12 301
#define KEY_LEFT_SHIFT 340
#define KEY_LEFT_CONTROL 341
#define KEY_LEFT_ALT 342
#define KEY_RIGHT_SHIFT 344
#define KEY_RIGHT_CONTROL 345
#define KEY_RIGHT_ALT 346
// Keyboard Alpha Numeric Keys
#define KEY_ZERO 48
#define KEY_ONE 49
#define KEY_TWO 50
#define KEY_THREE 51
#define KEY_FOUR 52
#define KEY_FIVE 53
#define KEY_SIX 54
#define KEY_SEVEN 55
#define KEY_EIGHT 56
#define KEY_NINE 57
#define KEY_A 65
#define KEY_B 66
#define KEY_C 67
#define KEY_D 68
#define KEY_E 69
#define KEY_F 70
#define KEY_G 71
#define KEY_H 72
#define KEY_I 73
#define KEY_J 74
#define KEY_K 75
#define KEY_L 76
#define KEY_M 77
#define KEY_N 78
#define KEY_O 79
#define KEY_P 80
#define KEY_Q 81
#define KEY_R 82
#define KEY_S 83
#define KEY_T 84
#define KEY_U 85
#define KEY_V 86
#define KEY_W 87
#define KEY_X 88
#define KEY_Y 89
#define KEY_Z 90
#if defined(PLATFORM_ANDROID)
// Android Physical Buttons
#define KEY_BACK 4
#define KEY_MENU 82
#define KEY_VOLUME_UP 24
#define KEY_VOLUME_DOWN 25
#endif
// Mouse Buttons
#define MOUSE_LEFT_BUTTON 0
#define MOUSE_RIGHT_BUTTON 1
#define MOUSE_MIDDLE_BUTTON 2
// Touch points registered
#define MAX_TOUCH_POINTS 2
// Gamepad Number
#define GAMEPAD_PLAYER1 0
#define GAMEPAD_PLAYER2 1
#define GAMEPAD_PLAYER3 2
#define GAMEPAD_PLAYER4 3
// Gamepad Buttons/Axis
// PS3 USB Controller Buttons
#define GAMEPAD_PS3_BUTTON_TRIANGLE 0
#define GAMEPAD_PS3_BUTTON_CIRCLE 1
#define GAMEPAD_PS3_BUTTON_CROSS 2
#define GAMEPAD_PS3_BUTTON_SQUARE 3
#define GAMEPAD_PS3_BUTTON_L1 6
#define GAMEPAD_PS3_BUTTON_R1 7
#define GAMEPAD_PS3_BUTTON_L2 4
#define GAMEPAD_PS3_BUTTON_R2 5
#define GAMEPAD_PS3_BUTTON_START 8
#define GAMEPAD_PS3_BUTTON_SELECT 9
#define GAMEPAD_PS3_BUTTON_UP 24
#define GAMEPAD_PS3_BUTTON_RIGHT 25
#define GAMEPAD_PS3_BUTTON_DOWN 26
#define GAMEPAD_PS3_BUTTON_LEFT 27
#define GAMEPAD_PS3_BUTTON_PS 12
// PS3 USB Controller Axis
#define GAMEPAD_PS3_AXIS_LEFT_X 0
#define GAMEPAD_PS3_AXIS_LEFT_Y 1
#define GAMEPAD_PS3_AXIS_RIGHT_X 2
#define GAMEPAD_PS3_AXIS_RIGHT_Y 5
#define GAMEPAD_PS3_AXIS_L2 3 // [1..-1] (pressure-level)
#define GAMEPAD_PS3_AXIS_R2 4 // [1..-1] (pressure-level)
// Xbox360 USB Controller Buttons
#define GAMEPAD_XBOX_BUTTON_A 0
#define GAMEPAD_XBOX_BUTTON_B 1
#define GAMEPAD_XBOX_BUTTON_X 2
#define GAMEPAD_XBOX_BUTTON_Y 3
#define GAMEPAD_XBOX_BUTTON_LB 4
#define GAMEPAD_XBOX_BUTTON_RB 5
#define GAMEPAD_XBOX_BUTTON_SELECT 6
#define GAMEPAD_XBOX_BUTTON_START 7
#define GAMEPAD_XBOX_BUTTON_UP 10
#define GAMEPAD_XBOX_BUTTON_RIGHT 11
#define GAMEPAD_XBOX_BUTTON_DOWN 12
#define GAMEPAD_XBOX_BUTTON_LEFT 13
#define GAMEPAD_XBOX_BUTTON_HOME 8
// Xbox360 USB Controller Axis
// NOTE: For Raspberry Pi, axis must be reconfigured
#if defined(PLATFORM_RPI)
#define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right)
#define GAMEPAD_XBOX_AXIS_LEFT_Y 1 // [-1..1] (up->down)
#define GAMEPAD_XBOX_AXIS_RIGHT_X 3 // [-1..1] (left->right)
#define GAMEPAD_XBOX_AXIS_RIGHT_Y 4 // [-1..1] (up->down)
#define GAMEPAD_XBOX_AXIS_LT 2 // [-1..1] (pressure-level)
#define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level)
#else
#define GAMEPAD_XBOX_AXIS_LEFT_X 0 // [-1..1] (left->right)
#define GAMEPAD_XBOX_AXIS_LEFT_Y 1 // [1..-1] (up->down)
#define GAMEPAD_XBOX_AXIS_RIGHT_X 2 // [-1..1] (left->right)
#define GAMEPAD_XBOX_AXIS_RIGHT_Y 3 // [1..-1] (up->down)
#define GAMEPAD_XBOX_AXIS_LT 4 // [-1..1] (pressure-level)
#define GAMEPAD_XBOX_AXIS_RT 5 // [-1..1] (pressure-level)
#endif
// NOTE: MSC C++ compiler does not support compound literals (C99 feature)
// Plain structures in C++ (without constructors) can be initialized from { } initializers.
#ifdef __cplusplus
#define CLITERAL
#else
#define CLITERAL (Color)
#endif
// Some Basic Colors
// NOTE: Custom raylib color palette for amazing visuals on WHITE background
#define LIGHTGRAY CLITERAL{ 200, 200, 200, 255 } // Light Gray
#define GRAY CLITERAL{ 130, 130, 130, 255 } // Gray
#define DARKGRAY CLITERAL{ 80, 80, 80, 255 } // Dark Gray
#define YELLOW CLITERAL{ 253, 249, 0, 255 } // Yellow
#define GOLD CLITERAL{ 255, 203, 0, 255 } // Gold
#define ORANGE CLITERAL{ 255, 161, 0, 255 } // Orange
#define PINK CLITERAL{ 255, 109, 194, 255 } // Pink
#define RED CLITERAL{ 230, 41, 55, 255 } // Red
#define MAROON CLITERAL{ 190, 33, 55, 255 } // Maroon
#define GREEN CLITERAL{ 0, 228, 48, 255 } // Green
#define LIME CLITERAL{ 0, 158, 47, 255 } // Lime
#define DARKGREEN CLITERAL{ 0, 117, 44, 255 } // Dark Green
#define SKYBLUE CLITERAL{ 102, 191, 255, 255 } // Sky Blue
#define BLUE CLITERAL{ 0, 121, 241, 255 } // Blue
#define DARKBLUE CLITERAL{ 0, 82, 172, 255 } // Dark Blue
#define PURPLE CLITERAL{ 200, 122, 255, 255 } // Purple
#define VIOLET CLITERAL{ 135, 60, 190, 255 } // Violet
#define DARKPURPLE CLITERAL{ 112, 31, 126, 255 } // Dark Purple
#define BEIGE CLITERAL{ 211, 176, 131, 255 } // Beige
#define BROWN CLITERAL{ 127, 106, 79, 255 } // Brown
#define DARKBROWN CLITERAL{ 76, 63, 47, 255 } // Dark Brown
#define WHITE CLITERAL{ 255, 255, 255, 255 } // White
#define BLACK CLITERAL{ 0, 0, 0, 255 } // Black
#define BLANK CLITERAL{ 0, 0, 0, 0 } // Blank (Transparent)
#define MAGENTA CLITERAL{ 255, 0, 255, 255 } // Magenta
#define RAYWHITE CLITERAL{ 245, 245, 245, 255 } // My own White (raylib logo)
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
#ifndef __cplusplus
// Boolean type
#ifndef __APPLE__
#if !defined(_STDBOOL_H)
typedef enum { false, true } bool;
#define _STDBOOL_H
#endif
#else
#include <stdbool.h>
#endif
#endif
// Vector2 type
typedef struct Vector2 {
float x;
float y;
} Vector2;
// Vector3 type
typedef struct Vector3 {
float x;
float y;
float z;
} Vector3;
// Matrix type (OpenGL style 4x4 - right handed, column major)
typedef struct Matrix {
float m0, m4, m8, m12;
float m1, m5, m9, m13;
float m2, m6, m10, m14;
float m3, m7, m11, m15;
} Matrix;
// Color type, RGBA (32bit)
typedef struct Color {
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
} Color;
// Rectangle type
typedef struct Rectangle {
int x;
int y;
int width;
int height;
} Rectangle;
// Image type, bpp always RGBA (32bit)
// NOTE: Data stored in CPU memory (RAM)
typedef struct Image {
void *data; // Image raw data
int width; // Image base width
int height; // Image base height
int mipmaps; // Mipmap levels, 1 by default
int format; // Data format (TextureFormat type)
} Image;
// Texture2D type, bpp always RGBA (32bit)
// NOTE: Data stored in GPU memory
typedef struct Texture2D {
unsigned int id; // OpenGL texture id
int width; // Texture base width
int height; // Texture base height
int mipmaps; // Mipmap levels, 1 by default
int format; // Data format (TextureFormat type)
} Texture2D;
// RenderTexture2D type, for texture rendering
typedef struct RenderTexture2D {
unsigned int id; // OpenGL Framebuffer Object (FBO) id
Texture2D texture; // Color buffer attachment texture
Texture2D depth; // Depth buffer attachment texture
} RenderTexture2D;
// SpriteFont type, includes texture and charSet array data
typedef struct SpriteFont {
Texture2D texture; // Font texture
int size; // Base size (default chars height)
int numChars; // Number of characters
int *charValues; // Characters values array
Rectangle *charRecs; // Characters rectangles within the texture
Vector2 *charOffsets; // Characters offsets (on drawing)
int *charAdvanceX; // Characters x advance (on drawing)
} SpriteFont;
// Camera type, defines a camera position/orientation in 3d space
typedef struct Camera {
Vector3 position; // Camera position
Vector3 target; // Camera target it looks-at
Vector3 up; // Camera up vector (rotation over its axis)
float fovy; // Camera field-of-view apperture in Y (degrees)
} Camera;
// Camera2D type, defines a 2d camera
typedef struct Camera2D {
Vector2 offset; // Camera offset (displacement from target)
Vector2 target; // Camera target (rotation and zoom origin)
float rotation; // Camera rotation in degrees
float zoom; // Camera zoom (scaling), should be 1.0f by default
} Camera2D;
// Bounding box type
typedef struct BoundingBox {
Vector3 min; // minimum vertex box-corner
Vector3 max; // maximum vertex box-corner
} BoundingBox;
// Vertex data definning a mesh
typedef struct Mesh {
int vertexCount; // number of vertices stored in arrays
int triangleCount; // number of triangles stored (indexed or not)
float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0)
float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5)
float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4)
unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
unsigned short *indices;// vertex indices (in case vertex data comes indexed)
unsigned int vaoId; // OpenGL Vertex Array Object id
unsigned int vboId[7]; // OpenGL Vertex Buffer Objects id (7 types of vertex data)
} Mesh;
// Shader type (generic shader)
typedef struct Shader {
unsigned int id; // Shader program id
// Vertex attributes locations (default locations)
int vertexLoc; // Vertex attribute location point (default-location = 0)
int texcoordLoc; // Texcoord attribute location point (default-location = 1)
int texcoord2Loc; // Texcoord2 attribute location point (default-location = 5)
int normalLoc; // Normal attribute location point (default-location = 2)
int tangentLoc; // Tangent attribute location point (default-location = 4)
int colorLoc; // Color attibute location point (default-location = 3)
// Uniform locations
int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader)
int colDiffuseLoc; // Diffuse color uniform location point (fragment shader)
int colAmbientLoc; // Ambient color uniform location point (fragment shader)
int colSpecularLoc; // Specular color uniform location point (fragment shader)
// Texture map locations (generic for any kind of map)
int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0)
int mapTexture1Loc; // Map texture uniform location point (default-texture-unit = 1)
int mapTexture2Loc; // Map texture uniform location point (default-texture-unit = 2)
} Shader;
// Material type
typedef struct Material {
Shader shader; // Standard shader (supports 3 map textures)
Texture2D texDiffuse; // Diffuse texture (binded to shader mapTexture0Loc)
Texture2D texNormal; // Normal texture (binded to shader mapTexture1Loc)
Texture2D texSpecular; // Specular texture (binded to shader mapTexture2Loc)
Color colDiffuse; // Diffuse color
Color colAmbient; // Ambient color
Color colSpecular; // Specular color
float glossiness; // Glossiness level (Ranges from 0 to 1000)
} Material;
// Model type
typedef struct Model {
Mesh mesh; // Vertex data buffers (RAM and VRAM)
Matrix transform; // Local transform matrix
Material material; // Shader and textures data
} Model;
// Ray type (useful for raycast)
typedef struct Ray {
Vector3 position; // Ray position (origin)
Vector3 direction; // Ray direction
} Ray;
// Information returned from a raycast
typedef struct RayHitInfo {
bool hit; // Did the ray hit something?
float distance; // Distance to nearest hit
Vector3 hitPosition; // Position of nearest hit
Vector3 hitNormal; // Surface normal of hit
} RayHitInfo;
// Wave type, defines audio wave data
typedef struct Wave {
unsigned int sampleCount; // Number of samples
unsigned int sampleRate; // Frequency (samples per second)
unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
unsigned int channels; // Number of channels (1-mono, 2-stereo)
void *data; // Buffer data pointer
} Wave;
// Sound source type
typedef struct Sound {
unsigned int source; // OpenAL audio source id
unsigned int buffer; // OpenAL audio buffer id
int format; // OpenAL audio format specifier
} Sound;
// Music type (file streaming from memory)
// NOTE: Anything longer than ~10 seconds should be streamed
typedef struct MusicData *Music;
// Audio stream type
// NOTE: Useful to create custom audio streams not bound to a specific file
typedef struct AudioStream {
unsigned int sampleRate; // Frequency (samples per second)
unsigned int sampleSize; // Bit depth (bits per sample): 8, 16, 32 (24 not supported)
unsigned int channels; // Number of channels (1-mono, 2-stereo)
int format; // OpenAL audio format specifier
unsigned int source; // OpenAL audio source id
unsigned int buffers[2]; // OpenAL audio buffers (double buffering)
} AudioStream;
// Texture formats
// NOTE: Support depends on OpenGL version and platform
typedef enum {
UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha)
UNCOMPRESSED_GRAY_ALPHA, // 16 bpp (2 channels)
UNCOMPRESSED_R5G6B5, // 16 bpp
UNCOMPRESSED_R8G8B8, // 24 bpp
UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha)
UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha)
UNCOMPRESSED_R8G8B8A8, // 32 bpp
COMPRESSED_DXT1_RGB, // 4 bpp (no alpha)
COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha)
COMPRESSED_DXT3_RGBA, // 8 bpp
COMPRESSED_DXT5_RGBA, // 8 bpp
COMPRESSED_ETC1_RGB, // 4 bpp
COMPRESSED_ETC2_RGB, // 4 bpp
COMPRESSED_ETC2_EAC_RGBA, // 8 bpp
COMPRESSED_PVRT_RGB, // 4 bpp
COMPRESSED_PVRT_RGBA, // 4 bpp
COMPRESSED_ASTC_4x4_RGBA, // 8 bpp
COMPRESSED_ASTC_8x8_RGBA // 2 bpp
} TextureFormat;
// Texture parameters: filter mode
// NOTE 1: Filtering considers mipmaps if available in the texture
// NOTE 2: Filter is accordingly set for minification and magnification
typedef enum {
FILTER_POINT = 0, // No filter, just pixel aproximation
FILTER_BILINEAR, // Linear filtering
FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps)
FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x
FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x
FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x
} TextureFilterMode;
// Texture parameters: wrap mode
typedef enum { WRAP_REPEAT = 0, WRAP_CLAMP, WRAP_MIRROR } TextureWrapMode;
// Color blending modes (pre-defined)
typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode;
// Gestures type
// NOTE: It could be used as flags to enable only some gestures
typedef enum {
GESTURE_NONE = 0,
GESTURE_TAP = 1,
GESTURE_DOUBLETAP = 2,
GESTURE_HOLD = 4,
GESTURE_DRAG = 8,
GESTURE_SWIPE_RIGHT = 16,
GESTURE_SWIPE_LEFT = 32,
GESTURE_SWIPE_UP = 64,
GESTURE_SWIPE_DOWN = 128,
GESTURE_PINCH_IN = 256,
GESTURE_PINCH_OUT = 512
} Gestures;
// Camera system modes
typedef enum {
CAMERA_CUSTOM = 0,
CAMERA_FREE,
CAMERA_ORBITAL,
CAMERA_FIRST_PERSON,
CAMERA_THIRD_PERSON
} CameraMode;
// Head Mounted Display devices
typedef enum {
HMD_DEFAULT_DEVICE = 0,
HMD_OCULUS_RIFT_DK2,
HMD_OCULUS_RIFT_CV1,
HMD_VALVE_HTC_VIVE,
HMD_SAMSUNG_GEAR_VR,
HMD_GOOGLE_CARDBOARD,
HMD_SONY_PLAYSTATION_VR,
HMD_RAZER_OSVR,
HMD_FOVE_VR,
} VrDevice;
// rRES data returned when reading a resource, it contains all required data for user (24 byte)
typedef struct {
unsigned int type; // Resource type (4 byte)
unsigned int param1; // Resouce parameter 1 (4 byte)
unsigned int param2; // Resouce parameter 2 (4 byte)
unsigned int param3; // Resouce parameter 3 (4 byte)
unsigned int param4; // Resouce parameter 4 (4 byte)
void *data; // Resource data pointer (4 byte)
} RRESData;
typedef enum {
RRES_RAW = 0,
RRES_IMAGE,
RRES_WAVE,
RRES_VERTEX,
RRES_TEXT
} RRESDataType;
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
//------------------------------------------------------------------------------------
// Global Variables Definition
//------------------------------------------------------------------------------------
// It's lonely here...
//------------------------------------------------------------------------------------
// Window and Graphics Device Functions (Module: core)
//------------------------------------------------------------------------------------
#if defined(PLATFORM_ANDROID)
RLAPI void InitWindow(int width, int height, void *state); // Init Android Activity and OpenGL Graphics (struct android_app)
#elif defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
RLAPI void InitWindow(int width, int height, const char *title); // Initialize Window and OpenGL Graphics
#endif
RLAPI void CloseWindow(void); // Close Window and Terminate Context
RLAPI bool WindowShouldClose(void); // Detect if KEY_ESCAPE pressed or Close icon pressed
RLAPI bool IsWindowMinimized(void); // Detect if window has been minimized (or lost focus)
RLAPI void ToggleFullscreen(void); // Fullscreen toggle (only PLATFORM_DESKTOP)
RLAPI int GetScreenWidth(void); // Get current screen width
RLAPI int GetScreenHeight(void); // Get current screen height
#if !defined(PLATFORM_ANDROID)
RLAPI void ShowCursor(void); // Shows cursor
RLAPI void HideCursor(void); // Hides cursor
RLAPI bool IsCursorHidden(void); // Returns true if cursor is not visible
RLAPI void EnableCursor(void); // Enables cursor
RLAPI void DisableCursor(void); // Disables cursor
#endif
RLAPI void ClearBackground(Color color); // Sets Background Color
RLAPI void BeginDrawing(void); // Setup drawing canvas to start drawing
RLAPI void EndDrawing(void); // End canvas drawing and Swap Buffers (Double Buffering)
RLAPI void Begin2dMode(Camera2D camera); // Initialize 2D mode with custom camera
RLAPI void End2dMode(void); // Ends 2D mode custom camera usage
RLAPI void Begin3dMode(Camera camera); // Initializes 3D mode for drawing (Camera setup)
RLAPI void End3dMode(void); // Ends 3D mode and returns to default 2D orthographic mode
RLAPI void BeginTextureMode(RenderTexture2D target); // Initializes render texture for drawing
RLAPI void EndTextureMode(void); // Ends drawing to render texture
RLAPI Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position
RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position from a 3d world space position
RLAPI Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix)
RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum)
RLAPI int GetFPS(void); // Returns current FPS (rounded value)
RLAPI float GetFrameTime(void); // Returns time in seconds for one frame (rounded value)
RLAPI Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value
RLAPI int GetHexValue(Color color); // Returns hexadecimal value for a Color
RLAPI float *ColorToFloat(Color color); // Converts Color to float array and normalizes
RLAPI float *VectorToFloat(Vector3 vec); // Converts Vector3 to float array
RLAPI float *MatrixToFloat(Matrix mat); // Converts Matrix to float array
RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included)
RLAPI Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
RLAPI void SetConfigFlags(char flags); // Setup some window configuration flags
RLAPI void ShowLogo(void); // Activates raylib logo at startup (can be done with flags)
RLAPI bool IsFileDropped(void); // Check if a file have been dropped into window
RLAPI char **GetDroppedFiles(int *count); // Retrieve dropped files into window
RLAPI void ClearDroppedFiles(void); // Clear dropped files paths buffer
RLAPI void StorageSaveValue(int position, int value); // Storage save integer value (to defined position)
RLAPI int StorageLoadValue(int position); // Storage load integer value (from defined position)
//------------------------------------------------------------------------------------
// Input Handling Functions (Module: core)
//------------------------------------------------------------------------------------
RLAPI bool IsKeyPressed(int key); // Detect if a key has been pressed once
RLAPI bool IsKeyDown(int key); // Detect if a key is being pressed
RLAPI bool IsKeyReleased(int key); // Detect if a key has been released once
RLAPI bool IsKeyUp(int key); // Detect if a key is NOT being pressed
RLAPI int GetKeyPressed(void); // Get latest key pressed
RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC)
RLAPI bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available
RLAPI bool IsGamepadName(int gamepad, const char *name); // Check gamepad name (if available)
RLAPI const char *GetGamepadName(int gamepad); // Return gamepad internal name id
RLAPI bool IsGamepadButtonPressed(int gamepad, int button); // Detect if a gamepad button has been pressed once
RLAPI bool IsGamepadButtonDown(int gamepad, int button); // Detect if a gamepad button is being pressed
RLAPI bool IsGamepadButtonReleased(int gamepad, int button); // Detect if a gamepad button has been released once
RLAPI bool IsGamepadButtonUp(int gamepad, int button); // Detect if a gamepad button is NOT being pressed
RLAPI int GetGamepadButtonPressed(void); // Get the last gamepad button pressed
RLAPI int GetGamepadAxisCount(int gamepad); // Return gamepad axis count for a gamepad
RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis
RLAPI bool IsMouseButtonPressed(int button); // Detect if a mouse button has been pressed once
RLAPI bool IsMouseButtonDown(int button); // Detect if a mouse button is being pressed
RLAPI bool IsMouseButtonReleased(int button); // Detect if a mouse button has been released once
RLAPI bool IsMouseButtonUp(int button); // Detect if a mouse button is NOT being pressed
RLAPI int GetMouseX(void); // Returns mouse position X
RLAPI int GetMouseY(void); // Returns mouse position Y
RLAPI Vector2 GetMousePosition(void); // Returns mouse position XY
RLAPI void SetMousePosition(Vector2 position); // Set mouse position XY
RLAPI int GetMouseWheelMove(void); // Returns mouse wheel movement Y
RLAPI int GetTouchX(void); // Returns touch position X for touch point 0 (relative to screen size)
RLAPI int GetTouchY(void); // Returns touch position Y for touch point 0 (relative to screen size)
RLAPI Vector2 GetTouchPosition(int index); // Returns touch position XY for a touch point index (relative to screen size)
//------------------------------------------------------------------------------------
// Gestures and Touch Handling Functions (Module: gestures)
//------------------------------------------------------------------------------------
RLAPI void SetGesturesEnabled(unsigned int gestureFlags); // Enable a set of gestures using flags
RLAPI bool IsGestureDetected(int gesture); // Check if a gesture have been detected
RLAPI int GetGestureDetected(void); // Get latest detected gesture
RLAPI int GetTouchPointsCount(void); // Get touch points count
RLAPI float GetGestureHoldDuration(void); // Get gesture hold time in milliseconds
RLAPI Vector2 GetGestureDragVector(void); // Get gesture drag vector
RLAPI float GetGestureDragAngle(void); // Get gesture drag angle
RLAPI Vector2 GetGesturePinchVector(void); // Get gesture pinch delta
RLAPI float GetGesturePinchAngle(void); // Get gesture pinch angle
//------------------------------------------------------------------------------------
// Camera System Functions (Module: camera)
//------------------------------------------------------------------------------------
RLAPI void SetCameraMode(Camera camera, int mode); // Set camera mode (multiple camera modes available)
RLAPI void UpdateCamera(Camera *camera); // Update camera position for selected mode
RLAPI void SetCameraPanControl(int panKey); // Set camera pan key to combine with mouse movement (free camera)
RLAPI void SetCameraAltControl(int altKey); // Set camera alt key to combine with mouse movement (free camera)
RLAPI void SetCameraSmoothZoomControl(int szKey); // Set camera smooth zoom key to combine with mouse (free camera)
RLAPI void SetCameraMoveControls(int frontKey, int backKey,
int rightKey, int leftKey,
int upKey, int downKey); // Set camera move controls (1st person and 3rd person cameras)
//------------------------------------------------------------------------------------
// Basic Shapes Drawing Functions (Module: shapes)
//------------------------------------------------------------------------------------
RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel
RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel (Vector version)
RLAPI void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line
RLAPI void DrawLineV(Vector2 startPos, Vector2 endPos, Color color); // Draw a line (Vector version)
RLAPI void DrawCircle(int centerX, int centerY, float radius, Color color); // Draw a color-filled circle
RLAPI void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2); // Draw a gradient-filled circle
RLAPI void DrawCircleV(Vector2 center, float radius, Color color); // Draw a color-filled circle (Vector version)
RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color); // Draw circle outline
RLAPI void DrawRectangle(int posX, int posY, int width, int height, Color color); // Draw a color-filled rectangle
RLAPI void DrawRectangleRec(Rectangle rec, Color color); // Draw a color-filled rectangle
RLAPI void DrawRectangleGradient(int posX, int posY, int width, int height, Color color1, Color color2); // Draw a gradient-filled rectangle
RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version)
RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline
RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle
RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline
RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version)
RLAPI void DrawPolyEx(Vector2 *points, int numPoints, Color color); // Draw a closed polygon defined by points
RLAPI void DrawPolyExLines(Vector2 *points, int numPoints, Color color); // Draw polygon lines
RLAPI bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2); // Check collision between two rectangles
RLAPI bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2); // Check collision between two circles
RLAPI bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec); // Check collision between circle and rectangle
RLAPI Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2); // Get collision rectangle for two rectangles collision
RLAPI bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle
RLAPI bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius); // Check if point is inside circle
RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3); // Check if point is inside a triangle
//------------------------------------------------------------------------------------
// Texture Loading and Drawing Functions (Module: textures)
//------------------------------------------------------------------------------------
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 Texture2D LoadTexture(const char *fileName); // Load texture from file into GPU memory (VRAM)
RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data
RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer)
RLAPI void UnloadImage(Image image); // Unload image from CPU memory (RAM)
RLAPI void UnloadTexture(Texture2D texture); // Unload texture from GPU memory (VRAM)
RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory (VRAM)
RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array
RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image
RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data
RLAPI void ImageToPOT(Image *image, Color fillColor); // Convert image to POT (power-of-two)
RLAPI void ImageFormat(Image *image, int newFormat); // Convert image data to desired format
RLAPI void ImageAlphaMask(Image *image, Image alphaMask); // Apply alpha mask to image
RLAPI void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp); // Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
RLAPI Image ImageCopy(Image image); // Create an image duplicate (useful for transformations)
RLAPI void ImageCrop(Image *image, Rectangle crop); // Crop an image to a defined rectangle
RLAPI void ImageResize(Image *image, int newWidth, int newHeight); // Resize and image (bilinear filtering)
RLAPI void ImageResizeNN(Image *image,int newWidth,int newHeight); // Resize and image (Nearest-Neighbor scaling algorithm)
RLAPI Image ImageText(const char *text, int fontSize, Color color); // Create an image from text (default font)
RLAPI Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing, Color tint); // Create an image from text (custom sprite font)
RLAPI void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec); // Draw a source image within a destination image
RLAPI void ImageDrawText(Image *dst, Vector2 position, const char *text, int fontSize, Color color); // Draw text (default font) within an image (destination)
RLAPI void ImageDrawTextEx(Image *dst, Vector2 position, SpriteFont font, const char *text,
float fontSize, int spacing, Color color); // Draw text (custom sprite font) within an image (destination)
RLAPI void ImageFlipVertical(Image *image); // Flip image vertically
RLAPI void ImageFlipHorizontal(Image *image); // Flip image horizontally
RLAPI void ImageColorTint(Image *image, Color color); // Modify image color: tint
RLAPI void ImageColorInvert(Image *image); // Modify image color: invert
RLAPI void ImageColorGrayscale(Image *image); // Modify image color: grayscale
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 GenTextureMipmaps(Texture2D *texture); // Generate GPU mipmaps for a texture
RLAPI void SetTextureFilter(Texture2D texture, int filterMode); // Set texture scaling filter mode
RLAPI void SetTextureWrap(Texture2D texture, int wrapMode); // Set texture wrapping mode
RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D
RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2
RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters
RLAPI void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle
RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, // Draw a part of a texture defined by a rectangle with 'pro' parameters
float rotation, Color tint);
//------------------------------------------------------------------------------------
// Font Loading and Text Drawing Functions (Module: text)
//------------------------------------------------------------------------------------
RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont
RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load SpriteFont from file into GPU memory (VRAM)
RLAPI SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars); // Load SpriteFont from TTF font file with generation parameters
RLAPI void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory (VRAM)
RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font)
RLAPI void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, // Draw text using SpriteFont and additional parameters
float fontSize, int spacing, Color tint);
RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font
RLAPI Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, int spacing); // Measure string size for SpriteFont
RLAPI void DrawFPS(int posX, int posY); // Shows current FPS on top-left corner
RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed'
RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string
//------------------------------------------------------------------------------------
// Basic 3d Shapes Drawing Functions (Module: models)
//------------------------------------------------------------------------------------
RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color); // Draw a line 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 DrawCube(Vector3 position, float width, float height, float length, Color color); // Draw cube
RLAPI void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version)
RLAPI void DrawCubeWires(Vector3 position, float width, float height, float length, Color color); // Draw cube wires
RLAPI void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float length, Color color); // Draw cube textured
RLAPI void DrawSphere(Vector3 centerPos, float radius, Color color); // Draw sphere
RLAPI void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere with extended parameters
RLAPI void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires
RLAPI void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone
RLAPI void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires
RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color); // Draw a plane XZ
RLAPI void DrawRay(Ray ray, Color color); // Draw a ray line
RLAPI void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0))
RLAPI void DrawGizmo(Vector3 position); // Draw simple gizmo
//DrawTorus(), DrawTeapot() could be useful?
//------------------------------------------------------------------------------------
// Model 3d Loading and Drawing Functions (Module: models)
//------------------------------------------------------------------------------------
RLAPI Mesh LoadMesh(const char *fileName); // Load mesh from file
RLAPI Mesh LoadMeshEx(int numVertex, float *vData, float *vtData, float *vnData, Color *cData); // Load mesh from vertex data
RLAPI Model LoadModel(const char *fileName); // Load model from file
RLAPI Model LoadModelFromMesh(Mesh data, bool dynamic); // Load model from mesh data
RLAPI Model LoadHeightmap(Image heightmap, Vector3 size); // Load heightmap model from image data
RLAPI Model LoadCubicmap(Image cubicmap); // Load cubes-based map model from image data
RLAPI void UnloadMesh(Mesh *mesh); // Unload mesh from memory (RAM and/or VRAM)
RLAPI void UnloadModel(Model model); // Unload model from memory (RAM and/or VRAM)
RLAPI Material LoadMaterial(const char *fileName); // Load material from file
RLAPI Material LoadMaterialEx(Shader shader, Texture2D diffuse, Color color); // Load material from basic shading data
RLAPI Material LoadDefaultMaterial(void); // Load default material (uses default models shader)
RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM)
RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint); // Draw a model (with texture if set)
RLAPI void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis,
float rotationAngle, Vector3 scale, Color tint); // Draw a model with extended parameters
RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint); // Draw a model wires (with texture if set)
RLAPI void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis,
float rotationAngle, Vector3 scale, Color tint); // Draw a model wires (with texture if set) with extended parameters
RLAPI void DrawBoundingBox(BoundingBox box, Color color); // Draw bounding box (wires)
RLAPI void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture
RLAPI void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec,
Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec
RLAPI BoundingBox CalculateBoundingBox(Mesh mesh); // Calculate mesh bounding box limits
RLAPI bool CheckCollisionSpheres(Vector3 centerA, float radiusA, Vector3 centerB, float radiusB); // Detect collision between two spheres
RLAPI bool CheckCollisionBoxes(BoundingBox box1, BoundingBox box2); // Detect collision between two bounding boxes
RLAPI bool CheckCollisionBoxSphere(BoundingBox box, Vector3 centerSphere, float radiusSphere); // Detect collision between box and sphere
RLAPI bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius); // Detect collision between ray and sphere
RLAPI bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadius,
Vector3 *collisionPoint); // Detect collision between ray and sphere, returns collision point
RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box
RLAPI RayHitInfo GetCollisionRayMesh(Ray ray, Mesh *mesh); // Get collision info between ray and mesh
RLAPI RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3); // Get collision info between ray and triangle
RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight); // Get collision info between ray and ground plane (Y-normal plane)
//------------------------------------------------------------------------------------
// Shaders System Functions (Module: rlgl)
// NOTE: This functions are useless when using OpenGL 1.1
//------------------------------------------------------------------------------------
RLAPI char *LoadText(const char *fileName); // Load chars array from text file
RLAPI Shader LoadShader(char *vsFileName, char *fsFileName); // Load shader from files and bind default locations
RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM)
RLAPI Shader GetDefaultShader(void); // Get default shader
RLAPI Texture2D GetDefaultTexture(void); // Get default texture
RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
RLAPI void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float)
RLAPI void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int)
RLAPI void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4)
RLAPI void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix)
RLAPI void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix)
RLAPI void BeginShaderMode(Shader shader); // Begin custom shader drawing
RLAPI void EndShaderMode(void); // End custom shader drawing (use default shader)
RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied)
RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending)
//------------------------------------------------------------------------------------
// VR experience Functions (Module: rlgl)
// NOTE: This functions are useless when using OpenGL 1.1
//------------------------------------------------------------------------------------
RLAPI void InitVrDevice(int vdDevice); // Init VR device
RLAPI void CloseVrDevice(void); // Close VR device
RLAPI bool IsVrDeviceReady(void); // Detect if VR device is ready
RLAPI bool IsVrSimulator(void); // Detect if VR simulator is running
RLAPI void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera
RLAPI void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator)
//------------------------------------------------------------------------------------
// Audio Loading and Playing Functions (Module: audio)
//------------------------------------------------------------------------------------
RLAPI void InitAudioDevice(void); // Initialize audio device and context
RLAPI void CloseAudioDevice(void); // Close the audio device and context
RLAPI bool IsAudioDeviceReady(void); // Check if audio device has been initialized successfully
RLAPI Wave LoadWave(const char *fileName); // Load wave data from file
RLAPI Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from raw array data
RLAPI Sound LoadSound(const char *fileName); // Load sound from file
RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound from wave data
RLAPI void UpdateSound(Sound sound, const void *data, int numSamples);// Update sound buffer with new data
RLAPI void UnloadWave(Wave wave); // Unload wave data
RLAPI void UnloadSound(Sound sound); // Unload sound
RLAPI void PlaySound(Sound sound); // Play a sound
RLAPI void PauseSound(Sound sound); // Pause a sound
RLAPI void ResumeSound(Sound sound); // Resume a paused sound
RLAPI void StopSound(Sound sound); // Stop playing a sound
RLAPI bool IsSoundPlaying(Sound sound); // Check if a sound is currently playing
RLAPI void SetSoundVolume(Sound sound, float volume); // Set volume for a sound (1.0 is max level)
RLAPI void SetSoundPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level)
RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels); // Convert wave data to desired format
RLAPI Wave WaveCopy(Wave wave); // Copy a wave to a new wave
RLAPI void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range
RLAPI float *GetWaveData(Wave wave); // Get samples data from wave as a floats array
RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file
RLAPI void UnloadMusicStream(Music music); // Unload music stream
RLAPI void PlayMusicStream(Music music); // Start music playing
RLAPI void UpdateMusicStream(Music music); // Updates buffers for music streaming
RLAPI void StopMusicStream(Music music); // Stop music playing
RLAPI void PauseMusicStream(Music music); // Pause music playing
RLAPI void ResumeMusicStream(Music music); // Resume playing paused music
RLAPI bool IsMusicPlaying(Music music); // Check if music is playing
RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds)
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
RLAPI AudioStream InitAudioStream(unsigned int sampleRate,
unsigned int sampleSize,
unsigned int channels); // Init audio stream (to stream raw audio pcm data)
RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int numSamples); // Update audio stream buffers with data
RLAPI void CloseAudioStream(AudioStream stream); // Close audio stream and free memory
RLAPI bool IsAudioBufferProcessed(AudioStream stream); // Check if any audio stream buffers requires refill
RLAPI void PlayAudioStream(AudioStream stream); // Play audio stream
RLAPI void PauseAudioStream(AudioStream stream); // Pause audio stream
RLAPI void ResumeAudioStream(AudioStream stream); // Resume audio stream
RLAPI void StopAudioStream(AudioStream stream); // Stop audio stream
#ifdef __cplusplus
}
#endif
#endif // RAYLIB_H

1156
raylib/raymath.h Normal file

File diff suppressed because it is too large Load diff

4191
raylib/rlgl.c Normal file

File diff suppressed because it is too large Load diff

443
raylib/rlgl.h Normal file
View file

@ -0,0 +1,443 @@
/**********************************************************************************************
*
* rlgl - raylib OpenGL abstraction layer
*
* rlgl allows usage of OpenGL 1.1 style functions (rlVertex) that are internally mapped to
* selected OpenGL version (1.1, 2.1, 3.3 Core, ES 2.0).
*
* When chosing an OpenGL version greater than OpenGL 1.1, rlgl stores vertex data on internal
* VBO buffers (and VAOs if available). It requires calling 3 functions:
* rlglInit() - Initialize internal buffers and auxiliar resources
* rlglDraw() - Process internal buffers and send required draw calls
* rlglClose() - De-initialize internal buffers data and other auxiliar resources
*
* External libs:
* raymath - 3D math functionality (Vector3, Matrix, Quaternion)
* GLAD - OpenGL extensions loading (OpenGL 3.3 Core only)
*
* Module Configuration Flags:
* GRAPHICS_API_OPENGL_11 - Use OpenGL 1.1 backend
* GRAPHICS_API_OPENGL_21 - Use OpenGL 2.1 backend
* GRAPHICS_API_OPENGL_33 - Use OpenGL 3.3 Core profile backend
* GRAPHICS_API_OPENGL_ES2 - Use OpenGL ES 2.0 backend
*
* RLGL_STANDALONE - Use rlgl as standalone library (no raylib dependency)
*
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* 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 RLGL_H
#define RLGL_H
//#define RLGL_STANDALONE // NOTE: To use rlgl as standalone lib, just uncomment this line
#ifndef RLGL_STANDALONE
#include "raylib.h" // Required for: Model, Shader, Texture2D
#include "utils.h" // Required for: TraceLog()
#endif
#ifdef RLGL_STANDALONE
#define RAYMATH_STANDALONE
#endif
#include "raymath.h" // Required for: Vector3, Matrix
// Select desired OpenGL version
// NOTE: Those preprocessor defines are only used on rlgl module,
// if OpenGL version is required by any other module, it uses rlGetVersion()
// Choose opengl version here or just define it at compile time: -DGRAPHICS_API_OPENGL_33
//#define GRAPHICS_API_OPENGL_11 // Only available on PLATFORM_DESKTOP
//#define GRAPHICS_API_OPENGL_33 // Only available on PLATFORM_DESKTOP and RLGL_OCULUS_SUPPORT
//#define GRAPHICS_API_OPENGL_ES2 // Only available on PLATFORM_ANDROID or PLATFORM_RPI or PLATFORM_WEB
// Security check in case no GRAPHICS_API_OPENGL_* defined
#if !defined(GRAPHICS_API_OPENGL_11) && !defined(GRAPHICS_API_OPENGL_21) && !defined(GRAPHICS_API_OPENGL_33) && !defined(GRAPHICS_API_OPENGL_ES2)
#define GRAPHICS_API_OPENGL_11
#endif
// Security check in case multiple GRAPHICS_API_OPENGL_* defined
#if defined(GRAPHICS_API_OPENGL_11)
#if defined(GRAPHICS_API_OPENGL_21)
#undef GRAPHICS_API_OPENGL_21
#endif
#if defined(GRAPHICS_API_OPENGL_33)
#undef GRAPHICS_API_OPENGL_33
#endif
#if defined(GRAPHICS_API_OPENGL_ES2)
#undef GRAPHICS_API_OPENGL_ES2
#endif
#endif
#if defined(GRAPHICS_API_OPENGL_21)
#define GRAPHICS_API_OPENGL_33
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
// NOTE: This is the maximum amount of lines, triangles and quads per frame, be careful!
#define MAX_LINES_BATCH 8192
#define MAX_TRIANGLES_BATCH 4096
#define MAX_QUADS_BATCH 8192
#elif defined(GRAPHICS_API_OPENGL_ES2)
// NOTE: Reduce memory sizes for embedded systems (RPI and HTML5)
// NOTE: On HTML5 (emscripten) this is allocated on heap, by default it's only 16MB!...just take care...
#define MAX_LINES_BATCH 1024 // Critical for wire shapes (sphere)
#define MAX_TRIANGLES_BATCH 2048 // Critical for some shapes (sphere)
#define MAX_QUADS_BATCH 1024 // Be careful with text, every letter maps a quad
#endif
// Texture parameters (equivalent to OpenGL defines)
#define RL_TEXTURE_WRAP_S 0x2802 // GL_TEXTURE_WRAP_S
#define RL_TEXTURE_WRAP_T 0x2803 // GL_TEXTURE_WRAP_T
#define RL_TEXTURE_MAG_FILTER 0x2800 // GL_TEXTURE_MAG_FILTER
#define RL_TEXTURE_MIN_FILTER 0x2801 // GL_TEXTURE_MIN_FILTER
#define RL_TEXTURE_ANISOTROPIC_FILTER 0x3000 // Anisotropic filter (custom identifier)
#define RL_FILTER_NEAREST 0x2600 // GL_NEAREST
#define RL_FILTER_LINEAR 0x2601 // GL_LINEAR
#define RL_FILTER_MIP_NEAREST 0x2700 // GL_NEAREST_MIPMAP_NEAREST
#define RL_FILTER_NEAREST_MIP_LINEAR 0x2702 // GL_NEAREST_MIPMAP_LINEAR
#define RL_FILTER_LINEAR_MIP_NEAREST 0x2701 // GL_LINEAR_MIPMAP_NEAREST
#define RL_FILTER_MIP_LINEAR 0x2703 // GL_LINEAR_MIPMAP_LINEAR
#define RL_WRAP_REPEAT 0x2901 // GL_REPEAT
#define RL_WRAP_CLAMP 0x812F // GL_CLAMP_TO_EDGE
#define RL_WRAP_CLAMP_MIRROR 0x8742 // GL_MIRROR_CLAMP_EXT
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
typedef enum { OPENGL_11 = 1, OPENGL_21, OPENGL_33, OPENGL_ES_20 } GlVersion;
typedef enum { RL_PROJECTION, RL_MODELVIEW, RL_TEXTURE } MatrixMode;
typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode;
typedef unsigned char byte;
#if defined(RLGL_STANDALONE)
#ifndef __cplusplus
// Boolean type
typedef enum { false, true } bool;
#endif
// Color type, RGBA (32bit)
typedef struct Color {
unsigned char r;
unsigned char g;
unsigned char b;
unsigned char a;
} Color;
// Texture formats (support depends on OpenGL version)
typedef enum {
UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha)
UNCOMPRESSED_GRAY_ALPHA,
UNCOMPRESSED_R5G6B5, // 16 bpp
UNCOMPRESSED_R8G8B8, // 24 bpp
UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha)
UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha)
UNCOMPRESSED_R8G8B8A8, // 32 bpp
COMPRESSED_DXT1_RGB, // 4 bpp (no alpha)
COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha)
COMPRESSED_DXT3_RGBA, // 8 bpp
COMPRESSED_DXT5_RGBA, // 8 bpp
COMPRESSED_ETC1_RGB, // 4 bpp
COMPRESSED_ETC2_RGB, // 4 bpp
COMPRESSED_ETC2_EAC_RGBA, // 8 bpp
COMPRESSED_PVRT_RGB, // 4 bpp
COMPRESSED_PVRT_RGBA, // 4 bpp
COMPRESSED_ASTC_4x4_RGBA, // 8 bpp
COMPRESSED_ASTC_8x8_RGBA // 2 bpp
} TextureFormat;
// Vertex data definning a mesh
typedef struct Mesh {
int vertexCount; // number of vertices stored in arrays
int triangleCount; // number of triangles stored (indexed or not)
float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0)
float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5)
float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4)
unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
unsigned short *indices;// vertex indices (in case vertex data comes indexed)
unsigned int vaoId; // OpenGL Vertex Array Object id
unsigned int vboId[7]; // OpenGL Vertex Buffer Objects id (7 types of vertex data)
} Mesh;
// Shader type (generic shader)
typedef struct Shader {
unsigned int id; // Shader program id
// Vertex attributes locations (default locations)
int vertexLoc; // Vertex attribute location point (default-location = 0)
int texcoordLoc; // Texcoord attribute location point (default-location = 1)
int normalLoc; // Normal attribute location point (default-location = 2)
int colorLoc; // Color attibute location point (default-location = 3)
int tangentLoc; // Tangent attribute location point (default-location = 4)
int texcoord2Loc; // Texcoord2 attribute location point (default-location = 5)
// Uniform locations
int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader)
int colDiffuseLoc; // Color uniform location point (fragment shader)
int colAmbientLoc; // Ambient color uniform location point (fragment shader)
int colSpecularLoc; // Specular color uniform location point (fragment shader)
// Texture map locations (generic for any kind of map)
int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0)
int mapTexture1Loc; // Map texture uniform location point (default-texture-unit = 1)
int mapTexture2Loc; // Map texture uniform location point (default-texture-unit = 2)
} Shader;
// Texture2D type
// NOTE: Data stored in GPU memory
typedef struct Texture2D {
unsigned int id; // OpenGL texture id
int width; // Texture base width
int height; // Texture base height
int mipmaps; // Mipmap levels, 1 by default
int format; // Data format (TextureFormat)
} Texture2D;
// RenderTexture2D type, for texture rendering
typedef struct RenderTexture2D {
unsigned int id; // Render texture (fbo) id
Texture2D texture; // Color buffer attachment texture
Texture2D depth; // Depth buffer attachment texture
} RenderTexture2D;
// Material type
typedef struct Material {
Shader shader; // Standard shader (supports 3 map types: diffuse, normal, specular)
Texture2D texDiffuse; // Diffuse texture
Texture2D texNormal; // Normal texture
Texture2D texSpecular; // Specular texture
Color colDiffuse; // Diffuse color
Color colAmbient; // Ambient color
Color colSpecular; // Specular color
float glossiness; // Glossiness level (Ranges from 0 to 1000)
} Material;
// Camera type, defines a camera position/orientation in 3d space
typedef struct Camera {
Vector3 position; // Camera position
Vector3 target; // Camera target it looks-at
Vector3 up; // Camera up vector (rotation over its axis)
float fovy; // Camera field-of-view apperture in Y (degrees)
} Camera;
// Light type
typedef struct LightData {
unsigned int id; // Light unique id
bool enabled; // Light enabled
int type; // Light type: LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT
Vector3 position; // Light position
Vector3 target; // Light target: LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target)
float radius; // Light attenuation radius light intensity reduced with distance (world distance)
Color diffuse; // Light diffuse color
float intensity; // Light intensity level
float coneAngle; // Light cone max angle: LIGHT_SPOT
} LightData, *Light;
// Light types
typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType;
// Texture parameters: filter mode
// NOTE 1: Filtering considers mipmaps if available in the texture
// NOTE 2: Filter is accordingly set for minification and magnification
typedef enum {
FILTER_POINT = 0, // No filter, just pixel aproximation
FILTER_BILINEAR, // Linear filtering
FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps)
FILTER_ANISOTROPIC_4X, // Anisotropic filtering 4x
FILTER_ANISOTROPIC_8X, // Anisotropic filtering 8x
FILTER_ANISOTROPIC_16X, // Anisotropic filtering 16x
} TextureFilterMode;
// Texture parameters: wrap mode
typedef enum { WRAP_REPEAT = 0, WRAP_CLAMP, WRAP_MIRROR } TextureWrapMode;
// Color blending modes (pre-defined)
typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode;
// TraceLog message types
typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
// VR Head Mounted Display devices
typedef enum {
HMD_DEFAULT_DEVICE = 0,
HMD_OCULUS_RIFT_DK2,
HMD_OCULUS_RIFT_CV1,
HMD_VALVE_HTC_VIVE,
HMD_SAMSUNG_GEAR_VR,
HMD_GOOGLE_CARDBOARD,
HMD_SONY_PLAYSTATION_VR,
HMD_RAZER_OSVR,
HMD_FOVE_VR,
} VrDevice;
#endif
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
//------------------------------------------------------------------------------------
// Functions Declaration - Matrix operations
//------------------------------------------------------------------------------------
void rlMatrixMode(int mode); // Choose the current matrix to be transformed
void rlPushMatrix(void); // Push the current matrix to stack
void rlPopMatrix(void); // Pop lattest inserted matrix from stack
void rlLoadIdentity(void); // Reset current matrix to identity matrix
void rlTranslatef(float x, float y, float z); // Multiply the current matrix by a translation matrix
void rlRotatef(float angleDeg, float x, float y, float z); // Multiply the current matrix by a rotation matrix
void rlScalef(float x, float y, float z); // Multiply the current matrix by a scaling matrix
void rlMultMatrixf(float *mat); // Multiply the current matrix by another matrix
void rlFrustum(double left, double right, double bottom, double top, double near, double far);
void rlOrtho(double left, double right, double bottom, double top, double near, double far);
void rlViewport(int x, int y, int width, int height); // Set the viewport area
//------------------------------------------------------------------------------------
// Functions Declaration - Vertex level operations
//------------------------------------------------------------------------------------
void rlBegin(int mode); // Initialize drawing mode (how to organize vertex)
void rlEnd(void); // Finish vertex providing
void rlVertex2i(int x, int y); // Define one vertex (position) - 2 int
void rlVertex2f(float x, float y); // Define one vertex (position) - 2 float
void rlVertex3f(float x, float y, float z); // Define one vertex (position) - 3 float
void rlTexCoord2f(float x, float y); // Define one vertex (texture coordinate) - 2 float
void rlNormal3f(float x, float y, float z); // Define one vertex (normal) - 3 float
void rlColor4ub(byte r, byte g, byte b, byte a); // Define one vertex (color) - 4 byte
void rlColor3f(float x, float y, float z); // Define one vertex (color) - 3 float
void rlColor4f(float x, float y, float z, float w); // Define one vertex (color) - 4 float
//------------------------------------------------------------------------------------
// Functions Declaration - OpenGL equivalent functions (common to 1.1, 3.3+, ES2)
// NOTE: This functions are used to completely abstract raylib code from OpenGL layer
//------------------------------------------------------------------------------------
void rlEnableTexture(unsigned int id); // Enable texture usage
void rlDisableTexture(void); // Disable texture usage
void rlTextureParameters(unsigned int id, int param, int value); // Set texture parameters (filter, wrap)
void rlEnableRenderTexture(unsigned int id); // Enable render texture (fbo)
void rlDisableRenderTexture(void); // Disable render texture (fbo), return to default framebuffer
void rlEnableDepthTest(void); // Enable depth test
void rlDisableDepthTest(void); // Disable depth test
void rlEnableWireMode(void); // Enable wire mode
void rlDisableWireMode(void); // Disable wire mode
void rlDeleteTextures(unsigned int id); // Delete OpenGL texture from GPU
void rlDeleteRenderTextures(RenderTexture2D target); // Delete render textures (fbo) from GPU
void rlDeleteShader(unsigned int id); // Delete OpenGL shader program from GPU
void rlDeleteVertexArrays(unsigned int id); // Unload vertex data (VAO) from GPU memory
void rlDeleteBuffers(unsigned int id); // Unload vertex data (VBO) from GPU memory
void rlClearColor(byte r, byte g, byte b, byte a); // Clear color buffer with color
void rlClearScreenBuffers(void); // Clear used screen buffers (color and depth)
int rlGetVersion(void); // Returns current OpenGL version
//------------------------------------------------------------------------------------
// Functions Declaration - rlgl functionality
//------------------------------------------------------------------------------------
void rlglInit(int width, int height); // Initialize rlgl (buffers, shaders, textures, states)
void rlglClose(void); // De-init rlgl
void rlglDraw(void); // Draw VAO/VBO
void rlglLoadExtensions(void *loader); // Load OpenGL extensions
unsigned int rlglLoadTexture(void *data, int width, int height, int textureFormat, int mipmapCount); // Load texture in GPU
RenderTexture2D rlglLoadRenderTexture(int width, int height); // Load a texture to be used for rendering (fbo with color and depth attachments)
void rlglUpdateTexture(unsigned int id, int width, int height, int format, const void *data); // Update GPU texture with new data
void rlglGenerateMipmaps(Texture2D *texture); // Generate mipmap data for selected texture
void rlglLoadMesh(Mesh *mesh, bool dynamic); // Upload vertex data into GPU and provided VAO/VBO ids
void rlglUpdateMesh(Mesh mesh, int buffer, int numVertex); // Update vertex data on GPU (upload new data to one buffer)
void rlglDrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform
void rlglUnloadMesh(Mesh *mesh); // Unload mesh data from CPU and GPU
Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates
unsigned char *rlglReadScreenPixels(int width, int height); // Read screen pixel data (color buffer)
void *rlglReadTexturePixels(Texture2D texture); // Read texture pixel data
// VR functions exposed to core module but not to raylib users
void BeginVrDrawing(void); // Begin VR drawing configuration
void EndVrDrawing(void); // End VR drawing process (and desktop mirror)
// NOTE: There is a set of shader related functions that are available to end user,
// to avoid creating function wrappers through core module, they have been directly declared in raylib.h
#if defined(RLGL_STANDALONE)
//------------------------------------------------------------------------------------
// Shaders System Functions (Module: rlgl)
// NOTE: This functions are useless when using OpenGL 1.1
//------------------------------------------------------------------------------------
Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations
void UnloadShader(Shader shader); // Unload a custom shader from memory
Shader GetDefaultShader(void); // Get default shader
Shader GetStandardShader(void); // Get default shader
Texture2D GetDefaultTexture(void); // Get default texture
int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float)
void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int)
void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4)
void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix)
void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix)
void BeginShaderMode(Shader shader); // Begin custom shader drawing
void EndShaderMode(void); // End custom shader drawing (use default shader)
void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied)
void EndBlendMode(void); // End blending mode (reset to default: alpha blending)
Light CreateLight(int type, Vector3 position, Color diffuse); // Create a new light, initialize it and add to pool
void DestroyLight(Light light); // Destroy a light and take it out of the list
void TraceLog(int msgType, const char *text, ...);
float *MatrixToFloat(Matrix mat);
void InitVrDevice(int vrDevice); // Init VR device
void CloseVrDevice(void); // Close VR device
bool IsVrDeviceReady(void); // Detect if VR device is ready
bool IsVrSimulator(void); // Detect if VR simulator is running
void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera
void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator)
// Oculus Rift API for direct access the device (no simulator)
bool InitOculusDevice(void); // Initialize Oculus device (returns true if success)
void CloseOculusDevice(void); // Close Oculus device
void UpdateOculusTracking(Camera *camera); // Update Oculus head position-orientation tracking (and camera)
void BeginOculusDrawing(void); // Setup Oculus buffers for drawing
void EndOculusDrawing(void); // Finish Oculus drawing and blit framebuffer to mirror
#endif
#ifdef __cplusplus
}
#endif
#endif // RLGL_H

438
raylib/rres.h Normal file
View file

@ -0,0 +1,438 @@
/**********************************************************************************************
*
* rres - raylib Resource custom format management functions
*
* Basic functions to load/save rRES resource files
*
* External libs:
* tinfl - DEFLATE decompression functions
*
* Module Configuration Flags:
*
* #define RREM_IMPLEMENTATION
* Generates the implementation of the library into the included file.
*
*
* Copyright (c) 2016-2017 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* 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 RRES_H
#define RRES_H
#if !defined(RRES_STANDALONE)
#include "raylib.h"
#endif
//#define RRES_STATIC
#ifdef RRES_STATIC
#define RRESDEF static // Functions just visible to module including this file
#else
#ifdef __cplusplus
#define RRESDEF extern "C" // Functions visible from other files (no name mangling of functions in C++)
#else
#define RRESDEF extern // Functions visible from other files
#endif
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define MAX_RESOURCES_SUPPORTED 256
//----------------------------------------------------------------------------------
// Types and Structures Definition
// NOTE: Some types are required for RAYGUI_STANDALONE usage
//----------------------------------------------------------------------------------
#if defined(RRES_STANDALONE)
// rRES data returned when reading a resource, it contains all required data for user (24 byte)
// NOTE: Using void *data pointer, so we can load to image.data, wave.data, mesh.*, (unsigned char *)
typedef struct {
unsigned int type; // Resource type (4 byte)
unsigned int param1; // Resouce parameter 1 (4 byte)
unsigned int param2; // Resouce parameter 2 (4 byte)
unsigned int param3; // Resouce parameter 3 (4 byte)
unsigned int param4; // Resouce parameter 4 (4 byte)
void *data; // Resource data pointer (4 byte)
} RRESData;
typedef enum {
RRES_TYPE_RAW = 0,
RRES_TYPE_IMAGE,
RRES_TYPE_WAVE,
RRES_TYPE_VERTEX,
RRES_TYPE_TEXT,
RRES_TYPE_FONT_IMAGE,
RRES_TYPE_FONT_DATA, // Character { int value, recX, recY, recWidth, recHeight, offsetX, offsetY, xAdvance }
RRES_TYPE_DIRECTORY
} RRESDataType;
#endif
//----------------------------------------------------------------------------------
// Global variables
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
RRESDEF RRESData LoadResource(const char *rresFileName);
RRESDEF RRESData LoadResourceById(const char *rresFileName, int rresId);
RRESDEF void UnloadResource(RRESData rres);
#endif // RRES_H
/***********************************************************************************
*
* RRES IMPLEMENTATION
*
************************************************************************************/
#if defined(RRES_IMPLEMENTATION)
#include <stdio.h> // Required for: FILE, fopen(), fclose()
// Check if custom malloc/free functions defined, if not, using standard ones
#if !defined(RRES_MALLOC)
#include <stdlib.h> // Required for: malloc(), free()
#define RRES_MALLOC(size) malloc(size)
#define RRES_FREE(ptr) free(ptr)
#endif
#include "external/tinfl.c" // Required for: tinfl_decompress_mem_to_mem()
// NOTE: DEFLATE algorythm data decompression
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// rRES file header (8 byte)
typedef struct {
char id[4]; // File identifier: rRES (4 byte)
unsigned short version; // File version and subversion (2 byte)
unsigned short count; // Number of resources in this file (2 byte)
} RRESFileHeader;
// rRES info header, every resource includes this header (16 byte + 16 byte)
typedef struct {
unsigned int id; // Resource unique identifier (4 byte)
unsigned char dataType; // Resource data type (1 byte)
unsigned char compType; // Resource data compression type (1 byte)
unsigned char cryptoType; // Resource data encryption type (1 byte)
unsigned char partsCount; // Resource data parts count, used for splitted data (1 byte)
unsigned int dataSize; // Resource data size (compressed or not, only DATA) (4 byte)
unsigned int uncompSize; // Resource data size (uncompressed, only DATA) (4 byte)
unsigned int param1; // Resouce parameter 1 (4 byte)
unsigned int param2; // Resouce parameter 2 (4 byte)
unsigned int param3; // Resouce parameter 3 (4 byte)
unsigned int param4; // Resouce parameter 4 (4 byte)
} RRESInfoHeader;
// Compression types
typedef enum {
RRES_COMP_NONE = 0, // No data compression
RRES_COMP_DEFLATE, // DEFLATE compression
RRES_COMP_LZ4, // LZ4 compression
RRES_COMP_LZMA, // LZMA compression
RRES_COMP_BROTLI, // BROTLI compression
// gzip, zopfli, lzo, zstd // Other compression algorythms...
} RRESCompressionType;
typedef enum {
RRES_CRYPTO_NONE = 0, // No data encryption
RRES_CRYPTO_XOR, // XOR (128 bit) encryption
RRES_CRYPTO_AES, // RIJNDAEL (128 bit) encryption (AES)
RRES_CRYPTO_TDES, // Triple DES encryption
RRES_CRYPTO_BLOWFISH, // BLOWFISH encryption
RRES_CRYPTO_XTEA, // XTEA encryption
// twofish, RC5, RC6 // Other encryption algorythm...
} RRESEncryptionType;
typedef enum {
RRES_IM_UNCOMP_GRAYSCALE = 1, // 8 bit per pixel (no alpha)
RRES_IM_UNCOMP_GRAY_ALPHA, // 16 bpp (2 channels)
RRES_IM_UNCOMP_R5G6B5, // 16 bpp
RRES_IM_UNCOMP_R8G8B8, // 24 bpp
RRES_IM_UNCOMP_R5G5B5A1, // 16 bpp (1 bit alpha)
RRES_IM_UNCOMP_R4G4B4A4, // 16 bpp (4 bit alpha)
RRES_IM_UNCOMP_R8G8B8A8, // 32 bpp
RRES_IM_COMP_DXT1_RGB, // 4 bpp (no alpha)
RRES_IM_COMP_DXT1_RGBA, // 4 bpp (1 bit alpha)
RRES_IM_COMP_DXT3_RGBA, // 8 bpp
RRES_IM_COMP_DXT5_RGBA, // 8 bpp
RRES_IM_COMP_ETC1_RGB, // 4 bpp
RRES_IM_COMP_ETC2_RGB, // 4 bpp
RRES_IM_COMP_ETC2_EAC_RGBA, // 8 bpp
RRES_IM_COMP_PVRT_RGB, // 4 bpp
RRES_IM_COMP_PVRT_RGBA, // 4 bpp
RRES_IM_COMP_ASTC_4x4_RGBA, // 8 bpp
RRES_IM_COMP_ASTC_8x8_RGBA // 2 bpp
//...
} RRESImageFormat;
typedef enum {
RRES_VERT_POSITION,
RRES_VERT_TEXCOORD1,
RRES_VERT_TEXCOORD2,
RRES_VERT_TEXCOORD3,
RRES_VERT_TEXCOORD4,
RRES_VERT_NORMAL,
RRES_VERT_TANGENT,
RRES_VERT_COLOR,
RRES_VERT_INDEX,
//...
} RRESVertexType;
typedef enum {
RRES_VERT_BYTE,
RRES_VERT_SHORT,
RRES_VERT_INT,
RRES_VERT_HFLOAT,
RRES_VERT_FLOAT,
//...
} RRESVertexFormat;
#if defined(RRES_STANDALONE)
typedef enum { LOG_INFO = 0, LOG_ERROR, LOG_WARNING, LOG_DEBUG, LOG_OTHER } TraceLogType;
#endif
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
static void *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize);
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
// Load resource from file (only one)
// NOTE: Returns uncompressed data with parameters, only first resource found
RRESDEF RRESData LoadResource(const char *fileName)
{
// Force loading first resource available
RRESData rres = { 0 };
rres = LoadResourceById(fileName, 0);
return rres;
}
// Load resource from file by id
// NOTE: Returns uncompressed data with parameters, search resource by id
RRESDEF RRESData LoadResourceById(const char *fileName, int rresId)
{
RRESData rres = { 0 };
RRESFileHeader fileHeader;
RRESInfoHeader infoHeader;
FILE *rresFile = fopen(fileName, "rb");
if (rresFile == NULL) TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", fileName);
else
{
// Read rres file info header
fread(&fileHeader.id[0], sizeof(char), 1, rresFile);
fread(&fileHeader.id[1], sizeof(char), 1, rresFile);
fread(&fileHeader.id[2], sizeof(char), 1, rresFile);
fread(&fileHeader.id[3], sizeof(char), 1, rresFile);
fread(&fileHeader.version, sizeof(short), 1, rresFile);
fread(&fileHeader.count, sizeof(short), 1, rresFile);
// Verify "rRES" identifier
if ((fileHeader.id[0] != 'r') && (fileHeader.id[1] != 'R') && (fileHeader.id[2] != 'E') && (fileHeader.id[3] != 'S'))
{
TraceLog(WARNING, "[%s] This is not a valid raylib resource file", fileName);
}
else
{
for (int i = 0; i < fileHeader.count; i++)
{
// Read resource info and parameters
fread(&infoHeader, sizeof(RRESInfoHeader), 1, rresFile);
if (infoHeader.id == rresId)
{
// Register data type and parameters
rres.type = infoHeader.dataType;
rres.param1 = infoHeader.param1;
rres.param2 = infoHeader.param2;
rres.param3 = infoHeader.param3;
rres.param4 = infoHeader.param4;
// Read resource data block
void *data = RRES_MALLOC(infoHeader.dataSize);
fread(data, infoHeader.dataSize, 1, rresFile);
if (infoHeader.compType == RRES_COMP_DEFLATE)
{
void *uncompData = DecompressData(data, infoHeader.dataSize, infoHeader.uncompSize);
rres.data = uncompData;
RRES_FREE(data);
}
else rres.data = data;
if (rres.data != NULL) TraceLog(INFO, "[%s][ID %i] Resource data loaded successfully", fileName, (int)infoHeader.id);
if (rresId == 0) break; // Break for loop, do not check next resource
}
else
{
// Skip required data to read next resource infoHeader
fseek(rresFile, infoHeader.dataSize, SEEK_CUR);
}
}
if (rres.data == NULL) TraceLog(WARNING, "[%s][ID %i] Requested resource could not be found", fileName, (int)rresId);
}
fclose(rresFile);
}
return rres;
}
RRESDEF void UnloadResource(RRESData rres)
{
if (rres.data != NULL) free(rres.data);
}
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
// Data decompression function
// NOTE: Allocated data MUST be freed by user
static void *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize)
{
int tempUncompSize;
void *uncompData;
// Allocate buffer to hold decompressed data
uncompData = (mz_uint8 *)RRES_MALLOC((size_t)uncompSize);
// Check correct memory allocation
if (uncompData == NULL)
{
TraceLog(WARNING, "Out of memory while decompressing data");
}
else
{
// Decompress data
tempUncompSize = tinfl_decompress_mem_to_mem(uncompData, (size_t)uncompSize, data, compSize, 1);
if (tempUncompSize == -1)
{
TraceLog(WARNING, "Data decompression failed");
RRES_FREE(uncompData);
}
if (uncompSize != (int)tempUncompSize)
{
TraceLog(WARNING, "Expected uncompressed size do not match, data may be corrupted");
TraceLog(WARNING, " -- Expected uncompressed size: %i", uncompSize);
TraceLog(WARNING, " -- Returned uncompressed size: %i", tempUncompSize);
}
TraceLog(INFO, "Data decompressed successfully from %u bytes to %u bytes", (mz_uint32)compSize, (mz_uint32)tempUncompSize);
}
return uncompData;
}
// Some required functions for rres standalone module version
#if defined(RRES_STANDALONE)
// Outputs a trace log message (INFO, ERROR, WARNING)
// NOTE: If a file has been init, output log is written there
void TraceLog(int logType, const char *text, ...)
{
va_list args;
int traceDebugMsgs = 0;
#ifdef DO_NOT_TRACE_DEBUG_MSGS
traceDebugMsgs = 0;
#endif
switch (msgType)
{
case LOG_INFO: fprintf(stdout, "INFO: "); break;
case LOG_ERROR: fprintf(stdout, "ERROR: "); break;
case LOG_WARNING: fprintf(stdout, "WARNING: "); break;
case LOG_DEBUG: if (traceDebugMsgs) fprintf(stdout, "DEBUG: "); break;
default: break;
}
if ((msgType != LOG_DEBUG) || ((msgType == LOG_DEBUG) && (traceDebugMsgs)))
{
va_start(args, text);
vfprintf(stdout, text, args);
va_end(args);
fprintf(stdout, "\n");
}
if (msgType == ERROR) exit(1); // If ERROR message, exit program
}
#endif
#endif // RAYGUI_IMPLEMENTATION
/*
Mesh LoadMeshEx(int numVertex, float *vData, float *vtData, float *vnData, Color *cData);
Mesh LoadMeshEx(rres.param1, rres.data, rres.data + offset, rres.data + offset*2, rres.data + offset*3);
Shader LoadShader(const char *vsText, int vsLength);
Shader LoadShaderV(rres.data, rres.param1);
// Parameters information depending on resource type (IMAGE, WAVE, MESH, TEXT)
// Image data params
int imgWidth, imgHeight;
char colorFormat, mipmaps;
// Wave data params
int sampleCount,
short sampleRate, bps;
char channels, reserved;
// Mesh data params
int vertexCount, reserved;
short vertexTypesMask, vertexFormatsMask;
// Text data params
int charsCount;
int cultureCode;
*/

106
raylib/shader_distortion.h Normal file
View file

@ -0,0 +1,106 @@
// Vertex shader definition to embed, no external file required
static const char vDistortionShaderStr[] =
#if defined(GRAPHICS_API_OPENGL_21)
"#version 120 \n"
#elif defined(GRAPHICS_API_OPENGL_ES2)
"#version 100 \n"
#endif
#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
"attribute vec3 vertexPosition; \n"
"attribute vec2 vertexTexCoord; \n"
"attribute vec4 vertexColor; \n"
"varying vec2 fragTexCoord; \n"
"varying vec4 fragColor; \n"
#elif defined(GRAPHICS_API_OPENGL_33)
"#version 330 \n"
"in vec3 vertexPosition; \n"
"in vec2 vertexTexCoord; \n"
"in vec4 vertexColor; \n"
"out vec2 fragTexCoord; \n"
"out vec4 fragColor; \n"
#endif
"uniform mat4 mvpMatrix; \n"
"void main() \n"
"{ \n"
" fragTexCoord = vertexTexCoord; \n"
" fragColor = vertexColor; \n"
" gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); \n"
"} \n";
// Fragment shader definition to embed, no external file required
static const char fDistortionShaderStr[] =
#if defined(GRAPHICS_API_OPENGL_21)
"#version 120 \n"
#elif defined(GRAPHICS_API_OPENGL_ES2)
"#version 100 \n"
"precision mediump float; \n" // precision required for OpenGL ES2 (WebGL)
#endif
#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
"varying vec2 fragTexCoord; \n"
"varying vec4 fragColor; \n"
#elif defined(GRAPHICS_API_OPENGL_33)
"#version 330 \n"
"in vec2 fragTexCoord; \n"
"in vec4 fragColor; \n"
"out vec4 finalColor; \n"
#endif
"uniform sampler2D texture0; \n"
#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
"uniform vec2 leftLensCenter; \n"
"uniform vec2 rightLensCenter; \n"
"uniform vec2 leftScreenCenter; \n"
"uniform vec2 rightScreenCenter; \n"
"uniform vec2 scale; \n"
"uniform vec2 scaleIn; \n"
"uniform vec4 hmdWarpParam; \n"
"uniform vec4 chromaAbParam; \n"
#elif defined(GRAPHICS_API_OPENGL_33)
"uniform vec2 leftLensCenter = vec2(0.288, 0.5); \n"
"uniform vec2 rightLensCenter = vec2(0.712, 0.5); \n"
"uniform vec2 leftScreenCenter = vec2(0.25, 0.5); \n"
"uniform vec2 rightScreenCenter = vec2(0.75, 0.5); \n"
"uniform vec2 scale = vec2(0.25, 0.45); \n"
"uniform vec2 scaleIn = vec2(4, 2.2222); \n"
"uniform vec4 hmdWarpParam = vec4(1, 0.22, 0.24, 0); \n"
"uniform vec4 chromaAbParam = vec4(0.996, -0.004, 1.014, 0.0); \n"
#endif
"void main() \n"
"{ \n"
" vec2 lensCenter = fragTexCoord.x < 0.5 ? leftLensCenter : rightLensCenter; \n"
" vec2 screenCenter = fragTexCoord.x < 0.5 ? leftScreenCenter : rightScreenCenter; \n"
" vec2 theta = (fragTexCoord - lensCenter)*scaleIn; \n"
" float rSq = theta.x*theta.x + theta.y*theta.y; \n"
" vec2 theta1 = theta*(hmdWarpParam.x + hmdWarpParam.y*rSq + hmdWarpParam.z*rSq*rSq + hmdWarpParam.w*rSq*rSq*rSq); \n"
" vec2 thetaBlue = theta1*(chromaAbParam.z + chromaAbParam.w*rSq); \n"
" vec2 tcBlue = lensCenter + scale*thetaBlue; \n"
" if (any(bvec2(clamp(tcBlue, screenCenter - vec2(0.25, 0.5), screenCenter + vec2(0.25, 0.5)) - tcBlue))) \n"
" { \n"
#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
" gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); \n"
#elif defined(GRAPHICS_API_OPENGL_33)
" finalColor = vec4(0.0, 0.0, 0.0, 1.0); \n"
#endif
" } \n"
" else \n"
" { \n"
#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
" float blue = texture2D(texture0, tcBlue).b; \n"
" vec2 tcGreen = lensCenter + scale*theta1; \n"
" float green = texture2D(texture0, tcGreen).g; \n"
#elif defined(GRAPHICS_API_OPENGL_33)
" float blue = texture(texture0, tcBlue).b; \n"
" vec2 tcGreen = lensCenter + scale*theta1; \n"
" float green = texture(texture0, tcGreen).g; \n"
#endif
" vec2 thetaRed = theta1*(chromaAbParam.x + chromaAbParam.y*rSq); \n"
" vec2 tcRed = lensCenter + scale*thetaRed; \n"
#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
" float red = texture2D(texture0, tcRed).r; \n"
" gl_FragColor = vec4(red, green, blue, 1.0); \n"
#elif defined(GRAPHICS_API_OPENGL_33)
" float red = texture(texture0, tcRed).r; \n"
" finalColor = vec4(red, green, blue, 1.0); \n"
#endif
" } \n"
"} \n";

View file

@ -103,13 +103,6 @@ func GetDefaultShader() Shader {
return v
}
// Get standard shader
func GetStandardShader() Shader {
ret := C.GetStandardShader()
v := NewShaderFromPointer(unsafe.Pointer(&ret))
return v
}
// Get default texture
func GetDefaultTexture() *Texture2D {
ret := C.GetDefaultTexture()
@ -187,22 +180,6 @@ func EndBlendMode() {
C.EndBlendMode()
}
// Create a new light, initialize it and add to pool
func CreateLight(_type LightType, position Vector3, diffuse Color) Light {
c_type := (C.int)(_type)
cposition := position.cptr()
cdiffuse := diffuse.cptr()
ret := C.CreateLight(c_type, *cposition, *cdiffuse)
v := NewLightFromPointer(unsafe.Pointer(ret))
return v
}
// Destroy a light and take it out of the list
func DestroyLight(light Light) {
clightdata := NewLightData(light)
C.DestroyLight(clightdata.cptr())
}
// Init VR device
func InitVrDevice(vdDevice VrDevice) {
cvdDevice := (C.int)(vdDevice)

536
raylib/shapes.c Normal file
View file

@ -0,0 +1,536 @@
/**********************************************************************************************
*
* raylib.shapes
*
* Basic functions to draw 2d Shapes and check collisions
*
* External libs:
* rlgl - raylib OpenGL abstraction layer
*
* Module Configuration Flags:
* ...
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* 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.
*
**********************************************************************************************/
#include "raylib.h"
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2
#include <stdlib.h> // Required for: abs()
#include <math.h> // Required for: sinf(), cosf(), sqrtf()
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
// Nop...
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Not here...
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
// ...
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
// No private (static) functions in this module (.c file)
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
// Draw a pixel
void DrawPixel(int posX, int posY, Color color)
{
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2i(posX, posY);
rlVertex2i(posX + 1, posY + 1);
rlEnd();
}
// Draw a pixel (Vector version)
void DrawPixelV(Vector2 position, Color color)
{
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(position.x, position.y);
rlVertex2f(position.x + 1.0f, position.y + 1.0f);
rlEnd();
}
// Draw a line
void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color)
{
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2i(startPosX, startPosY);
rlVertex2i(endPosX, endPosY);
rlEnd();
}
// Draw a line (Vector version)
void DrawLineV(Vector2 startPos, Vector2 endPos, Color color)
{
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(startPos.x, startPos.y);
rlVertex2f(endPos.x, endPos.y);
rlEnd();
}
// Draw a color-filled circle
void DrawCircle(int centerX, int centerY, float radius, Color color)
{
DrawCircleV((Vector2){ (float)centerX, (float)centerY }, radius, color);
}
// Draw a gradient-filled circle
// NOTE: Gradient goes from center (color1) to border (color2)
void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2)
{
rlBegin(RL_TRIANGLES);
for (int i = 0; i < 360; i += 10)
{
rlColor4ub(color1.r, color1.g, color1.b, color1.a);
rlVertex2i(centerX, centerY);
rlColor4ub(color2.r, color2.g, color2.b, color2.a);
rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius);
rlColor4ub(color2.r, color2.g, color2.b, color2.a);
rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius);
}
rlEnd();
}
// Draw a color-filled circle (Vector version)
// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw)
void DrawCircleV(Vector2 center, float radius, Color color)
{
if (rlGetVersion() == OPENGL_11)
{
rlBegin(RL_TRIANGLES);
for (int i = 0; i < 360; i += 10)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x, center.y);
rlVertex2f(center.x + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius);
rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius);
}
rlEnd();
}
else if ((rlGetVersion() == OPENGL_21) || (rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20))
{
rlEnableTexture(GetDefaultTexture().id); // Default white texture
rlBegin(RL_QUADS);
for (int i = 0; i < 360; i += 20)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(center.x, center.y);
rlVertex2f(center.x + sinf(DEG2RAD*i)*radius, center.y + cosf(DEG2RAD*i)*radius);
rlVertex2f(center.x + sinf(DEG2RAD*(i + 10))*radius, center.y + cosf(DEG2RAD*(i + 10))*radius);
rlVertex2f(center.x + sinf(DEG2RAD*(i + 20))*radius, center.y + cosf(DEG2RAD*(i + 20))*radius);
}
rlEnd();
rlDisableTexture();
}
}
// Draw circle outline
void DrawCircleLines(int centerX, int centerY, float radius, Color color)
{
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
// NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360)
for (int i = 0; i < 360; i += 10)
{
rlVertex2f(centerX + sinf(DEG2RAD*i)*radius, centerY + cosf(DEG2RAD*i)*radius);
rlVertex2f(centerX + sinf(DEG2RAD*(i + 10))*radius, centerY + cosf(DEG2RAD*(i + 10))*radius);
}
rlEnd();
}
// Draw a color-filled rectangle
void DrawRectangle(int posX, int posY, int width, int height, Color color)
{
Vector2 position = { (float)posX, (float)posY };
Vector2 size = { (float)width, (float)height };
DrawRectangleV(position, size, color);
}
// Draw a color-filled rectangle
void DrawRectangleRec(Rectangle rec, Color color)
{
DrawRectangle(rec.x, rec.y, rec.width, rec.height, color);
}
// Draw a gradient-filled rectangle
// NOTE: Gradient goes from bottom (color1) to top (color2)
void DrawRectangleGradient(int posX, int posY, int width, int height, Color color1, Color color2)
{
rlBegin(RL_TRIANGLES);
rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX, posY);
rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX, posY + height);
rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX + width, posY + height);
rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX, posY);
rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX + width, posY + height);
rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX + width, posY);
rlEnd();
}
// Draw a color-filled rectangle (Vector version)
// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw)
void DrawRectangleV(Vector2 position, Vector2 size, Color color)
{
if (rlGetVersion() == OPENGL_11)
{
rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2i(position.x, position.y);
rlVertex2i(position.x, position.y + size.y);
rlVertex2i(position.x + size.x, position.y + size.y);
rlVertex2i(position.x, position.y);
rlVertex2i(position.x + size.x, position.y + size.y);
rlVertex2i(position.x + size.x, position.y);
rlEnd();
}
else if ((rlGetVersion() == OPENGL_21) || (rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20))
{
rlEnableTexture(GetDefaultTexture().id); // Default white texture
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
rlNormal3f(0.0f, 0.0f, 1.0f);
rlTexCoord2f(0.0f, 0.0f);
rlVertex2f(position.x, position.y);
rlTexCoord2f(0.0f, 1.0f);
rlVertex2f(position.x, position.y + size.y);
rlTexCoord2f(1.0f, 1.0f);
rlVertex2f(position.x + size.x, position.y + size.y);
rlTexCoord2f(1.0f, 0.0f);
rlVertex2f(position.x + size.x, position.y);
rlEnd();
rlDisableTexture();
}
}
// Draw rectangle outline
// NOTE: On OpenGL 3.3 and ES2 we use QUADS to avoid drawing order issues (view rlglDraw)
void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
{
if (rlGetVersion() == OPENGL_11)
{
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2i(posX + 1, posY + 1);
rlVertex2i(posX + width, posY + 1);
rlVertex2i(posX + width, posY + 1);
rlVertex2i(posX + width, posY + height);
rlVertex2i(posX + width, posY + height);
rlVertex2i(posX + 1, posY + height);
rlVertex2i(posX + 1, posY + height);
rlVertex2i(posX + 1, posY + 1);
rlEnd();
}
else if ((rlGetVersion() == OPENGL_21) || (rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20))
{
DrawRectangle(posX, posY, width, 1, color);
DrawRectangle(posX + width - 1, posY + 1, 1, height - 2, color);
DrawRectangle(posX, posY + height - 1, width, 1, color);
DrawRectangle(posX, posY + 1, 1, height - 2, color);
}
}
// Draw a triangle
void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
{
if (rlGetVersion() == OPENGL_11)
{
rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(v1.x, v1.y);
rlVertex2f(v2.x, v2.y);
rlVertex2f(v3.x, v3.y);
rlEnd();
}
else if ((rlGetVersion() == OPENGL_21) || (rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20))
{
rlEnableTexture(GetDefaultTexture().id); // Default white texture
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(v1.x, v1.y);
rlVertex2f(v2.x, v2.y);
rlVertex2f(v2.x, v2.y);
rlVertex2f(v3.x, v3.y);
rlEnd();
rlDisableTexture();
}
}
void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
{
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(v1.x, v1.y);
rlVertex2f(v2.x, v2.y);
rlVertex2f(v2.x, v2.y);
rlVertex2f(v3.x, v3.y);
rlVertex2f(v3.x, v3.y);
rlVertex2f(v1.x, v1.y);
rlEnd();
}
// Draw a regular polygon of n sides (Vector version)
void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color)
{
if (sides < 3) sides = 3;
rlPushMatrix();
rlTranslatef(center.x, center.y, 0.0);
rlRotatef(rotation, 0, 0, 1);
rlBegin(RL_TRIANGLES);
for (int i = 0; i < 360; i += 360/sides)
{
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(0, 0);
rlVertex2f(sinf(DEG2RAD*i)*radius, cosf(DEG2RAD*i)*radius);
rlVertex2f(sinf(DEG2RAD*(i + 360/sides))*radius, cosf(DEG2RAD*(i + 360/sides))*radius);
}
rlEnd();
rlPopMatrix();
}
// Draw a closed polygon defined by points
// NOTE: Array num elements MUST be passed as parameter to function
void DrawPolyEx(Vector2 *points, int numPoints, Color color)
{
if (numPoints >= 3)
{
rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 1; i < numPoints - 1; i++)
{
rlVertex2f(points[0].x, points[0].y);
rlVertex2f(points[i].x, points[i].y);
rlVertex2f(points[i + 1].x, points[i + 1].y);
}
rlEnd();
}
}
// Draw polygon lines
// NOTE: Array num elements MUST be passed as parameter to function
void DrawPolyExLines(Vector2 *points, int numPoints, Color color)
{
if (numPoints >= 2)
{
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 0; i < numPoints - 1; i++)
{
rlVertex2f(points[i].x, points[i].y);
rlVertex2f(points[i + 1].x, points[i + 1].y);
}
rlEnd();
}
}
//----------------------------------------------------------------------------------
// Module Functions Definition - Collision Detection functions
//----------------------------------------------------------------------------------
// Check if point is inside rectangle
bool CheckCollisionPointRec(Vector2 point, Rectangle rec)
{
bool collision = false;
if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) && (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true;
return collision;
}
// Check if point is inside circle
bool CheckCollisionPointCircle(Vector2 point, Vector2 center, float radius)
{
return CheckCollisionCircles(point, 0, center, radius);
}
// Check if point is inside a triangle defined by three points (p1, p2, p3)
bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 p3)
{
bool collision = false;
float alpha = ((p2.y - p3.y)*(point.x - p3.x) + (p3.x - p2.x)*(point.y - p3.y)) /
((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y));
float beta = ((p3.y - p1.y)*(point.x - p3.x) + (p1.x - p3.x)*(point.y - p3.y)) /
((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y));
float gamma = 1.0f - alpha - beta;
if ((alpha > 0) && (beta > 0) & (gamma > 0)) collision = true;
return collision;
}
// Check collision between two rectangles
bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2)
{
bool collision = false;
int dx = abs((rec1.x + rec1.width/2) - (rec2.x + rec2.width/2));
int dy = abs((rec1.y + rec1.height/2) - (rec2.y + rec2.height/2));
if ((dx <= (rec1.width/2 + rec2.width/2)) && ((dy <= (rec1.height/2 + rec2.height/2)))) collision = true;
return collision;
}
// Check collision between two circles
bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2)
{
bool collision = false;
float dx = center2.x - center1.x; // X distance between centers
float dy = center2.y - center1.y; // Y distance between centers
float distance = sqrtf(dx*dx + dy*dy); // Distance between centers
if (distance <= (radius1 + radius2)) collision = true;
return collision;
}
// Check collision between circle and rectangle
// NOTE: Reviewed version to take into account corner limit case
bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
{
int recCenterX = rec.x + rec.width/2;
int recCenterY = rec.y + rec.height/2;
float dx = fabsf(center.x - recCenterX);
float dy = fabsf(center.y - recCenterY);
if (dx > ((float)rec.width/2.0f + radius)) { return false; }
if (dy > ((float)rec.height/2.0f + radius)) { return false; }
if (dx <= ((float)rec.width/2.0f)) { return true; }
if (dy <= ((float)rec.height/2.0f)) { return true; }
float cornerDistanceSq = (dx - (float)rec.width/2.0f)*(dx - (float)rec.width/2.0f) +
(dy - (float)rec.height/2.0f)*(dy - (float)rec.height/2.0f);
return (cornerDistanceSq <= (radius*radius));
}
// Get collision rectangle for two rectangles collision
Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
{
Rectangle retRec = { 0, 0, 0, 0 };
if (CheckCollisionRecs(rec1, rec2))
{
int dxx = abs(rec1.x - rec2.x);
int dyy = abs(rec1.y - rec2.y);
if (rec1.x <= rec2.x)
{
if (rec1.y <= rec2.y)
{
retRec.x = rec2.x;
retRec.y = rec2.y;
retRec.width = rec1.width - dxx;
retRec.height = rec1.height - dyy;
}
else
{
retRec.x = rec2.x;
retRec.y = rec1.y;
retRec.width = rec1.width - dxx;
retRec.height = rec2.height - dyy;
}
}
else
{
if (rec1.y <= rec2.y)
{
retRec.x = rec1.x;
retRec.y = rec2.y;
retRec.width = rec2.width - dxx;
retRec.height = rec1.height - dyy;
}
else
{
retRec.x = rec1.x;
retRec.y = rec1.y;
retRec.width = rec2.width - dxx;
retRec.height = rec2.height - dyy;
}
}
if (rec1.width > rec2.width)
{
if (retRec.width >= rec2.width) retRec.width = rec2.width;
}
else
{
if (retRec.width >= rec1.width) retRec.width = rec1.width;
}
if (rec1.height > rec2.height)
{
if (retRec.height >= rec2.height) retRec.height = rec2.height;
}
else
{
if (retRec.height >= rec1.height) retRec.height = rec1.height;
}
}
return retRec;
}

5010
raylib/stb_vorbis.c Normal file

File diff suppressed because it is too large Load diff

393
raylib/stb_vorbis.h Normal file
View file

@ -0,0 +1,393 @@
// Ogg Vorbis audio decoder - v1.09 - public domain
// http://nothings.org/stb_vorbis/
//
// Original version written by Sean Barrett in 2007.
//
// Originally sponsored by RAD Game Tools. Seeking sponsored
// by Phillip Bennefall, Marc Andersen, Aaron Baker, Elias Software,
// Aras Pranckevicius, and Sean Barrett.
//
// LICENSE
//
// This software is dual-licensed to the public domain and under the following
// license: you are granted a perpetual, irrevocable license to copy, modify,
// publish, and distribute this file as you see fit.
//
// No warranty for any purpose is expressed or implied by the author (nor
// by RAD Game Tools). Report bugs and send enhancements to the author.
//
// Limitations:
//
// - floor 0 not supported (used in old ogg vorbis files pre-2004)
// - lossless sample-truncation at beginning ignored
// - cannot concatenate multiple vorbis streams
// - sample positions are 32-bit, limiting seekable 192Khz
// files to around 6 hours (Ogg supports 64-bit)
//
// Feature contributors:
// Dougall Johnson (sample-exact seeking)
//
// Bugfix/warning contributors:
// Terje Mathisen Niklas Frykholm Andy Hill
// Casey Muratori John Bolton Gargaj
// Laurent Gomila Marc LeBlanc Ronny Chevalier
// Bernhard Wodo Evan Balster alxprd@github
// Tom Beaumont Ingo Leitgeb Nicolas Guillemot
// Phillip Bennefall Rohit Thiago Goulart
// manxorist@github saga musix
//
// Partial history:
// 1.09 - 2016/04/04 - back out 'truncation of last frame' fix from previous version
// 1.08 - 2016/04/02 - warnings; setup memory leaks; truncation of last frame
// 1.07 - 2015/01/16 - fixes for crashes on invalid files; warning fixes; const
// 1.06 - 2015/08/31 - full, correct support for seeking API (Dougall Johnson)
// some crash fixes when out of memory or with corrupt files
// fix some inappropriately signed shifts
// 1.05 - 2015/04/19 - don't define __forceinline if it's redundant
// 1.04 - 2014/08/27 - fix missing const-correct case in API
// 1.03 - 2014/08/07 - warning fixes
// 1.02 - 2014/07/09 - declare qsort comparison as explicitly _cdecl in Windows
// 1.01 - 2014/06/18 - fix stb_vorbis_get_samples_float (interleaved was correct)
// 1.0 - 2014/05/26 - fix memory leaks; fix warnings; fix bugs in >2-channel;
// (API change) report sample rate for decode-full-file funcs
//
// See end of file for full version history.
//////////////////////////////////////////////////////////////////////////////
//
// HEADER BEGINS HERE
//
#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H
#define STB_VORBIS_INCLUDE_STB_VORBIS_H
#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
#define STB_VORBIS_NO_STDIO 1
#endif
#ifndef STB_VORBIS_NO_STDIO
#include <stdio.h>
#endif
// NOTE: Added to work with raylib on Android
#if defined(PLATFORM_ANDROID)
#include "utils.h" // Android fopen function map
#endif
#ifdef __cplusplus
extern "C" {
#endif
/////////// THREAD SAFETY
// Individual stb_vorbis* handles are not thread-safe; you cannot decode from
// them from multiple threads at the same time. However, you can have multiple
// stb_vorbis* handles and decode from them independently in multiple thrads.
/////////// MEMORY ALLOCATION
// normally stb_vorbis uses malloc() to allocate memory at startup,
// and alloca() to allocate temporary memory during a frame on the
// stack. (Memory consumption will depend on the amount of setup
// data in the file and how you set the compile flags for speed
// vs. size. In my test files the maximal-size usage is ~150KB.)
//
// You can modify the wrapper functions in the source (setup_malloc,
// setup_temp_malloc, temp_malloc) to change this behavior, or you
// can use a simpler allocation model: you pass in a buffer from
// which stb_vorbis will allocate _all_ its memory (including the
// temp memory). "open" may fail with a VORBIS_outofmem if you
// do not pass in enough data; there is no way to determine how
// much you do need except to succeed (at which point you can
// query get_info to find the exact amount required. yes I know
// this is lame).
//
// If you pass in a non-NULL buffer of the type below, allocation
// will occur from it as described above. Otherwise just pass NULL
// to use malloc()/alloca()
typedef struct
{
char *alloc_buffer;
int alloc_buffer_length_in_bytes;
} stb_vorbis_alloc;
/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES
typedef struct stb_vorbis stb_vorbis;
typedef struct
{
unsigned int sample_rate;
int channels;
unsigned int setup_memory_required;
unsigned int setup_temp_memory_required;
unsigned int temp_memory_required;
int max_frame_size;
} stb_vorbis_info;
// get general information about the file
extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f);
// get the last error detected (clears it, too)
extern int stb_vorbis_get_error(stb_vorbis *f);
// close an ogg vorbis file and free all memory in use
extern void stb_vorbis_close(stb_vorbis *f);
// this function returns the offset (in samples) from the beginning of the
// file that will be returned by the next decode, if it is known, or -1
// otherwise. after a flush_pushdata() call, this may take a while before
// it becomes valid again.
// NOT WORKING YET after a seek with PULLDATA API
extern int stb_vorbis_get_sample_offset(stb_vorbis *f);
// returns the current seek point within the file, or offset from the beginning
// of the memory buffer. In pushdata mode it returns 0.
extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);
/////////// PUSHDATA API
#ifndef STB_VORBIS_NO_PUSHDATA_API
// this API allows you to get blocks of data from any source and hand
// them to stb_vorbis. you have to buffer them; stb_vorbis will tell
// you how much it used, and you have to give it the rest next time;
// and stb_vorbis may not have enough data to work with and you will
// need to give it the same data again PLUS more. Note that the Vorbis
// specification does not bound the size of an individual frame.
extern stb_vorbis *stb_vorbis_open_pushdata(
const unsigned char * datablock, int datablock_length_in_bytes,
int *datablock_memory_consumed_in_bytes,
int *error,
const stb_vorbis_alloc *alloc_buffer);
// create a vorbis decoder by passing in the initial data block containing
// the ogg&vorbis headers (you don't need to do parse them, just provide
// the first N bytes of the file--you're told if it's not enough, see below)
// on success, returns an stb_vorbis *, does not set error, returns the amount of
// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes;
// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed
// if returns NULL and *error is VORBIS_need_more_data, then the input block was
// incomplete and you need to pass in a larger block from the start of the file
extern int stb_vorbis_decode_frame_pushdata(
stb_vorbis *f,
const unsigned char *datablock, int datablock_length_in_bytes,
int *channels, // place to write number of float * buffers
float ***output, // place to write float ** array of float * buffers
int *samples // place to write number of output samples
);
// decode a frame of audio sample data if possible from the passed-in data block
//
// return value: number of bytes we used from datablock
//
// possible cases:
// 0 bytes used, 0 samples output (need more data)
// N bytes used, 0 samples output (resynching the stream, keep going)
// N bytes used, M samples output (one frame of data)
// note that after opening a file, you will ALWAYS get one N-bytes,0-sample
// frame, because Vorbis always "discards" the first frame.
//
// Note that on resynch, stb_vorbis will rarely consume all of the buffer,
// instead only datablock_length_in_bytes-3 or less. This is because it wants
// to avoid missing parts of a page header if they cross a datablock boundary,
// without writing state-machiney code to record a partial detection.
//
// The number of channels returned are stored in *channels (which can be
// NULL--it is always the same as the number of channels reported by
// get_info). *output will contain an array of float* buffers, one per
// channel. In other words, (*output)[0][0] contains the first sample from
// the first channel, and (*output)[1][0] contains the first sample from
// the second channel.
extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
// inform stb_vorbis that your next datablock will not be contiguous with
// previous ones (e.g. you've seeked in the data); future attempts to decode
// frames will cause stb_vorbis to resynchronize (as noted above), and
// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it
// will begin decoding the _next_ frame.
//
// if you want to seek using pushdata, you need to seek in your file, then
// call stb_vorbis_flush_pushdata(), then start calling decoding, then once
// decoding is returning you data, call stb_vorbis_get_sample_offset, and
// if you don't like the result, seek your file again and repeat.
#endif
////////// PULLING INPUT API
#ifndef STB_VORBIS_NO_PULLDATA_API
// This API assumes stb_vorbis is allowed to pull data from a source--
// either a block of memory containing the _entire_ vorbis stream, or a
// FILE * that you or it create, or possibly some other reading mechanism
// if you go modify the source to replace the FILE * case with some kind
// of callback to your code. (But if you don't support seeking, you may
// just want to go ahead and use pushdata.)
#if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
extern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output);
#endif
#if !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output);
#endif
// decode an entire file and output the data interleaved into a malloc()ed
// buffer stored in *output. The return value is the number of samples
// decoded, or -1 if the file could not be opened or was not an ogg vorbis file.
// When you're done with it, just free() the pointer returned in *output.
extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len,
int *error, const stb_vorbis_alloc *alloc_buffer);
// create an ogg vorbis decoder from an ogg vorbis stream in memory (note
// this must be the entire stream!). on failure, returns NULL and sets *error
#ifndef STB_VORBIS_NO_STDIO
extern stb_vorbis * stb_vorbis_open_filename(const char *filename,
int *error, const stb_vorbis_alloc *alloc_buffer);
// create an ogg vorbis decoder from a filename via fopen(). on failure,
// returns NULL and sets *error (possibly to VORBIS_file_open_failure).
extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close,
int *error, const stb_vorbis_alloc *alloc_buffer);
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
// the _current_ seek point (ftell). on failure, returns NULL and sets *error.
// note that stb_vorbis must "own" this stream; if you seek it in between
// calls to stb_vorbis, it will become confused. Morever, if you attempt to
// perform stb_vorbis_seek_*() operations on this file, it will assume it
// owns the _entire_ rest of the file after the start point. Use the next
// function, stb_vorbis_open_file_section(), to limit it.
extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close,
int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len);
// create an ogg vorbis decoder from an open FILE *, looking for a stream at
// the _current_ seek point (ftell); the stream will be of length 'len' bytes.
// on failure, returns NULL and sets *error. note that stb_vorbis must "own"
// this stream; if you seek it in between calls to stb_vorbis, it will become
// confused.
#endif
extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number);
extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
// these functions seek in the Vorbis file to (approximately) 'sample_number'.
// after calling seek_frame(), the next call to get_frame_*() will include
// the specified sample. after calling stb_vorbis_seek(), the next call to
// stb_vorbis_get_samples_* will start with the specified sample. If you
// do not need to seek to EXACTLY the target sample when using get_samples_*,
// you can also use seek_frame().
extern void stb_vorbis_seek_start(stb_vorbis *f);
// this function is equivalent to stb_vorbis_seek(f,0)
extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);
extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f);
// these functions return the total length of the vorbis stream
extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output);
// decode the next frame and return the number of samples. the number of
// channels returned are stored in *channels (which can be NULL--it is always
// the same as the number of channels reported by get_info). *output will
// contain an array of float* buffers, one per channel. These outputs will
// be overwritten on the next call to stb_vorbis_get_frame_*.
//
// You generally should not intermix calls to stb_vorbis_get_frame_*()
// and stb_vorbis_get_samples_*(), since the latter calls the former.
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);
extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples);
#endif
// decode the next frame and return the number of *samples* per channel.
// Note that for interleaved data, you pass in the number of shorts (the
// size of your array), but the return value is the number of samples per
// channel, not the total number of samples.
//
// The data is coerced to the number of channels you request according to the
// channel coercion rules (see below). You must pass in the size of your
// buffer(s) so that stb_vorbis will not overwrite the end of the buffer.
// The maximum buffer size needed can be gotten from get_info(); however,
// the Vorbis I specification implies an absolute maximum of 4096 samples
// per channel.
// Channel coercion rules:
// Let M be the number of channels requested, and N the number of channels present,
// and Cn be the nth channel; let stereo L be the sum of all L and center channels,
// and stereo R be the sum of all R and center channels (channel assignment from the
// vorbis spec).
// M N output
// 1 k sum(Ck) for all k
// 2 * stereo L, stereo R
// k l k > l, the first l channels, then 0s
// k l k <= l, the first k channels
// Note that this is not _good_ surround etc. mixing at all! It's just so
// you get something useful.
extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats);
extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples);
// gets num_samples samples, not necessarily on a frame boundary--this requires
// buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES.
// Returns the number of samples stored per channel; it may be less than requested
// at the end of the file. If there are no more samples in the file, returns 0.
#ifndef STB_VORBIS_NO_INTEGER_CONVERSION
extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts);
extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples);
#endif
// gets num_samples samples, not necessarily on a frame boundary--this requires
// buffering so you have to supply the buffers. Applies the coercion rules above
// to produce 'channels' channels. Returns the number of samples stored per channel;
// it may be less than requested at the end of the file. If there are no more
// samples in the file, returns 0.
#endif
//////// ERROR CODES
enum STBVorbisError
{
VORBIS__no_error,
VORBIS_need_more_data=1, // not a real error
VORBIS_invalid_api_mixing, // can't mix API modes
VORBIS_outofmem, // not enough memory
VORBIS_feature_not_supported, // uses floor 0
VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small
VORBIS_file_open_failure, // fopen() failed
VORBIS_seek_without_length, // can't seek in unknown-length file
VORBIS_unexpected_eof=10, // file is truncated?
VORBIS_seek_invalid, // seek past EOF
// decoding errors (corrupt/invalid stream) -- you probably
// don't care about the exact details of these
// vorbis errors:
VORBIS_invalid_setup=20,
VORBIS_invalid_stream,
// ogg errors:
VORBIS_missing_capture_pattern=30,
VORBIS_invalid_stream_structure_version,
VORBIS_continued_packet_flag_invalid,
VORBIS_incorrect_stream_serial_number,
VORBIS_invalid_first_page,
VORBIS_bad_packet_type,
VORBIS_cant_find_last_page,
VORBIS_seek_failed
};
#ifdef __cplusplus
}
#endif
#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H
//
// HEADER ENDS HERE
//
//////////////////////////////////////////////////////////////////////////////

999
raylib/text.c Normal file
View file

@ -0,0 +1,999 @@
/**********************************************************************************************
*
* raylib.text
*
* Basic functions to load SpriteFonts and draw Text
*
* External libs:
* stb_truetype - Load TTF file and rasterize characters data
*
* Module Configuration Flags:
* ...
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* 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.
*
**********************************************************************************************/
#include "raylib.h"
#include <stdlib.h> // Required for: malloc(), free()
#include <string.h> // Required for: strlen()
#include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end()
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fscanf(), feof(), rewind(), fgets()
#include "utils.h" // Required for: GetExtension()
// Following libs are used on LoadTTF()
#define STBTT_STATIC // Define stb_truetype functions static to this module
#define STB_TRUETYPE_IMPLEMENTATION
#include "external/stb_truetype.h" // Required for: stbtt_BakeFontBitmap()
// Rectangle packing functions (not used at the moment)
//#define STB_RECT_PACK_IMPLEMENTATION
//#include "stb_rect_pack.h"
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define MAX_FORMATTEXT_LENGTH 64
#define MAX_SUBTEXT_LENGTH 64
#define BIT_CHECK(a,b) ((a) & (1 << (b)))
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// ...
//----------------------------------------------------------------------------------
// Global variables
//----------------------------------------------------------------------------------
static SpriteFont defaultFont; // Default font provided by raylib
// NOTE: defaultFont is loaded on InitWindow and disposed on CloseWindow [module: core]
//----------------------------------------------------------------------------------
// Other Modules Functions Declaration (required by text)
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
static int GetCharIndex(SpriteFont font, int letter);
static SpriteFont LoadImageFont(Image image, Color key, int firstChar); // Load a Image font file (XNA style)
static SpriteFont LoadRBMF(const char *fileName); // Load a rBMF font file (raylib BitMap Font)
static SpriteFont LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file)
static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int *fontChars); // Load spritefont from TTF data
extern void LoadDefaultFont(void);
extern void UnloadDefaultFont(void);
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
extern void LoadDefaultFont(void)
{
// NOTE: Using UTF8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
// http://www.utf8-chartable.de/unicode-utf8-table.pl
defaultFont.numChars = 224; // Number of chars included in our default font
// Default font is directly defined here (data generated from a sprite font image)
// This way, we reconstruct SpriteFont without creating large global variables
// This data is automatically allocated to Stack and automatically deallocated at the end of this function
int defaultFontData[512] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00200020, 0x0001b000, 0x00000000, 0x00000000, 0x8ef92520, 0x00020a00, 0x7dbe8000, 0x1f7df45f,
0x4a2bf2a0, 0x0852091e, 0x41224000, 0x10041450, 0x2e292020, 0x08220812, 0x41222000, 0x10041450, 0x10f92020, 0x3efa084c, 0x7d22103c, 0x107df7de,
0xe8a12020, 0x08220832, 0x05220800, 0x10450410, 0xa4a3f000, 0x08520832, 0x05220400, 0x10450410, 0xe2f92020, 0x0002085e, 0x7d3e0281, 0x107df41f,
0x00200000, 0x8001b000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xc0000fbe, 0xfbf7e00f, 0x5fbf7e7d, 0x0050bee8, 0x440808a2, 0x0a142fe8, 0x50810285, 0x0050a048,
0x49e428a2, 0x0a142828, 0x40810284, 0x0048a048, 0x10020fbe, 0x09f7ebaf, 0xd89f3e84, 0x0047a04f, 0x09e48822, 0x0a142aa1, 0x50810284, 0x0048a048,
0x04082822, 0x0a142fa0, 0x50810285, 0x0050a248, 0x00008fbe, 0xfbf42021, 0x5f817e7d, 0x07d09ce8, 0x00008000, 0x00000fe0, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000c0180,
0xdfbf4282, 0x0bfbf7ef, 0x42850505, 0x004804bf, 0x50a142c6, 0x08401428, 0x42852505, 0x00a808a0, 0x50a146aa, 0x08401428, 0x42852505, 0x00081090,
0x5fa14a92, 0x0843f7e8, 0x7e792505, 0x00082088, 0x40a15282, 0x08420128, 0x40852489, 0x00084084, 0x40a16282, 0x0842022a, 0x40852451, 0x00088082,
0xc0bf4282, 0xf843f42f, 0x7e85fc21, 0x3e0900bf, 0x00000000, 0x00000004, 0x00000000, 0x000c0180, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04000402, 0x41482000, 0x00000000, 0x00000800,
0x04000404, 0x4100203c, 0x00000000, 0x00000800, 0xf7df7df0, 0x514bef85, 0xbefbefbe, 0x04513bef, 0x14414500, 0x494a2885, 0xa28a28aa, 0x04510820,
0xf44145f0, 0x474a289d, 0xa28a28aa, 0x04510be0, 0x14414510, 0x494a2884, 0xa28a28aa, 0x02910a00, 0xf7df7df0, 0xd14a2f85, 0xbefbe8aa, 0x011f7be0,
0x00000000, 0x00400804, 0x20080000, 0x00000000, 0x00000000, 0x00600f84, 0x20080000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0xac000000, 0x00000f01, 0x00000000, 0x00000000, 0x24000000, 0x00000901, 0x00000000, 0x06000000, 0x24000000, 0x00000901, 0x00000000, 0x09108000,
0x24fa28a2, 0x00000901, 0x00000000, 0x013e0000, 0x2242252a, 0x00000952, 0x00000000, 0x038a8000, 0x2422222a, 0x00000929, 0x00000000, 0x010a8000,
0x2412252a, 0x00000901, 0x00000000, 0x010a8000, 0x24fbe8be, 0x00000901, 0x00000000, 0x0ebe8000, 0xac020000, 0x00000f01, 0x00000000, 0x00048000,
0x0003e000, 0x00000000, 0x00000000, 0x00008000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000038, 0x8443b80e, 0x00203a03,
0x02bea080, 0xf0000020, 0xc452208a, 0x04202b02, 0xf8029122, 0x07f0003b, 0xe44b388e, 0x02203a02, 0x081e8a1c, 0x0411e92a, 0xf4420be0, 0x01248202,
0xe8140414, 0x05d104ba, 0xe7c3b880, 0x00893a0a, 0x283c0e1c, 0x04500902, 0xc4400080, 0x00448002, 0xe8208422, 0x04500002, 0x80400000, 0x05200002,
0x083e8e00, 0x04100002, 0x804003e0, 0x07000042, 0xf8008400, 0x07f00003, 0x80400000, 0x04000022, 0x00000000, 0x00000000, 0x80400000, 0x04000002,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00800702, 0x1848a0c2, 0x84010000, 0x02920921, 0x01042642, 0x00005121, 0x42023f7f, 0x00291002,
0xefc01422, 0x7efdfbf7, 0xefdfa109, 0x03bbbbf7, 0x28440f12, 0x42850a14, 0x20408109, 0x01111010, 0x28440408, 0x42850a14, 0x2040817f, 0x01111010,
0xefc78204, 0x7efdfbf7, 0xe7cf8109, 0x011111f3, 0x2850a932, 0x42850a14, 0x2040a109, 0x01111010, 0x2850b840, 0x42850a14, 0xefdfbf79, 0x03bbbbf7,
0x001fa020, 0x00000000, 0x00001000, 0x00000000, 0x00002070, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x08022800, 0x00012283, 0x02430802, 0x01010001, 0x8404147c, 0x20000144, 0x80048404, 0x00823f08, 0xdfbf4284, 0x7e03f7ef, 0x142850a1, 0x0000210a,
0x50a14684, 0x528a1428, 0x142850a1, 0x03efa17a, 0x50a14a9e, 0x52521428, 0x142850a1, 0x02081f4a, 0x50a15284, 0x4a221428, 0xf42850a1, 0x03efa14b,
0x50a16284, 0x4a521428, 0x042850a1, 0x0228a17a, 0xdfbf427c, 0x7e8bf7ef, 0xf7efdfbf, 0x03efbd0b, 0x00000000, 0x04000000, 0x00000000, 0x00000008,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00200508, 0x00840400, 0x11458122, 0x00014210,
0x00514294, 0x51420800, 0x20a22a94, 0x0050a508, 0x00200000, 0x00000000, 0x00050000, 0x08000000, 0xfefbefbe, 0xfbefbefb, 0xfbeb9114, 0x00fbefbe,
0x20820820, 0x8a28a20a, 0x8a289114, 0x3e8a28a2, 0xfefbefbe, 0xfbefbe0b, 0x8a289114, 0x008a28a2, 0x228a28a2, 0x08208208, 0x8a289114, 0x088a28a2,
0xfefbefbe, 0xfbefbefb, 0xfa2f9114, 0x00fbefbe, 0x00000000, 0x00000040, 0x00000000, 0x00000000, 0x00000000, 0x00000020, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00210100, 0x00000004, 0x00000000, 0x00000000, 0x14508200, 0x00001402, 0x00000000, 0x00000000,
0x00000010, 0x00000020, 0x00000000, 0x00000000, 0xa28a28be, 0x00002228, 0x00000000, 0x00000000, 0xa28a28aa, 0x000022e8, 0x00000000, 0x00000000,
0xa28a28aa, 0x000022a8, 0x00000000, 0x00000000, 0xa28a28aa, 0x000022e8, 0x00000000, 0x00000000, 0xbefbefbe, 0x00003e2f, 0x00000000, 0x00000000,
0x00000004, 0x00002028, 0x00000000, 0x00000000, 0x80000000, 0x00003e0f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
int charsHeight = 10;
int charsDivisor = 1; // Every char is separated from the consecutive by a 1 pixel divisor, horizontally and vertically
int charsWidth[224] = { 3, 1, 4, 6, 5, 7, 6, 2, 3, 3, 5, 5, 2, 4, 1, 7, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 3, 4, 3, 6,
7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 5, 6, 5, 7, 6, 6, 6, 6, 6, 6, 7, 6, 7, 7, 6, 6, 6, 2, 7, 2, 3, 5,
2, 5, 5, 5, 5, 5, 4, 5, 5, 1, 2, 5, 2, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 3, 1, 3, 4, 4,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 5, 5, 5, 7, 1, 5, 3, 7, 3, 5, 4, 1, 7, 4, 3, 5, 3, 3, 2, 5, 6, 1, 2, 2, 3, 5, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 3, 3, 3, 3, 7, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 6, 4, 6,
5, 5, 5, 5, 5, 5, 9, 5, 5, 5, 5, 5, 2, 2, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 5 };
// Re-construct image from defaultFontData and generate OpenGL texture
//----------------------------------------------------------------------
int imWidth = 128;
int imHeight = 128;
Color *imagePixels = (Color *)malloc(imWidth*imHeight*sizeof(Color));
for (int i = 0; i < imWidth*imHeight; i++) imagePixels[i] = BLANK; // Initialize array
int counter = 0; // Font data elements counter
// Fill imgData with defaultFontData (convert from bit to pixel!)
for (int i = 0; i < imWidth*imHeight; i += 32)
{
for (int j = 31; j >= 0; j--)
{
if (BIT_CHECK(defaultFontData[counter], j)) imagePixels[i+j] = WHITE;
}
counter++;
if (counter > 512) counter = 0; // Security check...
}
//FILE *myimage = fopen("default_font.raw", "wb");
//fwrite(image.pixels, 1, 128*128*4, myimage);
//fclose(myimage);
Image image = LoadImageEx(imagePixels, imWidth, imHeight);
ImageFormat(&image, UNCOMPRESSED_GRAY_ALPHA);
free(imagePixels);
defaultFont.texture = LoadTextureFromImage(image);
UnloadImage(image);
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, numChars
//------------------------------------------------------------------------------
defaultFont.charValues = (int *)malloc(defaultFont.numChars*sizeof(int));
defaultFont.charRecs = (Rectangle *)malloc(defaultFont.numChars*sizeof(Rectangle)); // Allocate space for our character rectangle data
// This memory should be freed at end! --> Done on CloseWindow()
defaultFont.charOffsets = (Vector2 *)malloc(defaultFont.numChars*sizeof(Vector2));
defaultFont.charAdvanceX = (int *)malloc(defaultFont.numChars*sizeof(int));
int currentLine = 0;
int currentPosX = charsDivisor;
int testPosX = charsDivisor;
for (int i = 0; i < defaultFont.numChars; i++)
{
defaultFont.charValues[i] = 32 + i; // First char is 32
defaultFont.charRecs[i].x = currentPosX;
defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor);
defaultFont.charRecs[i].width = charsWidth[i];
defaultFont.charRecs[i].height = charsHeight;
testPosX += (defaultFont.charRecs[i].width + charsDivisor);
if (testPosX >= defaultFont.texture.width)
{
currentLine++;
currentPosX = 2*charsDivisor + charsWidth[i];
testPosX = currentPosX;
defaultFont.charRecs[i].x = charsDivisor;
defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor);
}
else currentPosX = testPosX;
// NOTE: On default font character offsets and xAdvance are not required
defaultFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f };
defaultFont.charAdvanceX[i] = 0;
}
defaultFont.size = defaultFont.charRecs[0].height;
TraceLog(INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id);
}
extern void UnloadDefaultFont(void)
{
UnloadTexture(defaultFont.texture);
free(defaultFont.charValues);
free(defaultFont.charRecs);
free(defaultFont.charOffsets);
free(defaultFont.charAdvanceX);
}
// Get the default font, useful to be used with extended parameters
SpriteFont GetDefaultFont()
{
return defaultFont;
}
// Load SpriteFont from file into GPU memory (VRAM)
SpriteFont LoadSpriteFont(const char *fileName)
{
// Default hardcoded values for ttf file loading
#define DEFAULT_TTF_FONTSIZE 32 // Font first character (32 - space)
#define DEFAULT_TTF_NUMCHARS 95 // ASCII 32..126 is 95 glyphs
#define DEFAULT_FIRST_CHAR 32 // Expected first char for image spritefont
SpriteFont spriteFont = { 0 };
// Check file extension
if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName);
else if (strcmp(GetExtension(fileName),"ttf") == 0) spriteFont = LoadSpriteFontTTF(fileName, DEFAULT_TTF_FONTSIZE, 0, NULL);
else if (strcmp(GetExtension(fileName),"fnt") == 0) spriteFont = LoadBMFont(fileName);
else
{
Image image = LoadImage(fileName);
if (image.data != NULL) spriteFont = LoadImageFont(image, MAGENTA, DEFAULT_FIRST_CHAR);
UnloadImage(image);
}
if (spriteFont.texture.id == 0)
{
TraceLog(WARNING, "[%s] SpriteFont could not be loaded, using default font", fileName);
spriteFont = GetDefaultFont();
}
else SetTextureFilter(spriteFont.texture, FILTER_POINT); // By default we set point filter (best performance)
return spriteFont;
}
// Load SpriteFont from TTF font file with generation parameters
// NOTE: You can pass an array with desired characters, those characters should be available in the font
// if array is NULL, default char set is selected 32..126
SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars)
{
SpriteFont spriteFont = { 0 };
if (strcmp(GetExtension(fileName),"ttf") == 0)
{
if ((fontChars == NULL) || (numChars == 0))
{
int totalChars = 95; // Default charset [32..126]
int *defaultFontChars = (int *)malloc(totalChars*sizeof(int));
for (int i = 0; i < totalChars; i++) defaultFontChars[i] = i + 32; // Default first character: SPACE[32]
spriteFont = LoadTTF(fileName, fontSize, totalChars, defaultFontChars);
}
else spriteFont = LoadTTF(fileName, fontSize, numChars, fontChars);
}
if (spriteFont.texture.id == 0)
{
TraceLog(WARNING, "[%s] SpriteFont could not be generated, using default font", fileName);
spriteFont = GetDefaultFont();
}
return spriteFont;
}
// Unload SpriteFont from GPU memory (VRAM)
void UnloadSpriteFont(SpriteFont spriteFont)
{
// NOTE: Make sure spriteFont is not default font (fallback)
if (spriteFont.texture.id != defaultFont.texture.id)
{
UnloadTexture(spriteFont.texture);
free(spriteFont.charValues);
free(spriteFont.charRecs);
free(spriteFont.charOffsets);
free(spriteFont.charAdvanceX);
TraceLog(DEBUG, "Unloaded sprite font data");
}
}
// Draw text (using default font)
// NOTE: fontSize work like in any drawing program but if fontSize is lower than font-base-size, then font-base-size is used
// NOTE: chars spacing is proportional to fontSize
void DrawText(const char *text, int posX, int posY, int fontSize, Color color)
{
// Check if default font has been loaded
if (defaultFont.texture.id != 0)
{
Vector2 position = { (float)posX, (float)posY };
int defaultFontSize = 10; // Default Font chars height in pixel
if (fontSize < defaultFontSize) fontSize = defaultFontSize;
int spacing = fontSize/defaultFontSize;
DrawTextEx(GetDefaultFont(), text, position, (float)fontSize, spacing, color);
}
}
// Draw text using SpriteFont
// NOTE: chars spacing is NOT proportional to fontSize
void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float fontSize, int spacing, Color tint)
{
int length = strlen(text);
int textOffsetX = 0; // Offset between characters
int textOffsetY = 0; // Required for line break!
float scaleFactor;
unsigned char letter; // Current character
int index; // Index position in sprite font
scaleFactor = fontSize/spriteFont.size;
// NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly
// written in C code files (codified by default as UTF-8)
for (int i = 0; i < length; i++)
{
if ((unsigned char)text[i] == '\n')
{
// NOTE: Fixed line spacing of 1.5 lines
textOffsetY += (int)((spriteFont.size + spriteFont.size/2)*scaleFactor);
textOffsetX = 0;
}
else
{
if ((unsigned char)text[i] == 0xc2) // UTF-8 encoding identification HACK!
{
// Support UTF-8 encoded values from [0xc2 0x80] -> [0xc2 0xbf](¿)
letter = (unsigned char)text[i + 1];
index = GetCharIndex(spriteFont, (int)letter);
i++;
}
else if ((unsigned char)text[i] == 0xc3) // UTF-8 encoding identification HACK!
{
// Support UTF-8 encoded values from [0xc3 0x80](À) -> [0xc3 0xbf](ÿ)
letter = (unsigned char)text[i + 1];
index = GetCharIndex(spriteFont, (int)letter + 64);
i++;
}
else index = GetCharIndex(spriteFont, (int)text[i]);
DrawTexturePro(spriteFont.texture, spriteFont.charRecs[index],
(Rectangle){ position.x + textOffsetX + spriteFont.charOffsets[index].x*scaleFactor,
position.y + textOffsetY + spriteFont.charOffsets[index].y*scaleFactor,
spriteFont.charRecs[index].width*scaleFactor,
spriteFont.charRecs[index].height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint);
if (spriteFont.charAdvanceX[index] == 0) textOffsetX += (int)(spriteFont.charRecs[index].width*scaleFactor + spacing);
else textOffsetX += (int)(spriteFont.charAdvanceX[index]*scaleFactor + spacing);
}
}
}
// Formatting of text with variables to 'embed'
const char *FormatText(const char *text, ...)
{
static char buffer[MAX_FORMATTEXT_LENGTH];
va_list args;
va_start(args, text);
vsprintf(buffer, text, args);
va_end(args);
return buffer;
}
// Get a piece of a text string
const char *SubText(const char *text, int position, int length)
{
static char buffer[MAX_SUBTEXT_LENGTH];
int textLength = strlen(text);
if (position >= textLength)
{
position = textLength - 1;
length = 0;
}
if (length >= textLength) length = textLength;
for (int c = 0 ; c < length ; c++)
{
*(buffer+c) = *(text+position);
text++;
}
*(buffer+length) = '\0';
return buffer;
}
// Measure string width for default font
int MeasureText(const char *text, int fontSize)
{
Vector2 vec = { 0.0f, 0.0f };
// Check if default font has been loaded
if (defaultFont.texture.id != 0)
{
int defaultFontSize = 10; // Default Font chars height in pixel
if (fontSize < defaultFontSize) fontSize = defaultFontSize;
int spacing = fontSize/defaultFontSize;
vec = MeasureTextEx(GetDefaultFont(), text, (float)fontSize, spacing);
}
return (int)vec.x;
}
// Measure string size for SpriteFont
Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, int spacing)
{
int len = strlen(text);
int tempLen = 0; // Used to count longer text line num chars
int lenCounter = 0;
float textWidth = 0;
float tempTextWidth = 0; // Used to count longer text line width
float textHeight = (float)spriteFont.size;
float scaleFactor = fontSize/(float)spriteFont.size;
for (int i = 0; i < len; i++)
{
lenCounter++;
if (text[i] != '\n')
{
int index = GetCharIndex(spriteFont, (int)text[i]);
if (spriteFont.charAdvanceX[index] != 0) textWidth += spriteFont.charAdvanceX[index];
else textWidth += (spriteFont.charRecs[index].width + spriteFont.charOffsets[index].x);
}
else
{
if (tempTextWidth < textWidth) tempTextWidth = textWidth;
lenCounter = 0;
textWidth = 0;
textHeight += ((float)spriteFont.size*1.5f); // NOTE: Fixed line spacing of 1.5 lines
}
if (tempLen < lenCounter) tempLen = lenCounter;
}
if (tempTextWidth < textWidth) tempTextWidth = textWidth;
Vector2 vec;
vec.x = tempTextWidth*scaleFactor + (float)((tempLen - 1)*spacing); // Adds chars spacing to measure
vec.y = textHeight*scaleFactor;
return vec;
}
// Shows current FPS on top-left corner
// NOTE: Uses default font
void DrawFPS(int posX, int posY)
{
// NOTE: We have rounding errors every frame, so it oscillates a lot
DrawText(FormatText("%2i FPS", GetFPS()), posX, posY, 20, LIME);
}
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
static int GetCharIndex(SpriteFont font, int letter)
{
#define UNORDERED_CHARSET
#if defined(UNORDERED_CHARSET)
int index = 0;
for (int i = 0; i < font.numChars; i++)
{
if (font.charValues[i] == letter)
{
index = i;
break;
}
}
return index;
#else
return (letter - 32);
#endif
}
// Load an Image font file (XNA style)
static SpriteFont LoadImageFont(Image image, Color key, int firstChar)
{
#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 lineSpacing = 0;
int x = 0;
int y = 0;
// Default number of characters supported
#define MAX_FONTCHARS 256
// We allocate a temporal arrays for chars data measures,
// once we get the actual number of chars, we copy data to a sized arrays
int tempCharValues[MAX_FONTCHARS];
Rectangle tempCharRecs[MAX_FONTCHARS];
Color *pixels = GetImageData(image);
// Parse image data to get charSpacing and lineSpacing
for (y = 0; y < image.height; y++)
{
for (x = 0; x < image.width; x++)
{
if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break;
}
if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break;
}
charSpacing = x;
lineSpacing = y;
int charHeight = 0;
int j = 0;
while (!COLOR_EQUAL(pixels[(lineSpacing + j)*image.width + charSpacing], key)) j++;
charHeight = j;
// Check array values to get characters: value, x, y, w, h
int index = 0;
int lineToRead = 0;
int xPosToRead = charSpacing;
// Parse image data to get rectangle sizes
while ((lineSpacing + lineToRead*(charHeight + lineSpacing)) < image.height)
{
while ((xPosToRead < image.width) &&
!COLOR_EQUAL((pixels[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*image.width + xPosToRead]), key))
{
tempCharValues[index] = firstChar + index;
tempCharRecs[index].x = xPosToRead;
tempCharRecs[index].y = lineSpacing + lineToRead*(charHeight + lineSpacing);
tempCharRecs[index].height = charHeight;
int charWidth = 0;
while (!COLOR_EQUAL(pixels[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*image.width + xPosToRead + charWidth], key)) charWidth++;
tempCharRecs[index].width = charWidth;
index++;
xPosToRead += (charWidth + charSpacing);
}
lineToRead++;
xPosToRead = charSpacing;
}
TraceLog(DEBUG, "SpriteFont data parsed correctly from image");
// NOTE: We need to remove key color borders from image to avoid weird
// artifacts on texture scaling when using FILTER_BILINEAR or FILTER_TRILINEAR
for (int i = 0; i < image.height*image.width; i++) if (COLOR_EQUAL(pixels[i], key)) pixels[i] = BLANK;
// Create a new image with the processed color data (key color replaced by BLANK)
Image fontClear = LoadImageEx(pixels, image.width, image.height);
free(pixels); // Free pixels array memory
// Create spritefont with all data parsed from image
SpriteFont spriteFont = { 0 };
spriteFont.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
spriteFont.numChars = index;
UnloadImage(fontClear); // Unload processed image once converted to texture
// We got tempCharValues and tempCharsRecs populated with chars data
// Now we move temp data to sized charValues and charRecs arrays
spriteFont.charRecs = (Rectangle *)malloc(spriteFont.numChars*sizeof(Rectangle));
spriteFont.charValues = (int *)malloc(spriteFont.numChars*sizeof(int));
spriteFont.charOffsets = (Vector2 *)malloc(spriteFont.numChars*sizeof(Vector2));
spriteFont.charAdvanceX = (int *)malloc(spriteFont.numChars*sizeof(int));
for (int i = 0; i < spriteFont.numChars; i++)
{
spriteFont.charValues[i] = tempCharValues[i];
spriteFont.charRecs[i] = tempCharRecs[i];
// NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0)
spriteFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f };
spriteFont.charAdvanceX[i] = 0;
}
spriteFont.size = spriteFont.charRecs[0].height;
TraceLog(INFO, "Image file loaded correctly as SpriteFont");
return spriteFont;
}
// Load a rBMF font file (raylib BitMap Font)
static SpriteFont LoadRBMF(const char *fileName)
{
// rBMF Info Header (16 bytes)
typedef struct {
char id[4]; // rBMF file identifier
char version; // rBMF file version
// 4 MSB --> main version
// 4 LSB --> subversion
char firstChar; // First character in the font
// NOTE: Depending on charDataType, it could be useless
short imgWidth; // Image width - always POT (power-of-two)
short imgHeight; // Image height - always POT (power-of-two)
short numChars; // Number of characters contained
short charHeight; // Characters height - the same for all characters
char compType; // Compression type:
// 4 MSB --> image data compression
// 4 LSB --> chars data compression
char charsDataType; // Char data type provided
} rbmfInfoHeader;
SpriteFont spriteFont = { 0 };
rbmfInfoHeader rbmfHeader;
unsigned int *rbmfFileData = NULL;
unsigned char *rbmfCharWidthData = NULL;
int charsDivisor = 1; // Every char is separated from the consecutive by a 1 pixel divisor, horizontally and vertically
FILE *rbmfFile = fopen(fileName, "rb"); // Define a pointer to bitmap file and open it in read-binary mode
if (rbmfFile == NULL)
{
TraceLog(WARNING, "[%s] rBMF font file could not be opened, using default font", fileName);
spriteFont = GetDefaultFont();
}
else
{
fread(&rbmfHeader, sizeof(rbmfInfoHeader), 1, rbmfFile);
TraceLog(DEBUG, "[%s] Loading rBMF file, size: %ix%i, numChars: %i, charHeight: %i", fileName, rbmfHeader.imgWidth, rbmfHeader.imgHeight, rbmfHeader.numChars, rbmfHeader.charHeight);
spriteFont.numChars = (int)rbmfHeader.numChars;
int numPixelBits = rbmfHeader.imgWidth*rbmfHeader.imgHeight/32;
rbmfFileData = (unsigned int *)malloc(numPixelBits*sizeof(unsigned int));
for (int i = 0; i < numPixelBits; i++) fread(&rbmfFileData[i], sizeof(unsigned int), 1, rbmfFile);
rbmfCharWidthData = (unsigned char *)malloc(spriteFont.numChars*sizeof(unsigned char));
for (int i = 0; i < spriteFont.numChars; i++) fread(&rbmfCharWidthData[i], sizeof(unsigned char), 1, rbmfFile);
// Re-construct image from rbmfFileData
//-----------------------------------------
Color *imagePixels = (Color *)malloc(rbmfHeader.imgWidth*rbmfHeader.imgHeight*sizeof(Color));
for (int i = 0; i < rbmfHeader.imgWidth*rbmfHeader.imgHeight; i++) imagePixels[i] = BLANK; // Initialize array
int counter = 0; // Font data elements counter
// Fill image data (convert from bit to pixel!)
for (int i = 0; i < rbmfHeader.imgWidth*rbmfHeader.imgHeight; i += 32)
{
for (int j = 31; j >= 0; j--)
{
if (BIT_CHECK(rbmfFileData[counter], j)) imagePixels[i+j] = WHITE;
}
counter++;
}
Image image = LoadImageEx(imagePixels, rbmfHeader.imgWidth, rbmfHeader.imgHeight);
ImageFormat(&image, UNCOMPRESSED_GRAY_ALPHA);
free(imagePixels);
TraceLog(DEBUG, "[%s] Image reconstructed correctly, now converting it to texture", fileName);
// Create spritefont with all data read from rbmf file
spriteFont.texture = LoadTextureFromImage(image);
UnloadImage(image); // Unload image data
//TraceLog(INFO, "[%s] Starting chars set reconstruction", fileName);
// Get characters data using rbmfCharWidthData, rbmfHeader.charHeight, charsDivisor, rbmfHeader.numChars
spriteFont.charValues = (int *)malloc(spriteFont.numChars*sizeof(int));
spriteFont.charRecs = (Rectangle *)malloc(spriteFont.numChars*sizeof(Rectangle));
spriteFont.charOffsets = (Vector2 *)malloc(spriteFont.numChars*sizeof(Vector2));
spriteFont.charAdvanceX = (int *)malloc(spriteFont.numChars*sizeof(int));
int currentLine = 0;
int currentPosX = charsDivisor;
int testPosX = charsDivisor;
for (int i = 0; i < spriteFont.numChars; i++)
{
spriteFont.charValues[i] = (int)rbmfHeader.firstChar + i;
spriteFont.charRecs[i].x = currentPosX;
spriteFont.charRecs[i].y = charsDivisor + currentLine*((int)rbmfHeader.charHeight + charsDivisor);
spriteFont.charRecs[i].width = (int)rbmfCharWidthData[i];
spriteFont.charRecs[i].height = (int)rbmfHeader.charHeight;
// NOTE: On image based fonts (XNA style), character offsets and xAdvance are not required (set to 0)
spriteFont.charOffsets[i] = (Vector2){ 0.0f, 0.0f };
spriteFont.charAdvanceX[i] = 0;
testPosX += (spriteFont.charRecs[i].width + charsDivisor);
if (testPosX > spriteFont.texture.width)
{
currentLine++;
currentPosX = 2*charsDivisor + (int)rbmfCharWidthData[i];
testPosX = currentPosX;
spriteFont.charRecs[i].x = charsDivisor;
spriteFont.charRecs[i].y = charsDivisor + currentLine*(rbmfHeader.charHeight + charsDivisor);
}
else currentPosX = testPosX;
}
spriteFont.size = spriteFont.charRecs[0].height;
TraceLog(INFO, "[%s] rBMF file loaded correctly as SpriteFont", fileName);
}
fclose(rbmfFile);
free(rbmfFileData); // Now we can free loaded data from RAM memory
free(rbmfCharWidthData);
return spriteFont;
}
// Load a BMFont file (AngelCode font file)
static SpriteFont LoadBMFont(const char *fileName)
{
#define MAX_BUFFER_SIZE 256
SpriteFont font = { 0 };
font.texture.id = 0;
char buffer[MAX_BUFFER_SIZE];
char *searchPoint = NULL;
int fontSize = 0;
int texWidth, texHeight;
char texFileName[128];
int numChars = 0;
int base; // Useless data
FILE *fntFile;
fntFile = fopen(fileName, "rt");
if (fntFile == NULL)
{
TraceLog(WARNING, "[%s] FNT file could not be opened", fileName);
return font;
}
// NOTE: We skip first line, it contains no useful information
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
//searchPoint = strstr(buffer, "size");
//sscanf(searchPoint, "size=%i", &fontSize);
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
searchPoint = strstr(buffer, "lineHeight");
sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &texWidth, &texHeight);
TraceLog(DEBUG, "[%s] Font size: %i", fileName, fontSize);
TraceLog(DEBUG, "[%s] Font texture scale: %ix%i", fileName, texWidth, texHeight);
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
searchPoint = strstr(buffer, "file");
sscanf(searchPoint, "file=\"%128[^\"]\"", texFileName);
TraceLog(DEBUG, "[%s] Font texture filename: %s", fileName, texFileName);
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
searchPoint = strstr(buffer, "count");
sscanf(searchPoint, "count=%i", &numChars);
TraceLog(DEBUG, "[%s] Font num chars: %i", fileName, numChars);
// Compose correct path using route of .fnt file (fileName) and texFileName
char *texPath = NULL;
char *lastSlash = NULL;
lastSlash = strrchr(fileName, '/');
// NOTE: We need some extra space to avoid memory corruption on next allocations!
texPath = malloc(strlen(fileName) - strlen(lastSlash) + strlen(texFileName) + 4);
// NOTE: strcat() and strncat() required a '\0' terminated string to work!
*texPath = '\0';
strncat(texPath, fileName, strlen(fileName) - strlen(lastSlash) + 1);
strncat(texPath, texFileName, strlen(texFileName));
TraceLog(DEBUG, "[%s] Font texture loading path: %s", fileName, texPath);
Image imFont = LoadImage(texPath);
if (imFont.format == UNCOMPRESSED_GRAYSCALE)
{
Image imCopy = ImageCopy(imFont);
for (int i = 0; i < imCopy.width*imCopy.height; i++) ((unsigned char *)imCopy.data)[i] = 0xff; // WHITE pixel
ImageAlphaMask(&imCopy, imFont);
font.texture = LoadTextureFromImage(imCopy);
UnloadImage(imCopy);
}
else font.texture = LoadTextureFromImage(imFont);
font.size = fontSize;
font.numChars = numChars;
font.charValues = (int *)malloc(numChars*sizeof(int));
font.charRecs = (Rectangle *)malloc(numChars*sizeof(Rectangle));
font.charOffsets = (Vector2 *)malloc(numChars*sizeof(Vector2));
font.charAdvanceX = (int *)malloc(numChars*sizeof(int));
UnloadImage(imFont);
free(texPath);
int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX;
for (int i = 0; i < numChars; i++)
{
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
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);
// Save data properly in sprite font
font.charValues[i] = charId;
font.charRecs[i] = (Rectangle){ charX, charY, charWidth, charHeight };
font.charOffsets[i] = (Vector2){ (float)charOffsetX, (float)charOffsetY };
font.charAdvanceX[i] = charAdvanceX;
}
fclose(fntFile);
if (font.texture.id == 0)
{
UnloadSpriteFont(font);
font = GetDefaultFont();
}
else TraceLog(INFO, "[%s] SpriteFont loaded successfully", fileName);
return font;
}
// Generate a sprite font from TTF file data (font size required)
// TODO: Review texture packing method and generation (use oversampling)
static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int *fontChars)
{
// NOTE: Font texture size is predicted (being as much conservative as possible)
// Predictive method consist of supposing same number of chars by line-column (sqrtf)
// and a maximum character width of 3/4 of fontSize... it worked ok with all my tests...
// Calculate next power-of-two value
float guessSize = ceilf((float)fontSize*3/4)*ceilf(sqrtf((float)numChars));
int textureSize = (int)powf(2, ceilf(logf((float)guessSize)/logf(2))); // Calculate next POT
TraceLog(INFO, "TTF spritefont loading: Predicted texture size: %ix%i", textureSize, textureSize);
unsigned char *ttfBuffer = (unsigned char *)malloc(1 << 25);
unsigned char *dataBitmap = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)); // One channel bitmap returned!
stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*numChars);
SpriteFont font = { 0 };
FILE *ttfFile = fopen(fileName, "rb");
if (ttfFile == NULL)
{
TraceLog(WARNING, "[%s] TTF file could not be opened", fileName);
return font;
}
fread(ttfBuffer, 1, 1 << 25, ttfFile);
if (fontChars[0] != 32) TraceLog(WARNING, "TTF spritefont loading: first character is not SPACE(32) character");
// NOTE: Using stb_truetype crappy packing method, no guarante the font fits the image...
// TODO: Replace this function by a proper packing method and support random chars order,
// we already receive a list (fontChars) with the ordered expected characters
int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, fontChars[0], numChars, charData);
//if (result > 0) TraceLog(INFO, "TTF spritefont loading: first unused row of generated bitmap: %i", result);
if (result < 0) TraceLog(WARNING, "TTF spritefont loading: Not all the characters fit in the font");
free(ttfBuffer);
// Convert image data from grayscale to to UNCOMPRESSED_GRAY_ALPHA
unsigned char *dataGrayAlpha = (unsigned char *)malloc(textureSize*textureSize*sizeof(unsigned char)*2); // Two channels
for (int i = 0, k = 0; i < textureSize*textureSize; i++, k += 2)
{
dataGrayAlpha[k] = 255;
dataGrayAlpha[k + 1] = dataBitmap[i];
}
free(dataBitmap);
// Sprite font generation from TTF extracted data
Image image;
image.width = textureSize;
image.height = textureSize;
image.mipmaps = 1;
image.format = UNCOMPRESSED_GRAY_ALPHA;
image.data = dataGrayAlpha;
font.texture = LoadTextureFromImage(image);
//SavePNG("generated_ttf_image.png", (unsigned char *)image.data, image.width, image.height, 2);
UnloadImage(image); // Unloads dataGrayAlpha
font.size = fontSize;
font.numChars = numChars;
font.charValues = (int *)malloc(font.numChars*sizeof(int));
font.charRecs = (Rectangle *)malloc(font.numChars*sizeof(Rectangle));
font.charOffsets = (Vector2 *)malloc(font.numChars*sizeof(Vector2));
font.charAdvanceX = (int *)malloc(font.numChars*sizeof(int));
for (int i = 0; i < font.numChars; i++)
{
font.charValues[i] = fontChars[i];
font.charRecs[i].x = (int)charData[i].x0;
font.charRecs[i].y = (int)charData[i].y0;
font.charRecs[i].width = (int)charData[i].x1 - (int)charData[i].x0;
font.charRecs[i].height = (int)charData[i].y1 - (int)charData[i].y0;
font.charOffsets[i] = (Vector2){ charData[i].xoff, charData[i].yoff };
font.charAdvanceX[i] = (int)charData[i].xadvance;
}
free(charData);
return font;
}

2151
raylib/textures.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -193,16 +193,6 @@ func LoadImageRaw(fileName string, width int32, height int32, format TextureForm
return v
}
// Load an image from rRES file (raylib Resource)
func LoadImageFromRES(rresName string, resId int32) *Image {
crresName := C.CString(rresName)
defer C.free(unsafe.Pointer(crresName))
cresId := (C.int)(resId)
ret := C.LoadImageFromRES(crresName, cresId)
v := NewImageFromPointer(unsafe.Pointer(&ret))
return v
}
// Load an image as texture into GPU memory
func LoadTexture(fileName string) Texture2D {
cfileName := C.CString(fileName)
@ -212,27 +202,6 @@ func LoadTexture(fileName string) Texture2D {
return v
}
// Load a texture from raw data into GPU memory
func LoadTextureEx(data unsafe.Pointer, width int32, height int32, textureFormat TextureFormat) Texture2D {
cdata := (unsafe.Pointer)(unsafe.Pointer(data))
cwidth := (C.int)(width)
cheight := (C.int)(height)
ctextureFormat := (C.int)(textureFormat)
ret := C.LoadTextureEx(cdata, cwidth, cheight, ctextureFormat)
v := NewTexture2DFromPointer(unsafe.Pointer(&ret))
return v
}
// Load an image as texture from rRES file (raylib Resource)
func LoadTextureFromRES(rresName string, resId int32) Texture2D {
crresName := C.CString(rresName)
defer C.free(unsafe.Pointer(crresName))
cresId := (C.int)(resId)
ret := C.LoadTextureFromRES(crresName, cresId)
v := NewTexture2DFromPointer(unsafe.Pointer(&ret))
return v
}
// Load a texture from image data
func LoadTextureFromImage(image *Image) Texture2D {
cimage := image.cptr()

202
raylib/utils.c Normal file
View file

@ -0,0 +1,202 @@
/**********************************************************************************************
*
* raylib.utils
*
* Some utility functions
*
* External libs:
* tinfl - zlib DEFLATE algorithm decompression
* stb_image_write - PNG writting functions
*
* Module Configuration Flags:
* DO_NOT_TRACE_DEBUG_MSGS - Avoid showing DEBUG TraceLog() messages
*
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* 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.
*
**********************************************************************************************/
#include "utils.h"
#if defined(PLATFORM_ANDROID)
#include <errno.h>
#include <android/log.h>
#include <android/asset_manager.h>
#endif
#include <stdlib.h> // Required for: malloc(), free()
#include <stdio.h> // Required for: fopen(), fclose(), fputc(), fwrite(), printf(), fprintf(), funopen()
#include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end()
#include <string.h> // Required for: strlen(), strrchr(), strcmp()
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "external/stb_image_write.h" // Required for: stbi_write_bmp(), stbi_write_png()
#endif
#define RRES_IMPLEMENTATION
#include "rres.h"
//#define NO_TRACELOG // Avoid TraceLog() output (any type)
#define DO_NOT_TRACE_DEBUG_MSGS // Avoid DEBUG messages tracing
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
#if defined(PLATFORM_ANDROID)
AAssetManager *assetManager;
#endif
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
#if defined(PLATFORM_ANDROID)
static int android_read(void *cookie, char *buf, int size);
static int android_write(void *cookie, const char *buf, int size);
static fpos_t android_seek(void *cookie, fpos_t offset, int whence);
static int android_close(void *cookie);
#endif
//----------------------------------------------------------------------------------
// Module Functions Definition - Utilities
//----------------------------------------------------------------------------------
// Outputs a trace log message
void TraceLog(int msgType, const char *text, ...)
{
#if !defined(NO_TRACELOG)
static char buffer[128];
int traceDebugMsgs = 1;
#ifdef DO_NOT_TRACE_DEBUG_MSGS
traceDebugMsgs = 0;
#endif
switch(msgType)
{
case INFO: strcpy(buffer, "INFO: "); break;
case ERROR: strcpy(buffer, "ERROR: "); break;
case WARNING: strcpy(buffer, "WARNING: "); break;
case DEBUG: strcpy(buffer, "DEBUG: "); break;
default: break;
}
strcat(buffer, text);
strcat(buffer, "\n");
va_list args;
va_start(args, text);
#if defined(PLATFORM_ANDROID)
switch(msgType)
{
case INFO: __android_log_vprint(ANDROID_LOG_INFO, "raylib", buffer, args); break;
case ERROR: __android_log_vprint(ANDROID_LOG_ERROR, "raylib", buffer, args); break;
case WARNING: __android_log_vprint(ANDROID_LOG_WARN, "raylib", buffer, args); break;
case DEBUG: if (traceDebugMsgs) __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", buffer, args); break;
default: break;
}
#else
if ((msgType != DEBUG) || ((msgType == DEBUG) && (traceDebugMsgs))) vprintf(buffer, args);
#endif
va_end(args);
if (msgType == ERROR) exit(1); // If ERROR message, exit program
#endif // NO_TRACELOG
}
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
// Creates a BMP image file from an array of pixel data
void SaveBMP(const char *fileName, unsigned char *imgData, int width, int height, int compSize)
{
stbi_write_bmp(fileName, width, height, compSize, imgData);
}
// Creates a PNG image file from an array of pixel data
void SavePNG(const char *fileName, unsigned char *imgData, int width, int height, int compSize)
{
stbi_write_png(fileName, width, height, compSize, imgData, width*compSize);
}
#endif
#if defined(PLATFORM_ANDROID)
// Initialize asset manager from android app
void InitAssetManager(AAssetManager *manager)
{
assetManager = manager;
}
// Replacement for fopen
FILE *android_fopen(const char *fileName, const char *mode)
{
if (mode[0] == 'w') return NULL;
AAsset *asset = AAssetManager_open(assetManager, fileName, 0);
if (!asset) return NULL;
return funopen(asset, android_read, android_write, android_seek, android_close);
}
#endif
// Keep track of memory allocated
// NOTE: mallocType defines the type of data allocated
/*
void RecordMalloc(int mallocType, int mallocSize, const char *msg)
{
// TODO: Investigate how to record memory allocation data...
// Maybe creating my own malloc function...
}
*/
// Get the extension for a filename
const char *GetExtension(const char *fileName)
{
const char *dot = strrchr(fileName, '.');
if (!dot || dot == fileName) return "";
return (dot + 1);
}
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
#if defined(PLATFORM_ANDROID)
static int android_read(void *cookie, char *buf, int size)
{
return AAsset_read((AAsset *)cookie, buf, size);
}
static int android_write(void *cookie, const char *buf, int size)
{
TraceLog(ERROR, "Can't provide write access to the APK");
return EACCES;
}
static fpos_t android_seek(void *cookie, fpos_t offset, int whence)
{
return AAsset_seek((AAsset *)cookie, offset, whence);
}
static int android_close(void *cookie)
{
AAsset_close((AAsset *)cookie);
return 0;
}
#endif

77
raylib/utils.h Normal file
View file

@ -0,0 +1,77 @@
/**********************************************************************************************
*
* raylib.utils
*
* Some utility functions
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
* will the authors be held liable for any damages arising from the use of this software.
*
* 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 UTILS_H
#define UTILS_H
#if defined(PLATFORM_ANDROID)
#include <stdio.h> // Required for: FILE
#include <android/asset_manager.h> // Required for: AAssetManager
#endif
#include "rres.h"
//----------------------------------------------------------------------------------
// Some basic Defines
//----------------------------------------------------------------------------------
#if defined(PLATFORM_ANDROID)
#define fopen(name, mode) android_fopen(name, mode)
#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
// Nop...
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
void TraceLog(int msgType, const char *text, ...); // Outputs a trace log message
const char *GetExtension(const char *fileName); // Returns extension of a filename
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
void SaveBMP(const char *fileName, unsigned char *imgData, int width, int height, int compSize);
void SavePNG(const char *fileName, unsigned char *imgData, int width, int height, int compSize);
#endif
#if defined(PLATFORM_ANDROID)
void InitAssetManager(AAssetManager *manager); // Initialize asset manager from android app
FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen()
#endif
#ifdef __cplusplus
}
#endif
#endif // UTILS_H