summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorvictorfisac <[email protected]>2017-03-06 09:40:04 +0100
committervictorfisac <[email protected]>2017-03-06 09:40:04 +0100
commit9261c3b8dc03d093bff5246a18ad9310ae8eaeb3 (patch)
treeaf87165723ac563ee1a7e1c605c7a4df821d74ea /src
parente8630c78d069a1cba50b1a78108663ebc19e5b9b (diff)
parentb734802743f2089c8d649b27aea48ab71fa653b3 (diff)
downloadraylib-9261c3b8dc03d093bff5246a18ad9310ae8eaeb3.tar.gz
raylib-9261c3b8dc03d093bff5246a18ad9310ae8eaeb3.zip
Merge remote-tracking branch 'refs/remotes/raysan5/develop' into develop
Diffstat (limited to 'src')
-rw-r--r--src/Makefile119
-rw-r--r--src/audio.c710
-rw-r--r--src/audio.h19
-rw-r--r--src/camera.h84
-rw-r--r--src/core.c516
-rw-r--r--src/external/dr_flac.h323
-rw-r--r--src/external/jar_mod.h3
-rw-r--r--src/external/stb_image.h905
-rw-r--r--src/external/stb_image_resize.h8
-rw-r--r--src/external/stb_image_write.h5
-rw-r--r--src/external/stb_rect_pack.h29
-rw-r--r--src/external/stb_truetype.h857
-rw-r--r--src/gestures.h51
-rw-r--r--src/models.c341
-rw-r--r--src/physac.h24
-rw-r--r--src/raylib.h267
-rw-r--r--src/raymath.h68
-rw-r--r--src/rlgl.c941
-rw-r--r--src/rlgl.h28
-rw-r--r--src/rlua.h4318
-rw-r--r--src/rres.h439
-rw-r--r--src/shader_standard.h173
-rw-r--r--src/shapes.c85
-rw-r--r--src/text.c350
-rw-r--r--src/textures.c782
-rw-r--r--src/utils.c208
-rw-r--r--src/utils.h24
27 files changed, 4499 insertions, 7178 deletions
diff --git a/src/Makefile b/src/Makefile
index 2e263189..4c2278f5 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -32,7 +32,7 @@
.PHONY: all clean install unistall
# define raylib platform to compile for
-# possible platforms: PLATFORM_DESKTOP PLATFORM_RPI PLATFORM_WEB
+# possible platforms: PLATFORM_DESKTOP PLATFORM_ANDROID PLATFORM_RPI PLATFORM_WEB
PLATFORM ?= PLATFORM_DESKTOP
# define YES if you want shared/dynamic version of library instead of static (default)
@@ -69,7 +69,28 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
endif
endif
+ifeq ($(PLATFORM),PLATFORM_ANDROID)
+ # path to Android NDK
+ ANDROID_NDK = $(ANDROID_NDK_HOME)
+
+ # possible Android architectures: ARM ARM64
+ ANDROID_ARCH ?= ARM
+
+ # define YES to use clang instead of gcc
+ ANDROID_LLVM ?= NO
+
+ # standalone Android toolchain install dir
+ ANDROID_TOOLCHAIN = $(CURDIR)/toolchain
+endif
+
+ifeq ($(PLATFORM),PLATFORM_RPI)
+ CROSS_COMPILE ?= NO
+endif
+
# define raylib graphics api depending on selected platform
+ifeq ($(PLATFORM),PLATFORM_ANDROID)
+ GRAPHICS = GRAPHICS_API_OPENGL_ES2
+endif
ifeq ($(PLATFORM),PLATFORM_RPI)
# define raylib graphics api to use (on RPI, OpenGL ES 2.0 must be used)
GRAPHICS = GRAPHICS_API_OPENGL_ES2
@@ -86,12 +107,48 @@ endif
# NOTE: makefiles targets require tab indentation
# define compiler: gcc for C program, define as g++ for C++
+
+# default gcc compiler
+CC = gcc
+
+ifeq ($(PLATFORM),PLATFORM_ANDROID)
+ ifeq ($(ANDROID_ARCH),ARM)
+ ifeq ($(ANDROID_LLVM),YES)
+ CC = $(ANDROID_TOOLCHAIN)/bin/arm-linux-androideabi-clang
+ else
+ CC = $(ANDROID_TOOLCHAIN)/bin/arm-linux-androideabi-gcc
+ endif
+ endif
+ ifeq ($(ANDROID_ARCH),ARM64)
+ ifeq ($(ANDROID_LLVM),YES)
+ CC = $(ANDROID_TOOLCHAIN)/bin/aarch64-linux-android-clang
+ else
+ CC = $(ANDROID_TOOLCHAIN)/bin/aarch64-linux-android-gcc
+ endif
+ endif
+endif
+
+ifeq ($(PLATFORM),PLATFORM_RPI)
+ ifeq ($(CROSS_COMPILE),YES)
+ # rpi compiler
+ CC = armv6j-hardfloat-linux-gnueabi-gcc
+ endif
+endif
+
ifeq ($(PLATFORM),PLATFORM_WEB)
# emscripten compiler
CC = emcc
-else
- # default gcc compiler
- CC = gcc
+endif
+
+AR = ar
+
+ifeq ($(PLATFORM),PLATFORM_ANDROID)
+ ifeq ($(ANDROID_ARCH),ARM)
+ AR = $(ANDROID_TOOLCHAIN)/bin/arm-linux-androideabi-ar
+ endif
+ ifeq ($(ANDROID_ARCH),ARM64)
+ AR = $(ANDROID_TOOLCHAIN)/bin/aarch64-linux-android-ar
+ endif
endif
# define compiler flags:
@@ -124,10 +181,14 @@ endif
#CFLAGSEXTRA = -Wextra -Wmissing-prototypes -Wstrict-prototypes
# define any directories containing required header files
-ifeq ($(PLATFORM),PLATFORM_RPI)
- INCLUDES = -I. -Iexternal -I/opt/vc/include \
- -I/opt/vc/include/interface/vmcs_host/linux \
- -I/opt/vc/include/interface/vcos/pthreads
+ifeq ($(PLATFORM),PLATFORM_ANDROID)
+# STB libraries and others
+ INCLUDES = -I. -Iexternal
+# OpenAL Soft library
+ INCLUDES += -Iexternal/openal_soft/include
+# Android includes
+ INCLUDES += -I$(ANDROID_TOOLCHAIN)/sysroot/usr/include
+ INCLUDES += -I$(ANDROID_NDK)/sources/android/native_app_glue
else
# STB libraries and others
INCLUDES = -I. -Iexternal
@@ -136,6 +197,16 @@ else
# OpenAL Soft library
INCLUDES += -Iexternal/openal_soft/include
endif
+ifeq ($(PLATFORM),PLATFORM_RPI)
+# STB libraries and others
+ INCLUDES = -I. -Iexternal
+# RPi libraries
+ INCLUDES += -I/opt/vc/include
+ INCLUDES += -I/opt/vc/include/interface/vmcs_host/linux
+ INCLUDES += -I/opt/vc/include/interface/vcos/pthreads
+# OpenAL Soft library
+ INCLUDES += -Iexternal/openal_soft/include
+endif
# define output directory for compiled library
ifeq ($(PLATFORM),PLATFORM_DESKTOP)
@@ -149,6 +220,14 @@ ifeq ($(PLATFORM),PLATFORM_DESKTOP)
OUTPUT_PATH = ../release/osx
endif
endif
+ifeq ($(PLATFORM),PLATFORM_ANDROID)
+ ifeq ($(ANDROID_ARCH),ARM)
+ OUTPUT_PATH = ../release/android/armeabi-v7a
+ endif
+ ifeq ($(ANDROID_ARCH),ARM64)
+ OUTPUT_PATH = ../release/android/arm64-v8a
+ endif
+endif
ifeq ($(PLATFORM),PLATFORM_WEB)
OUTPUT_PATH = ../release/html5
endif
@@ -164,7 +243,18 @@ OBJS += external/stb_vorbis.o
# typing 'make' will invoke the default target entry called 'all',
# in this case, the 'default' target entry is raylib
-all: raylib
+all: toolchain raylib
+
+# make standalone Android toolchain
+toolchain:
+ifeq ($(PLATFORM),PLATFORM_ANDROID)
+ ifeq ($(ANDROID_ARCH),ARM)
+ $(ANDROID_NDK)/build/tools/make-standalone-toolchain.sh --platform=android-9 --toolchain=arm-linux-androideabi-4.9 --use-llvm --install-dir=$(ANDROID_TOOLCHAIN)
+ endif
+ ifeq ($(ANDROID_ARCH),ARM64)
+ $(ANDROID_NDK)/build/tools/make-standalone-toolchain.sh --platform=android-21 --toolchain=aarch64-linux-androideabi-4.9 --use-llvm --install-dir=$(ANDROID_TOOLCHAIN)
+ endif
+endif
# compile raylib library
raylib: $(OBJS)
@@ -184,9 +274,13 @@ else
$(CC) -shared -o $(OUTPUT_PATH)/raylib.dll $(OBJS) $(SHAREDLIBS) -Wl,--out-implib,$(OUTPUT_PATH)/libraylibdll.a
@echo "raylib dynamic library (raylib.dll) and import library (libraylibdll.a) generated!"
endif
+ ifeq ($(PLATFORM),PLATFORM_ANDROID)
+ $(CC) -shared -o $(OUTPUT_PATH)/libraylib.so $(OBJS)
+ @echo "raylib shared library (libraylib.so) generated!"
+ endif
else
- # compile raylib static library for desktop platforms.
- ar rcs $(OUTPUT_PATH)/libraylib.a $(OBJS)
+ # compile raylib static library.
+ $(AR) rcs $(OUTPUT_PATH)/libraylib.a $(OBJS)
@echo "libraylib.a generated (static library)!"
ifeq ($(SHARED_OPENAL),NO)
@echo "expected OpenAL Soft static library linking"
@@ -284,4 +378,7 @@ ifeq ($(PLATFORM_OS),WINDOWS)
else
rm -f *.o $(OUTPUT_PATH)/libraylib.a $(OUTPUT_PATH)/libraylib.bc $(OUTPUT_PATH)/libraylib.so external/stb_vorbis.o
endif
+ifeq ($(PLATFORM),PLATFORM_ANDROID)
+ rm -rf $(ANDROID_TOOLCHAIN)
+endif
@echo "removed all generated files!"
diff --git a/src/audio.c b/src/audio.c
index 49aca4b0..659ead0f 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -3,28 +3,50 @@
* 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
+* 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:
+* NOTES:
+*
+* Only up to two channels supported: MONO and STEREO (for additional channels, use AL_EXT_MCFORMATS)
+* Only the following sample sizes supported: 8bit PCM, 16bit PCM, 32-bit float PCM (using AL_EXT_FLOAT32)
+*
+* CONFIGURATION:
+*
+* #define AUDIO_STANDALONE
+* If defined, the module can be used as standalone library (independently of raylib).
+* Required types and functions are defined in the same module.
+*
+* #define SUPPORT_FILEFORMAT_WAV / SUPPORT_LOAD_WAV / ENABLE_LOAD_WAV
+* #define SUPPORT_FILEFORMAT_OGG
+* #define SUPPORT_FILEFORMAT_XM
+* #define SUPPORT_FILEFORMAT_MOD
+* #define SUPPORT_FILEFORMAT_FLAC
+* Selected desired fileformats to be supported for loading. Some of those formats are
+* supported by default, to remove support, just comment unrequired #define in this module
+*
+* #define SUPPORT_RAW_AUDIO_BUFFERS
+*
+* DEPENDENCIES:
* 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
*
-* Module Configuration Flags:
-* AUDIO_STANDALONE - Use this module as standalone library (independently of raylib)
+* CONTRIBUTORS:
*
* 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
+* XM audio module support (jar_xm)
+* MOD audio module support (jar_mod)
+* Mixing channels support
+* Raw audio context support
+*
*
+* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
@@ -52,25 +74,25 @@
#include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end()
#else
#include "raylib.h"
- #include "utils.h" // Required for: DecompressData()
- // NOTE: Includes Android fopen() function map
+ #include "utils.h" // Required for: fopen() Android mapping, TraceLog()
#endif
-#include "AL/al.h" // OpenAL basic header
-#include "AL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work)
+#ifdef __APPLE__
+ #include "OpenAL/al.h" // OpenAL basic header
+ #include "OpenAL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work)
+#else
+ #include "AL/al.h" // OpenAL basic header
+ #include "AL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work)
+ //#include "AL/alext.h" // OpenAL extensions header, required for AL_EXT_FLOAT32 and AL_EXT_MCFORMATS
+#endif
+
+// OpenAL extension: AL_EXT_FLOAT32 - Support for 32bit float samples
+// OpenAL extension: AL_EXT_MCFORMATS - Support for multi-channel formats (Quad, 5.1, 6.1, 7.1)
#include <stdlib.h> // Required for: malloc(), free()
#include <string.h> // Required for: strcmp(), strncmp()
#include <stdio.h> // Required for: FILE, fopen(), fclose(), fread()
-// Tokens defined by OpenAL extension: AL_EXT_float32
-#ifndef AL_FORMAT_MONO_FLOAT32
- #define AL_FORMAT_MONO_FLOAT32 0x10010
-#endif
-#ifndef AL_FORMAT_STEREO_FLOAT32
- #define AL_FORMAT_STEREO_FLOAT32 0x10011
-#endif
-
//#define STB_VORBIS_HEADER_ONLY
#include "external/stb_vorbis.h" // OGG loading functions
@@ -93,11 +115,20 @@
//----------------------------------------------------------------------------------
#define MAX_STREAM_BUFFERS 2 // Number of buffers for each audio stream
-// NOTE: Music buffer size is defined by number of samples, independent of sample size
+// NOTE: Music buffer size is defined by number of samples, independent of sample size and channels number
// After some math, considering a sampleRate of 48000, a buffer refill rate of 1/60 seconds
// and double-buffering system, I concluded that a 4096 samples buffer should be enough
// In case of music-stalls, just increase this number
-#define AUDIO_BUFFER_SIZE 4096 // PCM data samples (i.e. short: 32Kb)
+#define AUDIO_BUFFER_SIZE 4096 // PCM data samples (i.e. 16bit, Mono: 8Kb)
+
+// Support uncompressed PCM data in 32-bit float IEEE format
+// NOTE: This definition is included in "AL/alext.h", but some OpenAL implementations
+// could not provide the extensions header (Android), so its defined here
+#if !defined(AL_EXT_float32)
+ #define AL_EXT_float32 1
+ #define AL_FORMAT_MONO_FLOAT32 0x10010
+ #define AL_FORMAT_STEREO_FLOAT32 0x10011
+#endif
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -115,7 +146,7 @@ typedef struct MusicData {
AudioStream stream; // Audio stream (double buffering)
- bool loop; // Repeat music after finish (loop)
+ int loopCount; // Loops count (times music repeats), -1 means infinite loop
unsigned int totalSamples; // Total number of samples
unsigned int samplesLeft; // Number of samples left to end
} MusicData;
@@ -169,9 +200,11 @@ void InitAudioDevice(void)
TraceLog(INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER));
// Listener definition (just for 2D)
- alListener3f(AL_POSITION, 0, 0, 0);
- alListener3f(AL_VELOCITY, 0, 0, 0);
- alListener3f(AL_ORIENTATION, 0, 0, -1);
+ alListener3f(AL_POSITION, 0.0f, 0.0f, 0.0f);
+ alListener3f(AL_VELOCITY, 0.0f, 0.0f, 0.0f);
+ alListener3f(AL_ORIENTATION, 0.0f, 0.0f, -1.0f);
+
+ alListenerf(AL_GAIN, 1.0f);
}
}
}
@@ -208,11 +241,20 @@ bool IsAudioDeviceReady(void)
}
}
+// Set master volume (listener)
+void SetMasterVolume(float volume)
+{
+ if (volume < 0.0f) volume = 0.0f;
+ else if (volume > 1.0f) volume = 1.0f;
+
+ alListenerf(AL_GAIN, volume);
+}
+
//----------------------------------------------------------------------------------
// Module Functions Definition - Sounds loading and playing (.WAV)
//----------------------------------------------------------------------------------
-// Load wave data from file into RAM
+// Load wave data from file
Wave LoadWave(const char *fileName)
{
Wave wave = { 0 };
@@ -220,39 +262,49 @@ Wave LoadWave(const char *fileName)
if (strcmp(GetExtension(fileName), "wav") == 0) wave = LoadWAV(fileName);
else if (strcmp(GetExtension(fileName), "ogg") == 0) wave = LoadOGG(fileName);
else if (strcmp(GetExtension(fileName), "flac") == 0) wave = LoadFLAC(fileName);
+ else if (strcmp(GetExtension(fileName),"rres") == 0)
+ {
+ RRES rres = LoadResource(fileName, 0);
+
+ // NOTE: Parameters for RRES_TYPE_WAVE are: sampleCount, sampleRate, sampleSize, channels
+
+ if (rres[0].type == RRES_TYPE_WAVE) wave = LoadWaveEx(rres[0].data, rres[0].param1, rres[0].param2, rres[0].param3, rres[0].param4);
+ else TraceLog(WARNING, "[%s] Resource file does not contain wave data", fileName);
+
+ UnloadResource(rres);
+ }
else TraceLog(WARNING, "[%s] File extension not recognized, it can't be loaded", fileName);
return wave;
}
-// Load wave data from float array data (32bit)
-Wave LoadWaveEx(float *data, int sampleCount, int sampleRate, int sampleSize, int channels)
+// Load wave data from raw array data
+Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels)
{
Wave wave;
-
+
wave.data = data;
wave.sampleCount = sampleCount;
wave.sampleRate = sampleRate;
- wave.sampleSize = 32;
+ wave.sampleSize = sampleSize;
wave.channels = channels;
-
- // NOTE: Copy wave data to work with,
- // user is responsible of input data to free
+
+ // NOTE: Copy wave data to work with, user is responsible of input data to free
Wave cwave = WaveCopy(wave);
-
+
WaveFormat(&cwave, sampleRate, sampleSize, channels);
-
+
return cwave;
}
-// Load sound to memory
+// Load sound from file
// NOTE: The entire file is loaded to memory to be played (no-streaming)
Sound LoadSound(const char *fileName)
{
Wave wave = LoadWave(fileName);
-
+
Sound sound = LoadSoundFromWave(wave);
-
+
UnloadWave(wave); // Sound is loaded, we can unload wave
return sound;
@@ -275,7 +327,7 @@ Sound LoadSoundFromWave(Wave wave)
{
case 8: format = AL_FORMAT_MONO8; break;
case 16: format = AL_FORMAT_MONO16; break;
- case 32: format = AL_FORMAT_MONO_FLOAT32; break;
+ case 32: format = AL_FORMAT_MONO_FLOAT32; break; // Requires OpenAL extension: AL_EXT_FLOAT32
default: TraceLog(WARNING, "Wave sample size not supported: %i", wave.sampleSize); break;
}
}
@@ -285,7 +337,7 @@ Sound LoadSoundFromWave(Wave wave)
{
case 8: format = AL_FORMAT_STEREO8; break;
case 16: format = AL_FORMAT_STEREO16; break;
- case 32: format = AL_FORMAT_STEREO_FLOAT32; break;
+ case 32: format = AL_FORMAT_STEREO_FLOAT32; break; // Requires OpenAL extension: AL_EXT_FLOAT32
default: TraceLog(WARNING, "Wave sample size not supported: %i", wave.sampleSize); break;
}
}
@@ -295,10 +347,10 @@ Sound LoadSoundFromWave(Wave wave)
ALuint source;
alGenSources(1, &source); // Generate pointer to audio source
- alSourcef(source, AL_PITCH, 1);
- alSourcef(source, AL_GAIN, 1);
- alSource3f(source, AL_POSITION, 0, 0, 0);
- alSource3f(source, AL_VELOCITY, 0, 0, 0);
+ alSourcef(source, AL_PITCH, 1.0f);
+ alSourcef(source, AL_GAIN, 1.0f);
+ alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f);
+ alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alSourcei(source, AL_LOOPING, AL_FALSE);
// Convert loaded data to OpenAL buffer
@@ -306,7 +358,7 @@ Sound LoadSoundFromWave(Wave wave)
ALuint buffer;
alGenBuffers(1, &buffer); // Generate pointer to buffer
- unsigned int dataSize = wave.sampleCount*wave.sampleSize/8; // Size in bytes
+ unsigned int dataSize = wave.sampleCount*wave.channels*wave.sampleSize/8; // Size in bytes
// Upload sound data to buffer
alBufferData(buffer, format, wave.data, dataSize, wave.sampleRate);
@@ -314,7 +366,7 @@ Sound LoadSoundFromWave(Wave wave)
// Attach sound buffer to source
alSourcei(source, AL_BUFFER, buffer);
- TraceLog(INFO, "[SND ID %i][BUFR ID %i] Sound data loaded successfully (SampleRate: %i, SampleSize: %i, Channels: %i)", source, buffer, wave.sampleRate, wave.sampleSize, wave.channels);
+ TraceLog(INFO, "[SND ID %i][BUFR ID %i] Sound data loaded successfully (%i Hz, %i bit, %s)", source, buffer, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo");
sound.source = source;
sound.buffer = buffer;
@@ -324,121 +376,10 @@ Sound LoadSoundFromWave(Wave wave)
return sound;
}
-// Load sound to memory from rRES file (raylib Resource)
-// TODO: Maybe rresName could be directly a char array with all the data?
-Sound LoadSoundFromRES(const char *rresName, int resId)
-{
- Sound sound = { 0 };
-
-#if defined(AUDIO_STANDALONE)
- TraceLog(WARNING, "Sound loading from rRES resource file not supported on standalone mode");
-#else
-
- bool found = false;
-
- char id[4]; // rRES file identifier
- unsigned char version; // rRES file version and subversion
- char useless; // rRES header reserved data
- short numRes;
-
- ResInfoHeader infoHeader;
-
- FILE *rresFile = fopen(rresName, "rb");
-
- if (rresFile == NULL) TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName);
- else
- {
- // Read rres file (basic file check - id)
- fread(&id[0], sizeof(char), 1, rresFile);
- fread(&id[1], sizeof(char), 1, rresFile);
- fread(&id[2], sizeof(char), 1, rresFile);
- fread(&id[3], sizeof(char), 1, rresFile);
- fread(&version, sizeof(char), 1, rresFile);
- fread(&useless, sizeof(char), 1, rresFile);
-
- if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S'))
- {
- TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName);
- }
- else
- {
- // Read number of resources embedded
- fread(&numRes, sizeof(short), 1, rresFile);
-
- for (int i = 0; i < numRes; i++)
- {
- fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile);
-
- if (infoHeader.id == resId)
- {
- found = true;
-
- // Check data is of valid SOUND type
- if (infoHeader.type == 1) // SOUND data type
- {
- // TODO: Check data compression type
- // NOTE: We suppose compression type 2 (DEFLATE - default)
-
- // Reading SOUND parameters
- Wave wave;
- short sampleRate, bps;
- char channels, reserved;
-
- fread(&sampleRate, sizeof(short), 1, rresFile); // Sample rate (frequency)
- fread(&bps, sizeof(short), 1, rresFile); // Bits per sample
- fread(&channels, 1, 1, rresFile); // Channels (1 - mono, 2 - stereo)
- fread(&reserved, 1, 1, rresFile); // <reserved>
-
- wave.sampleRate = sampleRate;
- wave.sampleSize = bps;
- wave.channels = (short)channels;
-
- unsigned char *data = malloc(infoHeader.size);
-
- fread(data, infoHeader.size, 1, rresFile);
-
- wave.data = DecompressData(data, infoHeader.size, infoHeader.srcSize);
-
- free(data);
-
- sound = LoadSoundFromWave(wave);
-
- // Sound is loaded, we can unload wave data
- UnloadWave(wave);
- }
- else TraceLog(WARNING, "[%s] Required resource do not seem to be a valid SOUND resource", rresName);
- }
- else
- {
- // Depending on type, skip the right amount of parameters
- switch (infoHeader.type)
- {
- case 0: fseek(rresFile, 6, SEEK_CUR); break; // IMAGE: Jump 6 bytes of parameters
- case 1: fseek(rresFile, 6, SEEK_CUR); break; // SOUND: Jump 6 bytes of parameters
- case 2: fseek(rresFile, 5, SEEK_CUR); break; // MODEL: Jump 5 bytes of parameters (TODO: Review)
- case 3: break; // TEXT: No parameters
- case 4: break; // RAW: No parameters
- default: break;
- }
-
- // Jump DATA to read next infoHeader
- fseek(rresFile, infoHeader.size, SEEK_CUR);
- }
- }
- }
-
- fclose(rresFile);
- }
-
- if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId);
-#endif
- return sound;
-}
-
-// Unload Wave data
+// Unload wave data
void UnloadWave(Wave wave)
{
- free(wave.data);
+ if (wave.data != NULL) free(wave.data);
TraceLog(INFO, "Unloaded wave data from RAM");
}
@@ -446,6 +387,8 @@ void UnloadWave(Wave wave)
// Unload sound
void UnloadSound(Sound sound)
{
+ alSourceStop(sound.source);
+
alDeleteSources(1, &sound.source);
alDeleteBuffers(1, &sound.buffer);
@@ -454,19 +397,19 @@ void UnloadSound(Sound sound)
// Update sound buffer with new data
// NOTE: data must match sound.format
-void UpdateSound(Sound sound, void *data, int numSamples)
+void UpdateSound(Sound sound, const void *data, int samplesCount)
{
ALint sampleRate, sampleSize, channels;
alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate);
- alGetBufferi(sound.buffer, AL_BITS, &sampleSize); // It could also be retrieved from sound.format
- alGetBufferi(sound.buffer, AL_CHANNELS, &channels); // It could also be retrieved from sound.format
-
+ alGetBufferi(sound.buffer, AL_BITS, &sampleSize); // It could also be retrieved from sound.format
+ alGetBufferi(sound.buffer, AL_CHANNELS, &channels); // It could also be retrieved from sound.format
+
TraceLog(DEBUG, "UpdateSound() : AL_FREQUENCY: %i", sampleRate);
TraceLog(DEBUG, "UpdateSound() : AL_BITS: %i", sampleSize);
TraceLog(DEBUG, "UpdateSound() : AL_CHANNELS: %i", channels);
- unsigned int dataSize = numSamples*sampleSize/8; // Size of data in bytes
-
+ unsigned int dataSize = samplesCount*channels*sampleSize/8; // Size of data in bytes
+
alSourceStop(sound.source); // Stop sound
alSourcei(sound.source, AL_BUFFER, 0); // Unbind buffer from sound to update
//alDeleteBuffers(1, &sound.buffer); // Delete current buffer data
@@ -547,69 +490,94 @@ void SetSoundPitch(Sound sound, float pitch)
}
// Convert wave data to desired format
-// TODO: Consider channels (mono - stereo)
void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels)
{
- if (wave->sampleSize != sampleSize)
+ // Format sample rate
+ // NOTE: Only supported 22050 <--> 44100
+ if (wave->sampleRate != sampleRate)
{
- float *samples = GetWaveData(*wave); //Color *pixels = GetImageData(*image);
+ // TODO: Resample wave data (upsampling or downsampling)
+ // NOTE 1: To downsample, you have to drop samples or average them.
+ // NOTE 2: To upsample, you have to interpolate new samples.
- free(wave->data);
-
- wave->sampleSize = sampleSize;
+ wave->sampleRate = sampleRate;
+ }
- //sample *= 4.0f; // Arbitrary gain to get reasonable output volume...
- //if (sample > 1.0f) sample = 1.0f;
- //if (sample < -1.0f) sample = -1.0f;
+ // Format sample size
+ // NOTE: Only supported 8 bit <--> 16 bit <--> 32 bit
+ if (wave->sampleSize != sampleSize)
+ {
+ void *data = malloc(wave->sampleCount*wave->channels*sampleSize/8);
- if (sampleSize == 8)
+ for (int i = 0; i < wave->sampleCount; i++)
{
- wave->data = (unsigned char *)malloc(wave->sampleCount*sizeof(unsigned char));
-
- for (int i = 0; i < wave->sampleCount; i++)
+ for (int j = 0; j < wave->channels; j++)
{
- ((unsigned char *)wave->data)[i] = (unsigned char)((float)samples[i]*127 + 128);
+ if (sampleSize == 8)
+ {
+ if (wave->sampleSize == 16) ((unsigned char *)data)[wave->channels*i + j] = (unsigned char)(((float)(((short *)wave->data)[wave->channels*i + j])/32767.0f)*256);
+ else if (wave->sampleSize == 32) ((unsigned char *)data)[wave->channels*i + j] = (unsigned char)(((float *)wave->data)[wave->channels*i + j]*127.0f + 127);
+ }
+ else if (sampleSize == 16)
+ {
+ if (wave->sampleSize == 8) ((short *)data)[wave->channels*i + j] = (short)(((float)(((unsigned char *)wave->data)[wave->channels*i + j] - 127)/256.0f)*32767);
+ else if (wave->sampleSize == 32) ((short *)data)[wave->channels*i + j] = (short)((((float *)wave->data)[wave->channels*i + j])*32767);
+ }
+ else if (sampleSize == 32)
+ {
+ if (wave->sampleSize == 8) ((float *)data)[wave->channels*i + j] = (float)(((unsigned char *)wave->data)[wave->channels*i + j] - 127)/256.0f;
+ else if (wave->sampleSize == 16) ((float *)data)[wave->channels*i + j] = (float)(((short *)wave->data)[wave->channels*i + j])/32767.0f;
+ }
}
}
- else if (sampleSize == 16)
+
+ wave->sampleSize = sampleSize;
+ free(wave->data);
+ wave->data = data;
+ }
+
+ // Format channels (interlaced mode)
+ // NOTE: Only supported mono <--> stereo
+ if (wave->channels != channels)
+ {
+ void *data = malloc(wave->sampleCount*channels*wave->sampleSize/8);
+
+ if ((wave->channels == 1) && (channels == 2)) // mono ---> stereo (duplicate mono information)
{
- wave->data = (short *)malloc(wave->sampleCount*sizeof(short));
-
for (int i = 0; i < wave->sampleCount; i++)
{
- ((short *)wave->data)[i] = (short)((float)samples[i]*32000); // SHRT_MAX = 32767
+ for (int j = 0; j < channels; j++)
+ {
+ if (wave->sampleSize == 8) ((unsigned char *)data)[channels*i + j] = ((unsigned char *)wave->data)[i];
+ else if (wave->sampleSize == 16) ((short *)data)[channels*i + j] = ((short *)wave->data)[i];
+ else if (wave->sampleSize == 32) ((float *)data)[channels*i + j] = ((float *)wave->data)[i];
+ }
}
}
- else if (sampleSize == 32)
+ else if ((wave->channels == 2) && (channels == 1)) // stereo ---> mono (mix stereo channels)
{
- wave->data = (float *)malloc(wave->sampleCount*sizeof(float));
-
- for (int i = 0; i < wave->sampleCount; i++)
+ for (int i = 0, j = 0; i < wave->sampleCount; i++, j += 2)
{
- ((float *)wave->data)[i] = (float)samples[i];
+ if (wave->sampleSize == 8) ((unsigned char *)data)[i] = (((unsigned char *)wave->data)[j] + ((unsigned char *)wave->data)[j + 1])/2;
+ else if (wave->sampleSize == 16) ((short *)data)[i] = (((short *)wave->data)[j] + ((short *)wave->data)[j + 1])/2;
+ else if (wave->sampleSize == 32) ((float *)data)[i] = (((float *)wave->data)[j] + ((float *)wave->data)[j + 1])/2.0f;
}
}
- else TraceLog(WARNING, "Wave formatting: Sample size not supported");
-
- free(samples);
- }
-
- // NOTE: Only supported 1 or 2 channels (mono or stereo)
- if ((channels > 0) && (channels < 3) && (wave->channels != channels))
- {
- // TODO: Add/remove channels interlaced data if required...
+
+ // TODO: Add/remove additional interlaced channels
+
+ wave->channels = channels;
+ free(wave->data);
+ wave->data = data;
}
}
// Copy a wave to a new wave
Wave WaveCopy(Wave wave)
{
- Wave newWave;
+ Wave newWave = { 0 };
- if (wave.sampleSize == 8) newWave.data = (unsigned char *)malloc(wave.sampleCount*wave.channels*sizeof(unsigned char));
- else if (wave.sampleSize == 16) newWave.data = (short *)malloc(wave.sampleCount*wave.channels*sizeof(short));
- else if (wave.sampleSize == 32) newWave.data = (float *)malloc(wave.sampleCount*wave.channels*sizeof(float));
- else TraceLog(WARNING, "Wave sample size not supported for copy");
+ newWave.data = malloc(wave.sampleCount*wave.channels*wave.sampleSize/8);
if (newWave.data != NULL)
{
@@ -629,40 +597,37 @@ Wave WaveCopy(Wave wave)
// NOTE: Security check in case of out-of-range
void WaveCrop(Wave *wave, int initSample, int finalSample)
{
- if ((initSample >= 0) && (initSample < finalSample) &&
+ if ((initSample >= 0) && (initSample < finalSample) &&
(finalSample > 0) && (finalSample < wave->sampleCount))
{
- // TODO: Review cropping (it could be simplified...)
-
- float *samples = GetWaveData(*wave);
- float *cropSamples = (float *)malloc((finalSample - initSample)*sizeof(float));
-
- for (int i = initSample; i < finalSample; i++) cropSamples[i] = samples[i];
+ int sampleCount = finalSample - initSample;
- free(wave->data);
- wave->data = cropSamples;
- int sampleSize = wave->sampleSize;
- wave->sampleSize = 32;
+ void *data = malloc(sampleCount*wave->channels*wave->sampleSize/8);
- WaveFormat(wave, wave->sampleRate, sampleSize, wave->channels);
+ memcpy(data, (unsigned char*)wave->data + (initSample*wave->channels*wave->sampleSize/8), sampleCount*wave->channels*wave->sampleSize/8);
+
+ free(wave->data);
+ wave->data = data;
}
else TraceLog(WARNING, "Wave crop range out of bounds");
}
// Get samples data from wave as a floats array
// NOTE: Returned sample values are normalized to range [-1..1]
-// TODO: Consider multiple channels (mono - stereo)
float *GetWaveData(Wave wave)
{
- float *samples = (float *)malloc(wave.sampleCount*sizeof(float));
-
+ float *samples = (float *)malloc(wave.sampleCount*wave.channels*sizeof(float));
+
for (int i = 0; i < wave.sampleCount; i++)
{
- if (wave.sampleSize == 8) samples[i] = (float)(((unsigned char *)wave.data)[i] - 127)/256.0f;
- else if (wave.sampleSize == 16) samples[i] = (float)((short *)wave.data)[i]/32767.0f;
- else if (wave.sampleSize == 32) samples[i] = ((float *)wave.data)[i];
+ for (int j = 0; j < wave.channels; j++)
+ {
+ if (wave.sampleSize == 8) samples[wave.channels*i + j] = (float)(((unsigned char *)wave.data)[wave.channels*i + j] - 127)/256.0f;
+ else if (wave.sampleSize == 16) samples[wave.channels*i + j] = (float)((short *)wave.data)[wave.channels*i + j]/32767.0f;
+ else if (wave.sampleSize == 32) samples[wave.channels*i + j] = ((float *)wave.data)[wave.channels*i + j];
+ }
}
-
+
return samples;
}
@@ -684,34 +649,34 @@ Music LoadMusicStream(const char *fileName)
else
{
stb_vorbis_info info = stb_vorbis_get_info(music->ctxOgg); // Get Ogg file info
- //float totalLengthSeconds = stb_vorbis_stream_length_in_seconds(music->ctxOgg);
- // TODO: Support 32-bit sampleSize OGGs
+ // OGG bit rate defaults to 16 bit, it's enough for compressed format
music->stream = InitAudioStream(info.sample_rate, 16, info.channels);
- music->totalSamples = (unsigned int)stb_vorbis_stream_length_in_samples(music->ctxOgg)*info.channels;
+ music->totalSamples = (unsigned int)stb_vorbis_stream_length_in_samples(music->ctxOgg); // Independent by channel
music->samplesLeft = music->totalSamples;
music->ctxType = MUSIC_AUDIO_OGG;
- music->loop = true; // We loop by default
+ music->loopCount = -1; // Infinite loop by default
+ TraceLog(DEBUG, "[%s] FLAC total samples: %i", fileName, music->totalSamples);
TraceLog(DEBUG, "[%s] OGG sample rate: %i", fileName, info.sample_rate);
TraceLog(DEBUG, "[%s] OGG channels: %i", fileName, info.channels);
TraceLog(DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required);
-
}
}
else if (strcmp(GetExtension(fileName), "flac") == 0)
{
music->ctxFlac = drflac_open_file(fileName);
-
+
if (music->ctxFlac == NULL) TraceLog(WARNING, "[%s] FLAC audio file could not be opened", fileName);
else
{
music->stream = InitAudioStream(music->ctxFlac->sampleRate, music->ctxFlac->bitsPerSample, music->ctxFlac->channels);
- music->totalSamples = (unsigned int)music->ctxFlac->totalSampleCount;
+ music->totalSamples = (unsigned int)music->ctxFlac->totalSampleCount/music->ctxFlac->channels;
music->samplesLeft = music->totalSamples;
music->ctxType = MUSIC_AUDIO_FLAC;
- music->loop = true; // We loop by default
-
+ music->loopCount = -1; // Infinite loop by default
+
+ TraceLog(DEBUG, "[%s] FLAC total samples: %i", fileName, music->totalSamples);
TraceLog(DEBUG, "[%s] FLAC sample rate: %i", fileName, music->ctxFlac->sampleRate);
TraceLog(DEBUG, "[%s] FLAC bits per sample: %i", fileName, music->ctxFlac->bitsPerSample);
TraceLog(DEBUG, "[%s] FLAC channels: %i", fileName, music->ctxFlac->channels);
@@ -723,14 +688,14 @@ Music LoadMusicStream(const char *fileName)
if (!result) // XM context created successfully
{
- jar_xm_set_max_loop_count(music->ctxXm, 0); // Set infinite number of loops
+ jar_xm_set_max_loop_count(music->ctxXm, 0); // Set infinite number of loops
// NOTE: Only stereo is supported for XM
- music->stream = InitAudioStream(48000, 32, 2);
+ music->stream = InitAudioStream(48000, 16, 2);
music->totalSamples = (unsigned int)jar_xm_get_remaining_samples(music->ctxXm);
music->samplesLeft = music->totalSamples;
music->ctxType = MUSIC_MODULE_XM;
- music->loop = true;
+ music->loopCount = -1; // Infinite loop by default
TraceLog(DEBUG, "[%s] XM number of samples: %i", fileName, music->totalSamples);
TraceLog(DEBUG, "[%s] XM track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f);
@@ -747,10 +712,10 @@ Music LoadMusicStream(const char *fileName)
music->totalSamples = (unsigned int)jar_mod_max_samples(&music->ctxMod);
music->samplesLeft = music->totalSamples;
music->ctxType = MUSIC_MODULE_MOD;
- music->loop = true;
+ music->loopCount = -1; // Infinite loop by default
- TraceLog(INFO, "[%s] MOD number of samples: %i", fileName, music->samplesLeft);
- TraceLog(INFO, "[%s] MOD track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f);
+ TraceLog(DEBUG, "[%s] MOD number of samples: %i", fileName, music->samplesLeft);
+ TraceLog(DEBUG, "[%s] MOD track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f);
}
else TraceLog(WARNING, "[%s] MOD file could not be opened", fileName);
}
@@ -794,115 +759,102 @@ void ResumeMusicStream(Music music)
}
// Stop music playing (close stream)
-// TODO: Restart XM context
void StopMusicStream(Music music)
{
alSourceStop(music->stream.source);
+ // Clear stream buffers
+ void *pcm = calloc(AUDIO_BUFFER_SIZE*music->stream.sampleSize/8*music->stream.channels, 1);
+
+ for (int i = 0; i < MAX_STREAM_BUFFERS; i++)
+ {
+ alBufferData(music->stream.buffers[i], music->stream.format, pcm, AUDIO_BUFFER_SIZE*music->stream.sampleSize/8*music->stream.channels, music->stream.sampleRate);
+ }
+
+ free(pcm);
+
+ // Restart music context
switch (music->ctxType)
{
case MUSIC_AUDIO_OGG: stb_vorbis_seek_start(music->ctxOgg); break;
- case MUSIC_MODULE_XM: break;
+ case MUSIC_MODULE_XM: /* TODO: Restart XM context */ break;
case MUSIC_MODULE_MOD: jar_mod_seek_start(&music->ctxMod); break;
default: break;
}
-
+
music->samplesLeft = music->totalSamples;
}
// Update (re-fill) music buffers if data already processed
+// TODO: Make sure buffers are ready for update... check music state
void UpdateMusicStream(Music music)
{
ALenum state;
ALint processed = 0;
-
+
alGetSourcei(music->stream.source, AL_SOURCE_STATE, &state); // Get music stream state
alGetSourcei(music->stream.source, AL_BUFFERS_PROCESSED, &processed); // Get processed buffers
if (processed > 0)
{
bool active = true;
- short pcm[AUDIO_BUFFER_SIZE];
- float pcmf[AUDIO_BUFFER_SIZE];
- int numBuffersToProcess = processed;
- int numSamples = 0; // Total size of data steamed in L+R samples for xm floats,
- // individual L or R for ogg shorts
+ // NOTE: Using dynamic allocation because it could require more than 16KB
+ void *pcm = calloc(AUDIO_BUFFER_SIZE*music->stream.channels*music->stream.sampleSize/8, 1);
+
+ int numBuffersToProcess = processed;
+ int samplesCount = 0; // Total size of data steamed in L+R samples for xm floats,
+ //individual L or R for ogg shorts
for (int i = 0; i < numBuffersToProcess; i++)
{
+ if (music->samplesLeft >= AUDIO_BUFFER_SIZE) samplesCount = AUDIO_BUFFER_SIZE;
+ else samplesCount = music->samplesLeft;
+
+ // TODO: Really don't like ctxType thingy...
switch (music->ctxType)
{
case MUSIC_AUDIO_OGG:
{
- if (music->samplesLeft >= AUDIO_BUFFER_SIZE) numSamples = AUDIO_BUFFER_SIZE;
- else numSamples = music->samplesLeft;
-
- // NOTE: Returns the number of samples to process (should be the same as numSamples -> it is)
- int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, pcm, numSamples);
-
- // TODO: Review stereo channels Ogg, not enough samples served!
- UpdateAudioStream(music->stream, pcm, numSamplesOgg*music->stream.channels);
- music->samplesLeft -= (numSamplesOgg*music->stream.channels);
+ // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!)
+ int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(music->ctxOgg, music->stream.channels, (short *)pcm, samplesCount*music->stream.channels);
} break;
case MUSIC_AUDIO_FLAC:
{
- if (music->samplesLeft >= AUDIO_BUFFER_SIZE) numSamples = AUDIO_BUFFER_SIZE;
- else numSamples = music->samplesLeft;
-
- int pcmi[AUDIO_BUFFER_SIZE];
-
- // NOTE: Returns the number of samples to process (should be the same as numSamples)
- unsigned int numSamplesFlac = (unsigned int)drflac_read_s32(music->ctxFlac, numSamples, pcmi);
-
- UpdateAudioStream(music->stream, pcmi, numSamplesFlac*music->stream.channels);
- music->samplesLeft -= (numSamples*music->stream.channels);
-
- } break;
- case MUSIC_MODULE_XM:
- {
- if (music->samplesLeft >= AUDIO_BUFFER_SIZE/2) numSamples = AUDIO_BUFFER_SIZE/2;
- else numSamples = music->samplesLeft;
-
- // NOTE: Output buffer is 2*numsamples elements (left and right value for each sample)
- jar_xm_generate_samples(music->ctxXm, pcmf, numSamples);
- UpdateAudioStream(music->stream, pcmf, numSamples*2); // Using 32bit PCM data
- music->samplesLeft -= numSamples;
-
- //TraceLog(INFO, "Samples left: %i", music->samplesLeft);
-
- } break;
- case MUSIC_MODULE_MOD:
- {
- if (music->samplesLeft >= AUDIO_BUFFER_SIZE/2) numSamples = AUDIO_BUFFER_SIZE/2;
- else numSamples = music->samplesLeft;
-
- // NOTE: Output buffer size is nbsample*channels (default: 48000Hz, 16bit, Stereo)
- jar_mod_fillbuffer(&music->ctxMod, pcm, numSamples, 0);
- UpdateAudioStream(music->stream, pcm, numSamples*2);
- music->samplesLeft -= numSamples;
+ // NOTE: Returns the number of samples to process
+ unsigned int numSamplesFlac = (unsigned int)drflac_read_s16(music->ctxFlac, samplesCount*music->stream.channels, (short *)pcm);
} break;
+ case MUSIC_MODULE_XM: jar_xm_generate_samples_16bit(music->ctxXm, pcm, samplesCount); break;
+ case MUSIC_MODULE_MOD: jar_mod_fillbuffer(&music->ctxMod, pcm, samplesCount, 0); break;
default: break;
}
+ UpdateAudioStream(music->stream, pcm, samplesCount);
+ music->samplesLeft -= samplesCount;
+
if (music->samplesLeft <= 0)
{
active = false;
break;
}
}
-
+
// This error is registered when UpdateAudioStream() fails
if (alGetError() == AL_INVALID_VALUE) TraceLog(WARNING, "OpenAL: Error buffering data...");
// Reset audio stream for looping
- if (!active)
+ if (!active)
{
StopMusicStream(music); // Stop music (and reset)
- if (music->loop) PlayMusicStream(music); // Play again
+ // Decrease loopCount to stop when required
+ if (music->loopCount > 0)
+ {
+ music->loopCount--; // Decrease loop count
+ PlayMusicStream(music); // Play again
+ }
}
else
{
@@ -910,6 +862,8 @@ void UpdateMusicStream(Music music)
// just make sure to play again on window restore
if (state != AL_PLAYING) PlayMusicStream(music);
}
+
+ free(pcm);
}
}
@@ -938,6 +892,13 @@ void SetMusicPitch(Music music, float pitch)
alSourcef(music->stream.source, AL_PITCH, pitch);
}
+// Set music loop count (loop repeats)
+// NOTE: If set to -1, means infinite loop
+void SetMusicLoopCount(Music music, float count)
+{
+ music->loopCount = count;
+}
+
// Get music time length (in seconds)
float GetMusicTimeLength(Music music)
{
@@ -952,7 +913,7 @@ float GetMusicTimePlayed(Music music)
float secondsPlayed = 0.0f;
unsigned int samplesPlayed = music->totalSamples - music->samplesLeft;
- secondsPlayed = (float)samplesPlayed/(music->stream.sampleRate*music->stream.channels);
+ secondsPlayed = (float)samplesPlayed/music->stream.sampleRate;
return secondsPlayed;
}
@@ -964,64 +925,61 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
stream.sampleRate = sampleRate;
stream.sampleSize = sampleSize;
- stream.channels = channels;
+
+ // Only mono and stereo channels are supported, more channels require AL_EXT_MCFORMATS extension
+ if ((channels > 0) && (channels < 3)) stream.channels = channels;
+ else
+ {
+ TraceLog(WARNING, "Init audio stream: Number of channels not supported: %i", channels);
+ stream.channels = 1; // Fallback to mono channel
+ }
// Setup OpenAL format
- if (channels == 1)
+ if (stream.channels == 1)
{
switch (sampleSize)
{
case 8: stream.format = AL_FORMAT_MONO8; break;
case 16: stream.format = AL_FORMAT_MONO16; break;
- case 32: stream.format = AL_FORMAT_MONO_FLOAT32; break;
+ case 32: stream.format = AL_FORMAT_MONO_FLOAT32; break; // Requires OpenAL extension: AL_EXT_FLOAT32
default: TraceLog(WARNING, "Init audio stream: Sample size not supported: %i", sampleSize); break;
}
}
- else if (channels == 2)
+ else if (stream.channels == 2)
{
switch (sampleSize)
{
case 8: stream.format = AL_FORMAT_STEREO8; break;
case 16: stream.format = AL_FORMAT_STEREO16; break;
- case 32: stream.format = AL_FORMAT_STEREO_FLOAT32; break;
+ case 32: stream.format = AL_FORMAT_STEREO_FLOAT32; break; // Requires OpenAL extension: AL_EXT_FLOAT32
default: TraceLog(WARNING, "Init audio stream: Sample size not supported: %i", sampleSize); break;
}
}
- else TraceLog(WARNING, "Init audio stream: Number of channels not supported: %i", channels);
// Create an audio source
alGenSources(1, &stream.source);
- alSourcef(stream.source, AL_PITCH, 1);
- alSourcef(stream.source, AL_GAIN, 1);
- alSource3f(stream.source, AL_POSITION, 0, 0, 0);
- alSource3f(stream.source, AL_VELOCITY, 0, 0, 0);
+ alSourcef(stream.source, AL_PITCH, 1.0f);
+ alSourcef(stream.source, AL_GAIN, 1.0f);
+ alSource3f(stream.source, AL_POSITION, 0.0f, 0.0f, 0.0f);
+ alSource3f(stream.source, AL_VELOCITY, 0.0f, 0.0f, 0.0f);
// Create Buffers (double buffering)
alGenBuffers(MAX_STREAM_BUFFERS, stream.buffers);
// Initialize buffer with zeros by default
+ // NOTE: Using dynamic allocation because it requires more than 16KB
+ void *pcm = calloc(AUDIO_BUFFER_SIZE*stream.sampleSize/8*stream.channels, 1);
+
for (int i = 0; i < MAX_STREAM_BUFFERS; i++)
{
- if (stream.sampleSize == 8)
- {
- unsigned char pcm[AUDIO_BUFFER_SIZE] = { 0 };
- alBufferData(stream.buffers[i], stream.format, pcm, AUDIO_BUFFER_SIZE*sizeof(unsigned char), stream.sampleRate);
- }
- else if (stream.sampleSize == 16)
- {
- short pcm[AUDIO_BUFFER_SIZE] = { 0 };
- alBufferData(stream.buffers[i], stream.format, pcm, AUDIO_BUFFER_SIZE*sizeof(short), stream.sampleRate);
- }
- else if (stream.sampleSize == 32)
- {
- float pcm[AUDIO_BUFFER_SIZE] = { 0.0f };
- alBufferData(stream.buffers[i], stream.format, pcm, AUDIO_BUFFER_SIZE*sizeof(float), stream.sampleRate);
- }
+ alBufferData(stream.buffers[i], stream.format, pcm, AUDIO_BUFFER_SIZE*stream.sampleSize/8*stream.channels, stream.sampleRate);
}
+ free(pcm);
+
alSourceQueueBuffers(stream.source, MAX_STREAM_BUFFERS, stream.buffers);
- TraceLog(INFO, "[AUD ID %i] Audio stream loaded successfully", stream.source);
+ TraceLog(INFO, "[AUD ID %i] Audio stream loaded successfully (%i Hz, %i bit, %s)", stream.source, stream.sampleRate, stream.sampleSize, (stream.channels == 1) ? "Mono" : "Stereo");
return stream;
}
@@ -1052,8 +1010,8 @@ void CloseAudioStream(AudioStream stream)
}
// Update audio stream buffers with data
-// NOTE: Only one buffer per call
-void UpdateAudioStream(AudioStream stream, void *data, int numSamples)
+// NOTE: Only updates one buffer per call
+void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
{
ALuint buffer = 0;
alSourceUnqueueBuffers(stream.source, 1, &buffer);
@@ -1061,10 +1019,7 @@ void UpdateAudioStream(AudioStream stream, void *data, int numSamples)
// Check if any buffer was available for unqueue
if (alGetError() != AL_INVALID_VALUE)
{
- if (stream.sampleSize == 8) alBufferData(buffer, stream.format, (unsigned char *)data, numSamples*sizeof(unsigned char), stream.sampleRate);
- else if (stream.sampleSize == 16) alBufferData(buffer, stream.format, (short *)data, numSamples*sizeof(short), stream.sampleRate);
- else if (stream.sampleSize == 32) alBufferData(buffer, stream.format, (float *)data, numSamples*sizeof(float), stream.sampleRate);
-
+ alBufferData(buffer, stream.format, data, samplesCount*stream.channels*stream.sampleSize/8, stream.sampleRate);
alSourceQueueBuffers(stream.source, 1, &buffer);
}
}
@@ -1119,7 +1074,7 @@ static Wave LoadWAV(const char *fileName)
char chunkID[4];
int chunkSize;
char format[4];
- } RiffHeader;
+ } WAVRiffHeader;
typedef struct {
char subChunkID[4];
@@ -1130,16 +1085,16 @@ static Wave LoadWAV(const char *fileName)
int byteRate;
short blockAlign;
short bitsPerSample;
- } WaveFormat;
+ } WAVFormat;
typedef struct {
char subChunkID[4];
int subChunkSize;
- } WaveData;
+ } WAVData;
- RiffHeader riffHeader;
- WaveFormat waveFormat;
- WaveData waveData;
+ WAVRiffHeader wavRiffHeader;
+ WAVFormat wavFormat;
+ WAVData wavData;
Wave wave = { 0 };
FILE *wavFile;
@@ -1154,54 +1109,70 @@ static Wave LoadWAV(const char *fileName)
else
{
// Read in the first chunk into the struct
- fread(&riffHeader, sizeof(RiffHeader), 1, wavFile);
+ fread(&wavRiffHeader, sizeof(WAVRiffHeader), 1, wavFile);
// Check for RIFF and WAVE tags
- if (strncmp(riffHeader.chunkID, "RIFF", 4) ||
- strncmp(riffHeader.format, "WAVE", 4))
+ if (strncmp(wavRiffHeader.chunkID, "RIFF", 4) ||
+ strncmp(wavRiffHeader.format, "WAVE", 4))
{
TraceLog(WARNING, "[%s] Invalid RIFF or WAVE Header", fileName);
}
else
{
// Read in the 2nd chunk for the wave info
- fread(&waveFormat, sizeof(WaveFormat), 1, wavFile);
+ fread(&wavFormat, sizeof(WAVFormat), 1, wavFile);
// Check for fmt tag
- if ((waveFormat.subChunkID[0] != 'f') || (waveFormat.subChunkID[1] != 'm') ||
- (waveFormat.subChunkID[2] != 't') || (waveFormat.subChunkID[3] != ' '))
+ if ((wavFormat.subChunkID[0] != 'f') || (wavFormat.subChunkID[1] != 'm') ||
+ (wavFormat.subChunkID[2] != 't') || (wavFormat.subChunkID[3] != ' '))
{
TraceLog(WARNING, "[%s] Invalid Wave format", fileName);
}
else
{
// Check for extra parameters;
- if (waveFormat.subChunkSize > 16) fseek(wavFile, sizeof(short), SEEK_CUR);
+ if (wavFormat.subChunkSize > 16) fseek(wavFile, sizeof(short), SEEK_CUR);
// Read in the the last byte of data before the sound file
- fread(&waveData, sizeof(WaveData), 1, wavFile);
+ fread(&wavData, sizeof(WAVData), 1, wavFile);
// Check for data tag
- if ((waveData.subChunkID[0] != 'd') || (waveData.subChunkID[1] != 'a') ||
- (waveData.subChunkID[2] != 't') || (waveData.subChunkID[3] != 'a'))
+ if ((wavData.subChunkID[0] != 'd') || (wavData.subChunkID[1] != 'a') ||
+ (wavData.subChunkID[2] != 't') || (wavData.subChunkID[3] != 'a'))
{
TraceLog(WARNING, "[%s] Invalid data header", fileName);
}
else
{
// Allocate memory for data
- wave.data = (unsigned char *)malloc(sizeof(unsigned char)*waveData.subChunkSize);
+ wave.data = malloc(wavData.subChunkSize);
// Read in the sound data into the soundData variable
- fread(wave.data, waveData.subChunkSize, 1, wavFile);
+ fread(wave.data, wavData.subChunkSize, 1, wavFile);
+
+ // Store wave parameters
+ wave.sampleRate = wavFormat.sampleRate;
+ wave.sampleSize = wavFormat.bitsPerSample;
+ wave.channels = wavFormat.numChannels;
+
+ // NOTE: Only support 8 bit, 16 bit and 32 bit sample sizes
+ if ((wave.sampleSize != 8) && (wave.sampleSize != 16) && (wave.sampleSize != 32))
+ {
+ TraceLog(WARNING, "[%s] WAV sample size (%ibit) not supported, converted to 16bit", fileName, wave.sampleSize);
+ WaveFormat(&wave, wave.sampleRate, 16, wave.channels);
+ }
+
+ // NOTE: Only support up to 2 channels (mono, stereo)
+ if (wave.channels > 2)
+ {
+ WaveFormat(&wave, wave.sampleRate, wave.sampleSize, 2);
+ TraceLog(WARNING, "[%s] WAV channels number (%i) not supported, converted to 2 channels", fileName, wave.channels);
+ }
- // Now we set the variables that we need later
- wave.sampleCount = waveData.subChunkSize;
- wave.sampleRate = waveFormat.sampleRate;
- wave.sampleSize = waveFormat.bitsPerSample;
- wave.channels = waveFormat.numChannels;
+ // NOTE: subChunkSize comes in bytes, we need to translate it to number of samples
+ wave.sampleCount = (wavData.subChunkSize/(wave.sampleSize/8))/wave.channels;
- TraceLog(INFO, "[%s] WAV file loaded successfully (SampleRate: %i, SampleSize: %i, Channels: %i)", fileName, wave.sampleRate, wave.sampleSize, wave.channels);
+ TraceLog(INFO, "[%s] WAV file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo");
}
}
}
@@ -1232,22 +1203,19 @@ static Wave LoadOGG(const char *fileName)
wave.sampleRate = info.sample_rate;
wave.sampleSize = 16; // 16 bit per sample (short)
wave.channels = info.channels;
+ wave.sampleCount = (int)stb_vorbis_stream_length_in_samples(oggFile);
- int totalSamplesLength = (stb_vorbis_stream_length_in_samples(oggFile)*info.channels);
float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile);
-
if (totalSeconds > 10) TraceLog(WARNING, "[%s] Ogg audio lenght is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds);
- int totalSamples = (int)(totalSeconds*info.sample_rate*info.channels);
- wave.sampleCount = totalSamples;
+ wave.data = (short *)malloc(wave.sampleCount*wave.channels*sizeof(short));
- wave.data = (short *)malloc(totalSamplesLength*sizeof(short));
+ // NOTE: Returns the number of samples to process (be careful! we ask for number of shorts!)
+ int numSamplesOgg = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, (short *)wave.data, wave.sampleCount*wave.channels);
- int samplesObtained = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, (short *)wave.data, totalSamplesLength);
+ TraceLog(DEBUG, "[%s] Samples obtained: %i", fileName, numSamplesOgg);
- TraceLog(DEBUG, "[%s] Samples obtained: %i", fileName, samplesObtained);
-
- TraceLog(INFO, "[%s] OGG file loaded successfully (SampleRate: %i, SampleSize: %i, Channels: %i)", fileName, wave.sampleRate, wave.sampleSize, wave.channels);
+ TraceLog(INFO, "[%s] OGG file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo");
stb_vorbis_close(oggFile);
}
@@ -1263,13 +1231,17 @@ static Wave LoadFLAC(const char *fileName)
// Decode an entire FLAC file in one go
uint64_t totalSampleCount;
- wave.data = drflac_open_and_decode_file_s32(fileName, &wave.channels, &wave.sampleRate, &totalSampleCount);
-
- wave.sampleCount = (int)totalSampleCount;
- wave.sampleSize = 32;
-
+ wave.data = drflac_open_and_decode_file_s16(fileName, &wave.channels, &wave.sampleRate, &totalSampleCount);
+
+ wave.sampleCount = (int)totalSampleCount/wave.channels;
+ wave.sampleSize = 16;
+
+ // NOTE: Only support up to 2 channels (mono, stereo)
+ if (wave.channels > 2) TraceLog(WARNING, "[%s] FLAC channels number (%i) not supported", fileName, wave.channels);
+
if (wave.data == NULL) TraceLog(WARNING, "[%s] FLAC data could not be loaded", fileName);
-
+ else TraceLog(INFO, "[%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo");
+
return wave;
}
@@ -1314,4 +1286,4 @@ void TraceLog(int msgType, const char *text, ...)
if (msgType == ERROR) exit(1); // If ERROR message, exit program
}
-#endif \ No newline at end of file
+#endif
diff --git a/src/audio.h b/src/audio.h
index 2b3c5933..01ed9f72 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -9,7 +9,7 @@
* Manage mixing channels
* Manage raw audio context
*
-* External libs:
+* DEPENDENCIES:
* 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
@@ -23,6 +23,8 @@
* Raw audio context support
*
*
+* LICENSE: zlib/libpng
+*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
* This software is provided "as-is", without any express or implied warranty. In no event
@@ -109,13 +111,13 @@ extern "C" { // Prevents name mangling of functions
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
+void SetMasterVolume(float volume); // Set master volume (listener)
-Wave LoadWave(const char *fileName); // Load wave data from file into RAM
-Wave LoadWaveEx(float *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from float array data (32bit)
-Sound LoadSound(const char *fileName); // Load sound to memory
-Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data
-Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource)
-void UpdateSound(Sound sound, void *data, int numSamples); // Update sound buffer with new data
+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 samplesCount); // 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
@@ -139,13 +141,14 @@ void ResumeMusicStream(Music music); // Resume playin
bool IsMusicPlaying(Music music); // Check if music is playing
void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
+void SetMusicLoopCount(Music music, float count); // Set music loop count (loop repeats)
float GetMusicTimeLength(Music music); // Get music time length (in seconds)
float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
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 UpdateAudioStream(AudioStream stream, void *data, int samplesCount); // 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
diff --git a/src/camera.h b/src/camera.h
index 33220390..87ba1942 100644
--- a/src/camera.h
+++ b/src/camera.h
@@ -2,6 +2,10 @@
*
* raylib Camera System - Camera Modes Setup and Control Functions
*
+* NOTE: Memory footprint of this library is aproximately 52 bytes (global variables)
+*
+* CONFIGURATION:
+*
* #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
@@ -11,10 +15,14 @@
* 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)
+* CONTRIBUTORS:
+* Marc Palau: Initial implementation (2014)
+* Ramon Santamaria: Supervision, review, update and maintenance
+*
+*
+* LICENSE: zlib/libpng
*
-* Initial design by Marc Palau (2014)
-* Reviewed by Ramon Santamaria (2015-2016)
+* Copyright (c) 2015-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.
@@ -223,15 +231,15 @@ void SetCameraMode(Camera camera, int mode)
float dy = v2.y - v1.y;
float dz = v2.z - v1.z;
- cameraTargetDistance = sqrt(dx*dx + dy*dy + dz*dz);
+ cameraTargetDistance = sqrtf(dx*dx + dy*dy + dz*dz);
Vector2 distance = { 0.0f, 0.0f };
- distance.x = sqrt(dx*dx + dz*dz);
- distance.y = sqrt(dx*dx + dy*dy);
+ distance.x = sqrtf(dx*dx + dz*dz);
+ distance.y = sqrtf(dx*dx + dy*dy);
// Camera angle calculation
- cameraAngle.x = asin(fabs(dx)/distance.x); // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
- cameraAngle.y = -asin(fabs(dy)/distance.y); // Camera angle in plane XY (0 aligned with X, move positive CW)
+ 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)
@@ -285,10 +293,10 @@ void UpdateCamera(Camera *camera)
{
HideCursor();
- if (mousePosition.x < screenHeight/3) SetMousePosition((Vector2){ screenWidth - screenHeight/3, mousePosition.y });
- else if (mousePosition.y < screenHeight/3) SetMousePosition((Vector2){ mousePosition.x, screenHeight - screenHeight/3 });
- else if (mousePosition.x > (screenWidth - screenHeight/3)) SetMousePosition((Vector2){ screenHeight/3, mousePosition.y });
- else if (mousePosition.y > (screenHeight - screenHeight/3)) SetMousePosition((Vector2){ mousePosition.x, screenHeight/3 });
+ 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;
@@ -321,6 +329,7 @@ void UpdateCamera(Camera *camera)
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;
@@ -341,6 +350,7 @@ void UpdateCamera(Camera *camera)
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;
@@ -385,9 +395,9 @@ void UpdateCamera(Camera *camera)
else
{
// Camera panning
- camera->target.x += ((mousePositionDelta.x*-CAMERA_FREE_MOUSE_SENSITIVITY)*cos(cameraAngle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*sin(cameraAngle.x)*sin(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER);
- camera->target.y += ((mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cos(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER);
- camera->target.z += ((mousePositionDelta.x*CAMERA_FREE_MOUSE_SENSITIVITY)*sin(cameraAngle.x) + (mousePositionDelta.y*CAMERA_FREE_MOUSE_SENSITIVITY)*cos(cameraAngle.x)*sin(cameraAngle.y))*(cameraTargetDistance/CAMERA_FREE_PANNING_DIVIDER);
+ 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);
}
}
@@ -404,19 +414,19 @@ void UpdateCamera(Camera *camera)
case CAMERA_FIRST_PERSON:
case CAMERA_THIRD_PERSON:
{
- camera->position.x += (sin(cameraAngle.x)*direction[MOVE_BACK] -
- sin(cameraAngle.x)*direction[MOVE_FRONT] -
- cos(cameraAngle.x)*direction[MOVE_LEFT] +
- cos(cameraAngle.x)*direction[MOVE_RIGHT])/PLAYER_MOVEMENT_SENSITIVITY;
+ 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 += (sin(cameraAngle.y)*direction[MOVE_FRONT] -
- sin(cameraAngle.y)*direction[MOVE_BACK] +
+ 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 += (cos(cameraAngle.x)*direction[MOVE_BACK] -
- cos(cameraAngle.x)*direction[MOVE_FRONT] +
- sin(cameraAngle.x)*direction[MOVE_LEFT] -
- sin(cameraAngle.x)*direction[MOVE_RIGHT])/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
@@ -439,9 +449,9 @@ void UpdateCamera(Camera *camera)
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*cos(cameraAngle.x) + CAMERA_THIRD_PERSON_OFFSET.z*sin(cameraAngle.x);
+ 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*sin(cameraAngle.x) - CAMERA_THIRD_PERSON_OFFSET.x*sin(cameraAngle.x);
+ 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
{
@@ -450,18 +460,18 @@ void UpdateCamera(Camera *camera)
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 - sin(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
- camera->target.y = camera->position.y + sin(cameraAngle.y)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
- camera->target.z = camera->position.z - cos(cameraAngle.x)*CAMERA_FIRST_PERSON_FOCUS_DISTANCE;
+ 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 - sin(swingCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER;
+ camera->position.y = playerEyesPosition - sinf(swingCounter/CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER)/CAMERA_FIRST_PERSON_STEP_DIVIDER;
- camera->up.x = sin(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_DIVIDER;
- camera->up.z = -sin(swingCounter/(CAMERA_FIRST_PERSON_STEP_TRIGONOMETRIC_DIVIDER*2))/CAMERA_FIRST_PERSON_WAVING_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;
@@ -473,10 +483,10 @@ void UpdateCamera(Camera *camera)
(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 = sin(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.x;
- if (cameraAngle.y <= 0.0f) camera->position.y = sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
- else camera->position.y = -sin(cameraAngle.y)*cameraTargetDistance*sin(cameraAngle.y) + camera->target.y;
- camera->position.z = cos(cameraAngle.x)*cameraTargetDistance*cos(cameraAngle.y) + camera->target.z;
+ 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;
}
}
diff --git a/src/core.c b/src/core.c
index 241772ec..a3b5f486 100644
--- a/src/core.c
+++ b/src/core.c
@@ -1,27 +1,46 @@
/**********************************************************************************************
*
-* raylib.core
-*
-* Basic functions to manage windows, OpenGL context and input on multiple platforms
+* raylib.core - Basic functions to manage windows, OpenGL context and input on multiple platforms
*
* The following platforms are supported: Windows, Linux, Mac (OSX), Android, Raspberry Pi, HTML5, Oculus Rift CV1
*
-* External libs:
+* CONFIGURATION:
+*
+* #define PLATFORM_DESKTOP
+* Windowing and input system configured for desktop platforms: Windows, Linux, OSX (managed by GLFW3 library)
+* NOTE: Oculus Rift CV1 requires PLATFORM_DESKTOP for mirror rendering - View [rlgl] module to enable it
+*
+* #define PLATFORM_ANDROID
+* Windowing and input system configured for Android device, app activity managed internally in this module.
+* NOTE: OpenGL ES 2.0 is required and graphic device is managed by EGL
+*
+* #define PLATFORM_RPI
+* Windowing and input system configured for Raspberry Pi (tested on Raspbian), graphic device is managed by EGL
+* and inputs are processed is raw mode, reading from /dev/input/
+*
+* #define PLATFORM_WEB
+* Windowing and input system configured for HTML5 (run on browser), code converted from C to asm.js
+* using emscripten compiler. OpenGL ES 2.0 required for direct translation to WebGL equivalent code.
+*
+* #define LOAD_DEFAULT_FONT (defined by default)
+* Default font is loaded on window initialization to be available for the user to render simple text.
+* NOTE: If enabled, uses external module functions to load default raylib font (module: text)
+*
+* #define INCLUDE_CAMERA_SYSTEM / SUPPORT_CAMERA_SYSTEM
+*
+* #define INCLUDE_GESTURES_SYSTEM / SUPPORT_GESTURES_SYSTEM
+*
+* #define SUPPORT_MOUSE_GESTURES
+* Mouse gestures are directly mapped like touches and processed by gestures system.
+*
+* DEPENDENCIES:
* GLFW3 - Manage graphic device, OpenGL context and inputs on PLATFORM_DESKTOP (Windows, Linux, OSX)
* raymath - 3D math functionality (Vector3, Matrix, Quaternion)
-* camera - Multiple 3D camera modes (free, orbital, 1st person, 3rd person)
+* camera - Multiple 3D camera modes (free, orbital, 1st person, 3rd person)
* gestures - Gestures system for touch-ready devices (or simulated from mouse inputs)
*
-* Module Configuration Flags:
-* PLATFORM_DESKTOP - Windows, Linux, Mac (OSX)
-* PLATFORM_ANDROID - Android (only OpenGL ES 2.0 devices), graphic device is managed by EGL and input system by Android activity.
-* PLATFORM_RPI - Rapsberry Pi (tested on Raspbian), graphic device is managed by EGL and input system is coded in raw mode.
-* PLATFORM_WEB - HTML5 (using emscripten compiler)
-*
-* RL_LOAD_DEFAULT_FONT - Use external module functions to load default raylib font (module: text)
-*
-* NOTE: Oculus Rift CV1 requires PLATFORM_DESKTOP for render mirror - View [rlgl] module to enable it
*
+* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
@@ -42,13 +61,14 @@
*
**********************************************************************************************/
-#include "raylib.h" // raylib main header
+#include "raylib.h"
+
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
-#include "utils.h" // Includes Android fopen map, InitAssetManager(), TraceLog()
+#include "utils.h" // Required for: fopen() Android mapping, TraceLog()
#define RAYMATH_IMPLEMENTATION // Use raymath as a header-only library (includes implementation)
#define RAYMATH_EXTERN_INLINE // Compile raymath functions as static inline (remember, it's a compiler hint)
-#include "raymath.h" // Required for Vector3 and Matrix functions
+#include "raymath.h" // Required for: Vector3 and Matrix functions
#define GESTURES_IMPLEMENTATION
#include "gestures.h" // Gestures detection functionality
@@ -66,9 +86,15 @@
#include <string.h> // Required for: strcmp()
//#include <errno.h> // Macros for reporting and retrieving error conditions through error codes
+#if defined __linux || defined(PLATFORM_WEB)
+ #include <sys/time.h> // Required for: timespec, nanosleep(), select() - POSIX
+#elif defined __APPLE__
+ #include <unistd.h> // Required for: usleep()
+#endif
+
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
- //#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3
- #include <GLFW/glfw3.h> // GLFW3 library: Windows, OpenGL context and Input management
+ //#define GLFW_INCLUDE_NONE // Disable the standard OpenGL header inclusion on GLFW3
+ #include <GLFW/glfw3.h> // GLFW3 library: Windows, OpenGL context and Input management
#ifdef __linux
#define GLFW_EXPOSE_NATIVE_X11 // Linux specific definitions for getting
@@ -98,7 +124,7 @@
#include <linux/kd.h> // Linux: KDSKBMODE, K_MEDIUMRAM constants definition
#include <linux/input.h> // Linux: Keycodes constants definition (KEY_A, ...)
#include <linux/joystick.h> // Linux: Joystick support library
-
+
#include "bcm_host.h" // Raspberry Pi VideoCore IV access functions
#include "EGL/egl.h" // Khronos EGL library - Native platform display device control functions
@@ -120,6 +146,7 @@
// Old device inputs system
#define DEFAULT_KEYBOARD_DEV STDIN_FILENO // Standard input
#define DEFAULT_MOUSE_DEV "/dev/input/mouse0" // Mouse input
+ #define DEFAULT_TOUCH_DEV "/dev/input/event4" // Touch input virtual device (created by ts_uinput)
#define DEFAULT_GAMEPAD_DEV "/dev/input/js" // Gamepad input (base dev for all gamepads: js0, js1, ...)
// New device input events (evdev) (must be detected)
@@ -134,7 +161,7 @@
#define MAX_GAMEPAD_BUTTONS 32 // Max bumber of buttons supported (per gamepad)
#define MAX_GAMEPAD_AXIS 8 // Max number of axis supported (per gamepad)
-#define RL_LOAD_DEFAULT_FONT // Load default font on window initialization (module: text)
+#define LOAD_DEFAULT_FONT // Load default font on window initialization (module: text)
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -173,6 +200,11 @@ static int mouseStream = -1; // Mouse device file descriptor
static bool mouseReady = false; // Flag to know if mouse is ready
static pthread_t mouseThreadId; // Mouse reading thread id
+// Touch input variables
+static int touchStream = -1; // Touch device file descriptor
+static bool touchReady = false; // Flag to know if touch interface is ready
+static pthread_t touchThreadId; // Touch reading thread id
+
// Gamepad input variables
static int gamepadStream[MAX_GAMEPADS] = { -1 };// Gamepad device file descriptor
static pthread_t gamepadThreadId; // Gamepad reading thread id
@@ -236,7 +268,7 @@ static int dropFilesCount = 0; // Count stored strings
static double currentTime, previousTime; // Used to track timmings
static double updateTime, drawTime; // Time measures for update and draw
-static double frameTime; // Time measure for one frame
+static double frameTime = 0.0; // Time measure for one frame
static double targetTime = 0.0; // Desired time for one frame, if 0 not applied
static char configFlags = 0; // Configuration flags (bit based)
@@ -245,7 +277,7 @@ static bool showLogo = false; // Track if showing logo at init is
//----------------------------------------------------------------------------------
// Other Modules Functions Declaration (required by core)
//----------------------------------------------------------------------------------
-#if defined(RL_LOAD_DEFAULT_FONT)
+#if defined(LOAD_DEFAULT_FONT)
extern void LoadDefaultFont(void); // [Module: text] Loads default font on InitWindow()
extern void UnloadDefaultFont(void); // [Module: text] Unloads default font from GPU memory
#endif
@@ -257,11 +289,13 @@ static void InitGraphicsDevice(int width, int height); // Initialize graphics d
static void SetupFramebufferSize(int displayWidth, int displayHeight);
static void InitTimer(void); // Initialize timer
static double GetTime(void); // Returns time since InitTimer() was run
+static void Wait(float ms); // Wait for some milliseconds (stop program execution)
static bool GetKeyStatus(int key); // Returns if a key has been pressed
static bool GetMouseButtonStatus(int button); // Returns if a mouse button has been pressed
static void PollInputEvents(void); // Register user events
static void SwapBuffers(void); // Copy back buffer to front buffers
static void LogoAnimation(void); // Plays raylib logo appearing animation
+static void SetupViewport(void); // Set viewport parameters
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
static void TakeScreenshot(void); // Takes a screenshot and saves it in the same folder as executable
#endif
@@ -290,6 +324,7 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
#if defined(PLATFORM_WEB)
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData);
static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData);
+static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData);
#endif
#if defined(PLATFORM_RPI)
@@ -298,10 +333,17 @@ static void ProcessKeyboard(void); // Process keyboard even
static void RestoreKeyboard(void); // Restore keyboard system
static void InitMouse(void); // Mouse initialization (including mouse thread)
static void *MouseThread(void *arg); // Mouse reading thread
+static void InitTouch(void); // Touch device initialization (including touch thread)
+static void *TouchThread(void *arg); // Touch device reading thread
static void InitGamepad(void); // Init raw gamepad input
static void *GamepadThread(void *arg); // Mouse reading thread
#endif
+#if defined(_WIN32)
+ // NOTE: We include Sleep() function signature here to avoid windows.h inclusion
+ void __stdcall Sleep(unsigned long msTimeout); // Required for Wait()
+#endif
+
//----------------------------------------------------------------------------------
// Module Functions Definition - Window and OpenGL Context Functions
//----------------------------------------------------------------------------------
@@ -309,7 +351,7 @@ static void *GamepadThread(void *arg); // Mouse reading thread
// Initialize Window and Graphics Context (OpenGL)
void InitWindow(int width, int height, const char *title)
{
- TraceLog(INFO, "Initializing raylib (v1.6.0)");
+ TraceLog(INFO, "Initializing raylib (v1.7.0)");
// Store window title (could be useful...)
windowTitle = title;
@@ -317,7 +359,7 @@ void InitWindow(int width, int height, const char *title)
// Init graphics device (display device and OpenGL context)
InitGraphicsDevice(width, height);
-#if defined(RL_LOAD_DEFAULT_FONT)
+#if defined(LOAD_DEFAULT_FONT)
// Load default font
// NOTE: External function (defined in module: text)
LoadDefaultFont();
@@ -329,6 +371,7 @@ void InitWindow(int width, int height, const char *title)
#if defined(PLATFORM_RPI)
// Init raw input system
InitMouse(); // Mouse init
+ InitTouch(); // Touch init
InitKeyboard(); // Keyboard init
InitGamepad(); // Gamepad init
#endif
@@ -344,9 +387,9 @@ void InitWindow(int width, int height, const char *title)
emscripten_set_touchmove_callback("#canvas", NULL, 1, EmscriptenInputCallback);
emscripten_set_touchcancel_callback("#canvas", NULL, 1, EmscriptenInputCallback);
- // TODO: Add gamepad support (not provided by GLFW3 on emscripten)
- //emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenInputCallback);
- //emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenInputCallback);
+ // Support gamepad (not provided by GLFW3 on emscripten)
+ emscripten_set_gamepadconnected_callback(NULL, 1, EmscriptenGamepadCallback);
+ emscripten_set_gamepaddisconnected_callback(NULL, 1, EmscriptenGamepadCallback);
#endif
mousePosition.x = (float)screenWidth/2.0f;
@@ -365,7 +408,7 @@ void InitWindow(int width, int height, const char *title)
// Android activity initialization
void InitWindow(int width, int height, void *state)
{
- TraceLog(INFO, "Initializing raylib (v1.6.0)");
+ TraceLog(INFO, "Initializing raylib (v1.7.0)");
app_dummy();
@@ -428,7 +471,7 @@ void InitWindow(int width, int height, void *state)
// Close Window and Terminate Context
void CloseWindow(void)
{
-#if defined(RL_LOAD_DEFAULT_FONT)
+#if defined(LOAD_DEFAULT_FONT)
UnloadDefaultFont();
#endif
@@ -466,10 +509,11 @@ void CloseWindow(void)
// Wait for mouse and gamepad threads to finish before closing
// NOTE: Those threads should already have finished at this point
// because they are controlled by windowShouldClose variable
-
+
windowShouldClose = true; // Added to force threads to exit when the close window is called
-
+
pthread_join(mouseThreadId, NULL);
+ pthread_join(touchThreadId, NULL);
pthread_join(gamepadThreadId, NULL);
#endif
@@ -481,7 +525,7 @@ bool WindowShouldClose(void)
{
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
// While window minimized, stop loop execution
- while (windowMinimized) glfwPollEvents();
+ while (windowMinimized) glfwWaitEvents();
return (glfwWindowShouldClose(window));
#endif
@@ -501,7 +545,7 @@ bool IsWindowMinimized(void)
#endif
}
-// Fullscreen toggle
+// Fullscreen toggle (only PLATFORM_DESKTOP)
void ToggleFullscreen(void)
{
#if defined(PLATFORM_DESKTOP)
@@ -517,6 +561,45 @@ void ToggleFullscreen(void)
#endif
}
+// Set icon for window (only PLATFORM_DESKTOP)
+void SetWindowIcon(Image image)
+{
+#if defined(PLATFORM_DESKTOP)
+ ImageFormat(&image, UNCOMPRESSED_R8G8B8A8);
+
+ GLFWimage icon[1];
+
+ icon[0].width = image.width;
+ icon[0].height = image.height;
+ icon[0].pixels = (unsigned char *)image.data;
+
+ // NOTE: We only support one image icon
+ glfwSetWindowIcon(window, 1, icon);
+
+ // TODO: Support multi-image icons --> image.mipmaps
+#endif
+}
+
+// Set window position on screen (windowed mode)
+void SetWindowPosition(int x, int y)
+{
+ glfwSetWindowPos(window, x, y);
+}
+
+// Set monitor for the current window (fullscreen mode)
+void SetWindowMonitor(int monitor)
+{
+ int monitorCount;
+ GLFWmonitor** monitors = glfwGetMonitors(&monitorCount);
+
+ if ((monitor >= 0) && (monitor < monitorCount))
+ {
+ glfwSetWindowMonitor(window, monitors[monitor], 0, 0, screenWidth, screenHeight, GLFW_DONT_CARE);
+ TraceLog(INFO, "Selected fullscreen monitor: [%i] %s", monitor, glfwGetMonitorName(monitors[monitor]));
+ }
+ else TraceLog(WARNING, "Selected monitor not found");
+}
+
// Get current screen width
int GetScreenWidth(void)
{
@@ -548,14 +631,14 @@ void HideCursor()
{
#if defined(PLATFORM_DESKTOP)
#ifdef __linux
- XColor Col;
- const char Nil[] = {0};
+ XColor col;
+ const char nil[] = {0};
- Pixmap Pix = XCreateBitmapFromData(glfwGetX11Display(), glfwGetX11Window(window), Nil, 1, 1);
- Cursor Cur = XCreatePixmapCursor(glfwGetX11Display(), Pix, Pix, &Col, &Col, 0, 0);
+ Pixmap pix = XCreateBitmapFromData(glfwGetX11Display(), glfwGetX11Window(window), nil, 1, 1);
+ Cursor cur = XCreatePixmapCursor(glfwGetX11Display(), pix, pix, &col, &col, 0, 0);
- XDefineCursor(glfwGetX11Display(), glfwGetX11Window(window), Cur);
- XFreeCursor(glfwGetX11Display(), Cur);
+ XDefineCursor(glfwGetX11Display(), glfwGetX11Window(window), cur);
+ XFreeCursor(glfwGetX11Display(), cur);
#else
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
#endif
@@ -622,17 +705,18 @@ void EndDrawing(void)
currentTime = GetTime();
drawTime = currentTime - previousTime;
previousTime = currentTime;
-
+
frameTime = updateTime + drawTime;
- double extraTime = 0.0;
-
- while (frameTime < targetTime)
+ // Wait for some milliseconds...
+ if (frameTime < targetTime)
{
- // Implement a delay
+ Wait((targetTime - frameTime)*1000.0f);
+
currentTime = GetTime();
- extraTime = currentTime - previousTime;
+ double extraTime = currentTime - previousTime;
previousTime = currentTime;
+
frameTime += extraTime;
}
}
@@ -744,8 +828,7 @@ void EndTextureMode(void)
rlDisableRenderTexture(); // Disable render target
// Set viewport to default framebuffer size (screen size)
- // TODO: consider possible viewport offsets
- rlViewport(0, 0, GetScreenWidth(), GetScreenHeight());
+ SetupViewport();
rlMatrixMode(RL_PROJECTION); // Switch to PROJECTION matrix
rlLoadIdentity(); // Reset current matrix (PROJECTION)
@@ -768,20 +851,16 @@ void SetTargetFPS(int fps)
}
// Returns current FPS
-float GetFPS(void)
+int GetFPS(void)
{
- return (float)(1.0/frameTime);
+ return (int)(1.0f/GetFrameTime());
}
// Returns time in seconds for one frame
float GetFrameTime(void)
{
- // As we are operate quite a lot with frameTime,
- // it could be no stable, so we round it before passing it around
- // NOTE: There are still problems with high framerates (>500fps)
- double roundedFrameTime = round(frameTime*10000)/10000.0;
-
- return (float)roundedFrameTime; // Time in seconds to run a frame
+ // NOTE: We round value to milliseconds
+ return (float)frameTime;
}
// Converts Color to float array and normalizes
@@ -987,14 +1066,14 @@ int StorageLoadValue(int position)
{
// Get file size
fseek(storageFile, 0, SEEK_END);
- int fileSize = ftell(storageFile); // Size in bytes
+ int fileSize = ftell(storageFile); // Size in bytes
rewind(storageFile);
if (fileSize < (position*4)) TraceLog(WARNING, "Storage position could not be found");
else
{
fseek(storageFile, (position*4), SEEK_SET);
- fread(&value, 1, 4, storageFile);
+ fread(&value, 4, 1, storageFile); // Read 1 element of 4 bytes size
}
fclose(storageFile);
@@ -1089,7 +1168,7 @@ Vector2 GetWorldToScreen(Vector3 position, Camera camera)
QuaternionTransform(&worldPos, matProj);
// Calculate normalized device coordinates (inverted y)
- Vector3 ndcPos = { worldPos.x/worldPos.w, -worldPos.y/worldPos.w, worldPos.z/worldPos.z };
+ Vector3 ndcPos = { worldPos.x/worldPos.w, -worldPos.y/worldPos.w, worldPos.z/worldPos.w };
// Calculate 2d screen position vector
Vector2 screenPosition = { (ndcPos.x + 1.0f)/2.0f*(float)GetScreenWidth(), (ndcPos.y + 1.0f)/2.0f*(float)GetScreenHeight() };
@@ -1128,7 +1207,7 @@ bool IsKeyDown(int key)
bool IsKeyReleased(int key)
{
bool released = false;
-
+
if ((currentKeyState[key] != previousKeyState[key]) && (currentKeyState[key] == 0)) released = true;
else released = false;
@@ -1163,7 +1242,7 @@ void SetExitKey(int key)
bool IsGamepadAvailable(int gamepad)
{
bool result = false;
-
+
#if !defined(PLATFORM_ANDROID)
if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad]) result = true;
#endif
@@ -1177,7 +1256,7 @@ bool IsGamepadName(int gamepad, const char *name)
bool result = false;
#if !defined(PLATFORM_ANDROID)
- const char *gamepadName = NULL;
+ const char *gamepadName = NULL;
if (gamepadReady[gamepad]) gamepadName = GetGamepadName(gamepad);
if ((name != NULL) && (gamepadName != NULL)) result = (strcmp(name, gamepadName) == 0);
@@ -1193,7 +1272,7 @@ const char *GetGamepadName(int gamepad)
if (gamepadReady[gamepad]) return glfwGetJoystickName(gamepad);
else return NULL;
#elif defined(PLATFORM_RPI)
- if (gamepadReady[gamepad]) ioctl(gamepadStream[gamepad], JSIOCGNAME(64), &gamepadName);
+ if (gamepadReady[gamepad]) ioctl(gamepadStream[gamepad], JSIOCGNAME(64), &gamepadName);
return gamepadName;
#else
@@ -1216,7 +1295,7 @@ int GetGamepadAxisCount(int gamepad)
float GetGamepadAxisMovement(int gamepad, int axis)
{
float value = 0;
-
+
#if !defined(PLATFORM_ANDROID)
if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (axis < MAX_GAMEPAD_AXIS)) value = gamepadAxisState[gamepad][axis];
#endif
@@ -1230,8 +1309,8 @@ bool IsGamepadButtonPressed(int gamepad, int button)
bool pressed = false;
#if !defined(PLATFORM_ANDROID)
- if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) &&
- (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) &&
+ if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) &&
+ (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) &&
(currentGamepadState[gamepad][button] == 1)) pressed = true;
#endif
@@ -1255,10 +1334,10 @@ bool IsGamepadButtonDown(int gamepad, int button)
bool IsGamepadButtonReleased(int gamepad, int button)
{
bool released = false;
-
+
#if !defined(PLATFORM_ANDROID)
- if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) &&
- (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) &&
+ if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) &&
+ (currentGamepadState[gamepad][button] != previousGamepadState[gamepad][button]) &&
(currentGamepadState[gamepad][button] == 0)) released = true;
#endif
@@ -1271,7 +1350,7 @@ bool IsGamepadButtonUp(int gamepad, int button)
bool result = false;
#if !defined(PLATFORM_ANDROID)
- if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) &&
+ if ((gamepad < MAX_GAMEPADS) && gamepadReady[gamepad] && (button < MAX_GAMEPAD_BUTTONS) &&
(currentGamepadState[gamepad][button] == 0)) result = true;
#endif
@@ -1479,13 +1558,23 @@ static void InitGraphicsDevice(int width, int height)
glfwDefaultWindowHints(); // Set default windows hints
- if (configFlags & FLAG_RESIZABLE_WINDOW)
+ // Check some Window creation flags
+ if (configFlags & FLAG_WINDOW_RESIZABLE) glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // Resizable window
+ else glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable
+
+ if (configFlags & FLAG_WINDOW_DECORATED) glfwWindowHint(GLFW_DECORATED, GL_TRUE); // Border and buttons on Window
+
+ if (configFlags & FLAG_WINDOW_TRANSPARENT)
{
- glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); // Resizable window
+ // TODO: Enable transparent window (not ready yet on GLFW 3.2)
+ }
+
+ if (configFlags & FLAG_MSAA_4X_HINT)
+ {
+ glfwWindowHint(GLFW_SAMPLES, 4); // Enables multisampling x4 (MSAA), default is 0
+ TraceLog(INFO, "Trying to enable MSAA x4");
}
- else glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable
- //glfwWindowHint(GLFW_DECORATED, GL_TRUE); // Border and buttons on Window
//glfwWindowHint(GLFW_RED_BITS, 8); // Framebuffer red color component bits
//glfwWindowHint(GLFW_DEPTH_BITS, 16); // Depthbuffer bits (24 by default)
//glfwWindowHint(GLFW_REFRESH_RATE, 0); // Refresh rate for fullscreen window
@@ -1494,13 +1583,7 @@ static void InitGraphicsDevice(int width, int height)
// NOTE: When asking for an OpenGL context version, most drivers provide highest supported version
// with forward compatibility to older OpenGL versions.
- // For example, if using OpenGL 1.1, driver can provide a 3.3 context fordward compatible.
-
- if (configFlags & FLAG_MSAA_4X_HINT)
- {
- glfwWindowHint(GLFW_SAMPLES, 4); // Enables multisampling x4 (MSAA), default is 0
- TraceLog(INFO, "Trying to enable MSAA x4");
- }
+ // For example, if using OpenGL 1.1, driver can provide a 4.3 context forward compatible.
// Check selection OpenGL version
if (rlGetVersion() == OPENGL_21)
@@ -1607,7 +1690,10 @@ static void InitGraphicsDevice(int width, int height)
#endif
glfwMakeContextCurrent(window);
- glfwSwapInterval(0); // Disable VSync by default
+
+ // Try to disable GPU V-Sync by default, set framerate using SetTargetFPS()
+ // NOTE: V-Sync can be enabled by graphic driver configuration
+ glfwSwapInterval(0);
#if defined(PLATFORM_DESKTOP)
// Load OpenGL 3.3 extensions
@@ -1615,9 +1701,8 @@ static void InitGraphicsDevice(int width, int height)
rlglLoadExtensions(glfwGetProcAddress);
#endif
- // Enables GPU v-sync, so frames are not limited to screen refresh rate (60Hz -> 60 FPS)
- // If not set, swap interval uses GPU v-sync configuration
- // Framerate can be setup using SetTargetFPS()
+ // Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
+ // NOTE: V-Sync can be enabled by graphic driver configuration
if (configFlags & FLAG_VSYNC_HINT)
{
glfwSwapInterval(1);
@@ -1776,19 +1861,8 @@ static void InitGraphicsDevice(int width, int height)
// NOTE: screenWidth and screenHeight not used, just stored as globals
rlglInit(screenWidth, screenHeight);
-#ifdef __APPLE__
- // Get framebuffer size of current window
- // NOTE: Required to handle HighDPI display correctly on OSX because framebuffer
- // is automatically reasized to adapt to new DPI.
- // When OS does that, it can be detected using GLFW3 callback: glfwSetFramebufferSizeCallback()
- int fbWidth, fbHeight;
- glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
- rlViewport(renderOffsetX/2, renderOffsetY/2, fbWidth - renderOffsetX, fbHeight - renderOffsetY);
-#else
- // Initialize screen viewport (area of the screen that you will actually draw to)
- // NOTE: Viewport must be recalculated if screen is resized
- rlViewport(renderOffsetX/2, renderOffsetY/2, renderWidth - renderOffsetX, renderHeight - renderOffsetY);
-#endif
+ // Setup default viewport
+ SetupViewport();
// Initialize internal projection and modelview matrices
// NOTE: Default to orthographic projection mode with top-left corner at (0,0)
@@ -1805,6 +1879,24 @@ static void InitGraphicsDevice(int width, int height)
#endif
}
+// Set viewport parameters
+static void SetupViewport(void)
+{
+#ifdef __APPLE__
+ // Get framebuffer size of current window
+ // NOTE: Required to handle HighDPI display correctly on OSX because framebuffer
+ // is automatically reasized to adapt to new DPI.
+ // When OS does that, it can be detected using GLFW3 callback: glfwSetFramebufferSizeCallback()
+ int fbWidth, fbHeight;
+ glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
+ rlViewport(renderOffsetX/2, renderOffsetY/2, fbWidth - renderOffsetX, fbHeight - renderOffsetY);
+#else
+ // Initialize screen viewport (area of the screen that you will actually draw to)
+ // NOTE: Viewport must be recalculated if screen is resized
+ rlViewport(renderOffsetX/2, renderOffsetY/2, renderWidth - renderOffsetX, renderHeight - renderOffsetY);
+#endif
+}
+
// Compute framebuffer size relative to screen size and display size
// NOTE: Global variables renderWidth/renderHeight and renderOffsetX/renderOffsetY can be modified
static void SetupFramebufferSize(int displayWidth, int displayHeight)
@@ -1912,6 +2004,34 @@ static double GetTime(void)
#endif
}
+// Wait for some milliseconds (stop program execution)
+static void Wait(float ms)
+{
+#define SUPPORT_BUSY_WAIT_LOOP
+#if defined(SUPPORT_BUSY_WAIT_LOOP)
+ double prevTime = GetTime();
+ double nextTime = 0.0;
+
+ // Busy wait loop
+ while ((nextTime - prevTime) < ms/1000.0f) nextTime = GetTime();
+#else
+ #if defined _WIN32
+ Sleep(ms);
+ #elif defined __linux || defined(PLATFORM_WEB)
+ struct timespec req = { 0 };
+ time_t sec = (int)(ms/1000.0f);
+ ms -= (sec*1000);
+ req.tv_sec = sec;
+ req.tv_nsec = ms*1000000L;
+
+ // NOTE: Use nanosleep() on Unix platforms... usleep() it's deprecated.
+ while (nanosleep(&req, &req) == -1) continue;
+ #elif defined __APPLE__
+ usleep(ms*1000.0f);
+ #endif
+#endif
+}
+
// Get one key state
static bool GetKeyStatus(int key)
{
@@ -1934,7 +2054,7 @@ static bool GetMouseButtonStatus(int button)
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
return glfwGetMouseButton(window, button);
#elif defined(PLATFORM_ANDROID)
- // TODO: Check for virtual mouse
+ // TODO: Check for virtual mouse?
return false;
#elif defined(PLATFORM_RPI)
// NOTE: Mouse buttons states are filled in PollInputEvents()
@@ -1948,10 +2068,10 @@ static void PollInputEvents(void)
// NOTE: Gestures update must be called every frame to reset gestures correctly
// because ProcessGestureEvent() is just called on an event, not every frame
UpdateGestures();
-
+
// Reset last key pressed registered
lastKeyPressed = -1;
-
+
#if !defined(PLATFORM_RPI)
// Reset last gamepad button/axis registered state
lastGamepadButtonPressed = -1;
@@ -1967,7 +2087,7 @@ static void PollInputEvents(void)
mousePosition.x = (float)mouseX;
mousePosition.y = (float)mouseY;
-
+
// Keyboard input polling (automatically managed by GLFW3 through callback)
// Register previous keys states
@@ -1980,8 +2100,6 @@ static void PollInputEvents(void)
currentMouseWheelY = 0;
#endif
-// NOTE: GLFW3 joystick functionality not available in web
-// TODO: Support joysticks using emscripten API
#if defined(PLATFORM_DESKTOP)
// Check if gamepads are ready
// NOTE: We do it here in case of disconection
@@ -1990,7 +2108,7 @@ static void PollInputEvents(void)
if (glfwJoystickPresent(i)) gamepadReady[i] = true;
else gamepadReady[i] = false;
}
-
+
// Register gamepads buttons events
for (int i = 0; i < MAX_GAMEPADS; i++)
{
@@ -1998,14 +2116,14 @@ static void PollInputEvents(void)
{
// Register previous gamepad states
for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) previousGamepadState[i][k] = currentGamepadState[i][k];
-
+
// Get current gamepad state
// NOTE: There is no callback available, so we get it manually
const unsigned char *buttons;
int buttonsCount;
buttons = glfwGetJoystickButtons(i, &buttonsCount);
-
+
for (int k = 0; (buttons != NULL) && (k < buttonsCount) && (buttonsCount < MAX_GAMEPAD_BUTTONS); k++)
{
if (buttons[k] == GLFW_PRESS)
@@ -2015,18 +2133,18 @@ static void PollInputEvents(void)
}
else currentGamepadState[i][k] = 0;
}
-
+
// Get current axis state
const float *axes;
int axisCount = 0;
axes = glfwGetJoystickAxes(i, &axisCount);
-
+
for (int k = 0; (axes != NULL) && (k < axisCount) && (k < MAX_GAMEPAD_AXIS); k++)
{
gamepadAxisState[i][k] = axes[k];
}
-
+
gamepadAxisCount = axisCount;
}
}
@@ -2034,6 +2152,47 @@ static void PollInputEvents(void)
glfwPollEvents(); // Register keyboard/mouse events (callbacks)... and window events!
#endif
+// Gamepad support using emscripten API
+// NOTE: GLFW3 joystick functionality not available in web
+#if defined(PLATFORM_WEB)
+ // Get number of gamepads connected
+ int numGamepads = emscripten_get_num_gamepads();
+
+ for (int i = 0; (i < numGamepads) && (i < MAX_GAMEPADS); i++)
+ {
+ // Register previous gamepad button states
+ for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) previousGamepadState[i][k] = currentGamepadState[i][k];
+
+ EmscriptenGamepadEvent gamepadState;
+
+ int result = emscripten_get_gamepad_status(i, &gamepadState);
+
+ if (result == EMSCRIPTEN_RESULT_SUCCESS)
+ {
+ // Register buttons data for every connected gamepad
+ for (int j = 0; (j < gamepadState.numButtons) && (j < MAX_GAMEPAD_BUTTONS); j++)
+ {
+ if (gamepadState.digitalButton[j] == 1)
+ {
+ currentGamepadState[i][j] = 1;
+ lastGamepadButtonPressed = j;
+ }
+ else currentGamepadState[i][j] = 0;
+
+ //printf("Gamepad %d, button %d: Digital: %d, Analog: %g\n", gamepadState.index, j, gamepadState.digitalButton[j], gamepadState.analogButton[j]);
+ }
+
+ // Register axis data for every connected gamepad
+ for (int j = 0; (j < gamepadState.numAxes) && (j < MAX_GAMEPAD_AXIS); j++)
+ {
+ gamepadAxisState[i][j] = gamepadState.axis[j];
+ }
+
+ gamepadAxisCount = gamepadState.numAxes;
+ }
+ }
+#endif
+
#if defined(PLATFORM_ANDROID)
// Register previous keys states
// NOTE: Android supports up to 260 keys
@@ -2091,7 +2250,7 @@ static void TakeScreenshot(void)
sprintf(buffer, "screenshot%03i.png", shotNum);
// Save image as PNG
- WritePNG(buffer, imgData, renderWidth, renderHeight, 4);
+ SavePNG(buffer, imgData, renderWidth, renderHeight, 4);
free(imgData);
@@ -2301,7 +2460,7 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
// Init graphics device (display device and OpenGL context)
InitGraphicsDevice(screenWidth, screenHeight);
- #if defined(RL_LOAD_DEFAULT_FONT)
+ #if defined(LOAD_DEFAULT_FONT)
// Load default font
// NOTE: External function (defined in module: text)
LoadDefaultFont();
@@ -2480,6 +2639,8 @@ static int32_t AndroidInputCallback(struct android_app *app, AInputEvent *event)
#endif
#if defined(PLATFORM_WEB)
+
+// Register fullscreen change events
static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const EmscriptenFullscreenChangeEvent *e, void *userData)
{
//isFullscreen: int e->isFullscreen
@@ -2503,7 +2664,7 @@ static EM_BOOL EmscriptenFullscreenChangeCallback(int eventType, const Emscripte
return 0;
}
-// Web: Get input events
+// Register touch input events
static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
{
/*
@@ -2567,6 +2728,26 @@ static EM_BOOL EmscriptenInputCallback(int eventType, const EmscriptenTouchEvent
return 1;
}
+
+// Register connected/disconnected gamepads events
+static EM_BOOL EmscriptenGamepadCallback(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)
+{
+ /*
+ printf("%s: timeStamp: %g, connected: %d, index: %ld, numAxes: %d, numButtons: %d, id: \"%s\", mapping: \"%s\"\n",
+ eventType != 0 ? emscripten_event_type_to_string(eventType) : "Gamepad state",
+ gamepadEvent->timestamp, gamepadEvent->connected, gamepadEvent->index, gamepadEvent->numAxes, gamepadEvent->numButtons, gamepadEvent->id, gamepadEvent->mapping);
+
+ for(int i = 0; i < gamepadEvent->numAxes; ++i) printf("Axis %d: %g\n", i, gamepadEvent->axis[i]);
+ for(int i = 0; i < gamepadEvent->numButtons; ++i) printf("Button %d: Digital: %d, Analog: %g\n", i, gamepadEvent->digitalButton[i], gamepadEvent->analogButton[i]);
+ */
+
+ if ((gamepadEvent->connected) && (gamepadEvent->index < MAX_GAMEPADS)) gamepadReady[gamepadEvent->index] = true;
+ else gamepadReady[gamepadEvent->index] = false;
+
+ // TODO: Test gamepadEvent->index
+
+ return 0;
+}
#endif
#if defined(PLATFORM_RPI)
@@ -2748,7 +2929,8 @@ static void InitMouse(void)
// if too much time passes between reads, queue gets full and new events override older ones...
static void *MouseThread(void *arg)
{
- const unsigned char XSIGN = 1<<4, YSIGN = 1<<5;
+ const unsigned char XSIGN = (1 << 4);
+ const unsigned char YSIGN = (1 << 5);
typedef struct {
char buttons;
@@ -2803,6 +2985,110 @@ static void *MouseThread(void *arg)
return NULL;
}
+// Touch initialization (including touch thread)
+static void InitTouch(void)
+{
+ if ((touchStream = open(DEFAULT_TOUCH_DEV, O_RDONLY|O_NONBLOCK)) < 0)
+ {
+ TraceLog(WARNING, "Touch device could not be opened, no touchscreen available");
+ }
+ else
+ {
+ touchReady = true;
+
+ int error = pthread_create(&touchThreadId, NULL, &TouchThread, NULL);
+
+ if (error != 0) TraceLog(WARNING, "Error creating touch input event thread");
+ else TraceLog(INFO, "Touch device initialized successfully");
+ }
+}
+
+// Touch reading thread.
+// This reads from a Virtual Input Event /dev/input/event4 which is
+// created by the ts_uinput daemon. This takes, filters and scales
+// raw input from the Touchscreen (which appears in /dev/input/event3)
+// based on the Calibration data referenced by tslib.
+static void *TouchThread(void *arg)
+{
+ struct input_event ev;
+ GestureEvent gestureEvent;
+
+ while (!windowShouldClose)
+ {
+ if (read(touchStream, &ev, sizeof(ev)) == (int)sizeof(ev))
+ {
+ // if pressure > 0 then simulate left mouse button click
+ if (ev.type == EV_ABS && ev.code == 24 && ev.value == 0 && currentMouseState[0] == 1)
+ {
+ currentMouseState[0] = 0;
+ gestureEvent.touchAction = TOUCH_UP;
+ gestureEvent.pointCount = 1;
+ gestureEvent.pointerId[0] = 0;
+ gestureEvent.pointerId[1] = 1;
+ gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y };
+ gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y };
+ gestureEvent.position[0].x /= (float)GetScreenWidth();
+ gestureEvent.position[0].y /= (float)GetScreenHeight();
+ gestureEvent.position[1].x /= (float)GetScreenWidth();
+ gestureEvent.position[1].y /= (float)GetScreenHeight();
+ ProcessGestureEvent(gestureEvent);
+ }
+ if (ev.type == EV_ABS && ev.code == 24 && ev.value > 0 && currentMouseState[0] == 0)
+ {
+ currentMouseState[0] = 1;
+ gestureEvent.touchAction = TOUCH_DOWN;
+ gestureEvent.pointCount = 1;
+ gestureEvent.pointerId[0] = 0;
+ gestureEvent.pointerId[1] = 1;
+ gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y };
+ gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y };
+ gestureEvent.position[0].x /= (float)GetScreenWidth();
+ gestureEvent.position[0].y /= (float)GetScreenHeight();
+ gestureEvent.position[1].x /= (float)GetScreenWidth();
+ gestureEvent.position[1].y /= (float)GetScreenHeight();
+ ProcessGestureEvent(gestureEvent);
+ }
+ // x & y values supplied by event4 have been scaled & de-jittered using tslib calibration data
+ if (ev.type == EV_ABS && ev.code == 0)
+ {
+ mousePosition.x = ev.value;
+ if (mousePosition.x < 0) mousePosition.x = 0;
+ if (mousePosition.x > screenWidth) mousePosition.x = screenWidth;
+ gestureEvent.touchAction = TOUCH_MOVE;
+ gestureEvent.pointCount = 1;
+ gestureEvent.pointerId[0] = 0;
+ gestureEvent.pointerId[1] = 1;
+ gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y };
+ gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y };
+ gestureEvent.position[0].x /= (float)GetScreenWidth();
+ gestureEvent.position[0].y /= (float)GetScreenHeight();
+ gestureEvent.position[1].x /= (float)GetScreenWidth();
+ gestureEvent.position[1].y /= (float)GetScreenHeight();
+ ProcessGestureEvent(gestureEvent);
+ }
+ if (ev.type == EV_ABS && ev.code == 1)
+ {
+ mousePosition.y = ev.value;
+ if (mousePosition.y < 0) mousePosition.y = 0;
+ if (mousePosition.y > screenHeight) mousePosition.y = screenHeight;
+ gestureEvent.touchAction = TOUCH_MOVE;
+ gestureEvent.pointCount = 1;
+ gestureEvent.pointerId[0] = 0;
+ gestureEvent.pointerId[1] = 1;
+ gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y };
+ gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y };
+ gestureEvent.position[0].x /= (float)GetScreenWidth();
+ gestureEvent.position[0].y /= (float)GetScreenHeight();
+ gestureEvent.position[1].x /= (float)GetScreenWidth();
+ gestureEvent.position[1].y /= (float)GetScreenHeight();
+ ProcessGestureEvent(gestureEvent);
+ }
+
+ }
+ }
+ return NULL;
+}
+
// Init gamepad system
static void InitGamepad(void)
{
@@ -2867,7 +3153,7 @@ static void *GamepadThread(void *arg)
{
// 1 - button pressed, 0 - button released
currentGamepadState[i][gamepadEvent.number] = (int)gamepadEvent.value;
-
+
if ((int)gamepadEvent.value == 1) lastGamepadButtonPressed = gamepadEvent.number;
else lastGamepadButtonPressed = -1;
}
diff --git a/src/external/dr_flac.h b/src/external/dr_flac.h
index d7b66f20..d2bebea5 100644
--- a/src/external/dr_flac.h
+++ b/src/external/dr_flac.h
@@ -1,5 +1,5 @@
// FLAC audio decoder. Public domain. See "unlicense" statement at the end of this file.
-// dr_flac - v0.4 - 2016-09-29
+// dr_flac - v0.4c - 2016-12-26
//
// David Reid - [email protected]
@@ -105,18 +105,32 @@
#include <stdint.h>
#include <stddef.h>
-#ifndef DR_BOOL_DEFINED
-#define DR_BOOL_DEFINED
-#ifdef _WIN32
-typedef char drBool8;
-typedef int drBool32;
+#ifndef DR_SIZED_TYPES_DEFINED
+#define DR_SIZED_TYPES_DEFINED
+#if defined(_MSC_VER) && _MSC_VER < 1600
+typedef signed char dr_int8;
+typedef unsigned char dr_uint8;
+typedef signed short dr_int16;
+typedef unsigned short dr_uint16;
+typedef signed int dr_int32;
+typedef unsigned int dr_uint32;
+typedef signed __int64 dr_int64;
+typedef unsigned __int64 dr_uint64;
#else
#include <stdint.h>
-typedef int8_t drBool8;
-typedef int32_t drBool32;
+typedef int8_t dr_int8;
+typedef uint8_t dr_uint8;
+typedef int16_t dr_int16;
+typedef uint16_t dr_uint16;
+typedef int32_t dr_int32;
+typedef uint32_t dr_uint32;
+typedef int64_t dr_int64;
+typedef uint64_t dr_uint64;
#endif
-#define DR_TRUE 1
-#define DR_FALSE 0
+typedef dr_int8 dr_bool8;
+typedef dr_int32 dr_bool32;
+#define DR_TRUE 1
+#define DR_FALSE 0
#endif
// As data is read from the client it is placed into an internal buffer for fast access. This controls the
@@ -262,7 +276,7 @@ typedef struct
{
char catalog[128];
uint64_t leadInSampleCount;
- drBool32 isCD;
+ dr_bool32 isCD;
uint8_t trackCount;
const uint8_t* pTrackData;
} cuesheet;
@@ -305,7 +319,7 @@ typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t by
//
// The offset will never be negative. Whether or not it is relative to the beginning or current position is determined
// by the "origin" parameter which will be either drflac_seek_origin_start or drflac_seek_origin_current.
-typedef drBool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
+typedef dr_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
// Callback for when a metadata block is read.
//
@@ -546,6 +560,10 @@ void drflac_close(drflac* pFlac);
// seeked.
uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* pBufferOut);
+// Same as drflac_read_s32(), except outputs samples as 16-bit integer PCM rather than 32-bit. Note
+// that this is lossey.
+uint64_t drflac_read_s16(drflac* pFlac, uint64_t samplesToRead, int16_t* pBufferOut);
+
// Seeks to the sample at the given index.
//
// pFlac [in] The decoder.
@@ -558,7 +576,7 @@ uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* pBuffer
//
// When seeking, you will likely want to ensure it's rounded to a multiple of the channel count. You can do this with
// something like drflac_seek_to_sample(pFlac, (mySampleIndex + (mySampleIndex % pFlac->channels)))
-drBool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex);
+dr_bool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex);
@@ -607,14 +625,17 @@ drflac* drflac_open_memory_with_metadata(const void* data, size_t dataSize, drfl
//
// Do not call this function on a broadcast type of stream (like internet radio streams and whatnot).
int32_t* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
+int16_t* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
#ifndef DR_FLAC_NO_STDIO
// Same as drflac_open_and_decode_s32() except opens the decoder from a file.
int32_t* drflac_open_and_decode_file_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
+int16_t* drflac_open_and_decode_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
#endif
// Same as drflac_open_and_decode_s32() except opens the decoder from a block of memory.
int32_t* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
+int16_t* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount);
// Frees data returned by drflac_open_and_decode_*().
void drflac_free(void* pSampleDataReturnedByOpenAndDecode);
@@ -684,7 +705,7 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, ui
//// Endian Management ////
-static DRFLAC_INLINE drBool32 drflac__is_little_endian()
+static DRFLAC_INLINE dr_bool32 drflac__is_little_endian()
{
int n = 1;
return (*(char*)&n) == 1;
@@ -817,7 +838,7 @@ static DRFLAC_INLINE uint32_t drflac__le2host_32(uint32_t n)
#define DRFLAC_CACHE_L2_LINE_COUNT(bs) (DRFLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0]))
#define DRFLAC_CACHE_L2_LINES_REMAINING(bs) (DRFLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line)
-static DRFLAC_INLINE drBool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs)
+static DRFLAC_INLINE dr_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs)
{
// Fast path. Try loading straight from L2.
if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
@@ -871,7 +892,7 @@ static DRFLAC_INLINE drBool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs)
}
}
-static drBool32 drflac__reload_cache(drflac_bs* bs)
+static dr_bool32 drflac__reload_cache(drflac_bs* bs)
{
// Fast path. Try just moving the next value in the L2 cache to the L1 cache.
if (drflac__reload_l1_cache_from_l2(bs)) {
@@ -907,7 +928,7 @@ static void drflac__reset_cache(drflac_bs* bs)
bs->unalignedCache = 0;
}
-static drBool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek)
+static dr_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek)
{
if (bitsToSeek <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
bs->consumedBits += bitsToSeek;
@@ -958,7 +979,7 @@ static drBool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek)
}
}
-static drBool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, uint32_t* pResultOut)
+static dr_bool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, uint32_t* pResultOut)
{
assert(bs != NULL);
assert(pResultOut != NULL);
@@ -999,7 +1020,7 @@ static drBool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, uint32
}
}
-static drBool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, int32_t* pResult)
+static dr_bool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, int32_t* pResult)
{
assert(bs != NULL);
assert(pResult != NULL);
@@ -1018,7 +1039,7 @@ static drBool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, int32_t
return DR_TRUE;
}
-static drBool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, uint64_t* pResultOut)
+static dr_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, uint64_t* pResultOut)
{
assert(bitCount <= 64);
assert(bitCount > 32);
@@ -1039,7 +1060,7 @@ static drBool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, uint64
// Function below is unused, but leaving it here in case I need to quickly add it again.
#if 0
-static drBool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, int64_t* pResultOut)
+static dr_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, int64_t* pResultOut)
{
assert(bitCount <= 64);
@@ -1056,7 +1077,7 @@ static drBool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, int64_t
}
#endif
-static drBool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, uint16_t* pResult)
+static dr_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, uint16_t* pResult)
{
assert(bs != NULL);
assert(pResult != NULL);
@@ -1072,7 +1093,7 @@ static drBool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, uint16
return DR_TRUE;
}
-static drBool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, int16_t* pResult)
+static dr_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, int16_t* pResult)
{
assert(bs != NULL);
assert(pResult != NULL);
@@ -1088,7 +1109,7 @@ static drBool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, int16_t
return DR_TRUE;
}
-static drBool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, uint8_t* pResult)
+static dr_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, uint8_t* pResult)
{
assert(bs != NULL);
assert(pResult != NULL);
@@ -1104,7 +1125,7 @@ static drBool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, uint8_t
return DR_TRUE;
}
-static drBool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, int8_t* pResult)
+static dr_bool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, int8_t* pResult)
{
assert(bs != NULL);
assert(pResult != NULL);
@@ -1121,7 +1142,7 @@ static drBool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, int8_t*
}
-static inline drBool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut)
+static inline dr_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut)
{
unsigned int zeroCounter = 0;
while (bs->cache == 0) {
@@ -1169,7 +1190,7 @@ static inline drBool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned in
-static drBool32 drflac__seek_to_byte(drflac_bs* bs, uint64_t offsetFromStart)
+static dr_bool32 drflac__seek_to_byte(drflac_bs* bs, uint64_t offsetFromStart)
{
assert(bs != NULL);
assert(offsetFromStart > 0);
@@ -1214,7 +1235,7 @@ static drBool32 drflac__seek_to_byte(drflac_bs* bs, uint64_t offsetFromStart)
}
-static drBool32 drflac__read_utf8_coded_number(drflac_bs* bs, uint64_t* pNumberOut)
+static dr_bool32 drflac__read_utf8_coded_number(drflac_bs* bs, uint64_t* pNumberOut)
{
assert(bs != NULL);
assert(pNumberOut != NULL);
@@ -1267,7 +1288,7 @@ static drBool32 drflac__read_utf8_coded_number(drflac_bs* bs, uint64_t* pNumberO
-static DRFLAC_INLINE drBool32 drflac__read_and_seek_rice(drflac_bs* bs, uint8_t m)
+static DRFLAC_INLINE dr_bool32 drflac__read_and_seek_rice(drflac_bs* bs, uint8_t m)
{
unsigned int unused;
if (!drflac__seek_past_next_set_bit(bs, &unused)) {
@@ -1520,7 +1541,7 @@ static DRFLAC_INLINE int32_t drflac__calculate_prediction_64(uint32_t order, int
// iteration. The prediction is done at the end, and there's an annoying branch I'd like to avoid so the main function is defined
// as a #define - sue me!
#define DRFLAC__DECODE_SAMPLES_WITH_RESIDULE__RICE__PROC(funcName, predictionFunc) \
-static drBool32 funcName (drflac_bs* bs, uint32_t count, uint8_t riceParam, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pSamplesOut) \
+static dr_bool32 funcName (drflac_bs* bs, uint32_t count, uint8_t riceParam, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pSamplesOut) \
{ \
assert(bs != NULL); \
assert(count > 0); \
@@ -1630,7 +1651,7 @@ DRFLAC__DECODE_SAMPLES_WITH_RESIDULE__RICE__PROC(drflac__decode_samples_with_res
// Reads and seeks past a string of residual values as Rice codes. The decoder should be sitting on the first bit of the Rice codes.
-static drBool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, uint32_t count, uint8_t riceParam)
+static dr_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, uint32_t count, uint8_t riceParam)
{
assert(bs != NULL);
assert(count > 0);
@@ -1644,7 +1665,7 @@ static drBool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, uint32_t cou
return DR_TRUE;
}
-static drBool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, uint32_t bitsPerSample, uint32_t count, uint8_t unencodedBitsPerSample, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pSamplesOut)
+static dr_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, uint32_t bitsPerSample, uint32_t count, uint8_t unencodedBitsPerSample, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pSamplesOut)
{
assert(bs != NULL);
assert(count > 0);
@@ -1671,7 +1692,7 @@ static drBool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, u
// Reads and decodes the residual for the sub-frame the decoder is currently sitting on. This function should be called
// when the decoder is sitting at the very start of the RESIDUAL block. The first <order> residuals will be ignored. The
// <blockSize> and <order> parameters are used to determine how many residual values need to be decoded.
-static drBool32 drflac__decode_samples_with_residual(drflac_bs* bs, uint32_t bitsPerSample, uint32_t blockSize, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pDecodedSamples)
+static dr_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, uint32_t bitsPerSample, uint32_t blockSize, uint32_t order, int32_t shift, const int16_t* coefficients, int32_t* pDecodedSamples)
{
assert(bs != NULL);
assert(blockSize != 0);
@@ -1755,7 +1776,7 @@ static drBool32 drflac__decode_samples_with_residual(drflac_bs* bs, uint32_t bit
// Reads and seeks past the residual for the sub-frame the decoder is currently sitting on. This function should be called
// when the decoder is sitting at the very start of the RESIDUAL block. The first <order> residuals will be set to 0. The
// <blockSize> and <order> parameters are used to determine how many residual values need to be decoded.
-static drBool32 drflac__read_and_seek_residual(drflac_bs* bs, uint32_t blockSize, uint32_t order)
+static dr_bool32 drflac__read_and_seek_residual(drflac_bs* bs, uint32_t blockSize, uint32_t order)
{
assert(bs != NULL);
assert(blockSize != 0);
@@ -1823,7 +1844,7 @@ static drBool32 drflac__read_and_seek_residual(drflac_bs* bs, uint32_t blockSize
}
-static drBool32 drflac__decode_samples__constant(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, int32_t* pDecodedSamples)
+static dr_bool32 drflac__decode_samples__constant(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, int32_t* pDecodedSamples)
{
// Only a single sample needs to be decoded here.
int32_t sample;
@@ -1840,7 +1861,7 @@ static drBool32 drflac__decode_samples__constant(drflac_bs* bs, uint32_t blockSi
return DR_TRUE;
}
-static drBool32 drflac__decode_samples__verbatim(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, int32_t* pDecodedSamples)
+static dr_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, int32_t* pDecodedSamples)
{
for (uint32_t i = 0; i < blockSize; ++i) {
int32_t sample;
@@ -1854,7 +1875,7 @@ static drBool32 drflac__decode_samples__verbatim(drflac_bs* bs, uint32_t blockSi
return DR_TRUE;
}
-static drBool32 drflac__decode_samples__fixed(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, uint8_t lpcOrder, int32_t* pDecodedSamples)
+static dr_bool32 drflac__decode_samples__fixed(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, uint8_t lpcOrder, int32_t* pDecodedSamples)
{
short lpcCoefficientsTable[5][4] = {
{0, 0, 0, 0},
@@ -1882,7 +1903,7 @@ static drBool32 drflac__decode_samples__fixed(drflac_bs* bs, uint32_t blockSize,
return DR_TRUE;
}
-static drBool32 drflac__decode_samples__lpc(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, uint8_t lpcOrder, int32_t* pDecodedSamples)
+static dr_bool32 drflac__decode_samples__lpc(drflac_bs* bs, uint32_t blockSize, uint32_t bitsPerSample, uint8_t lpcOrder, int32_t* pDecodedSamples)
{
// Warm up samples.
for (uint8_t i = 0; i < lpcOrder; ++i) {
@@ -1925,7 +1946,7 @@ static drBool32 drflac__decode_samples__lpc(drflac_bs* bs, uint32_t blockSize, u
}
-static drBool32 drflac__read_next_frame_header(drflac_bs* bs, uint8_t streaminfoBitsPerSample, drflac_frame_header* header)
+static dr_bool32 drflac__read_next_frame_header(drflac_bs* bs, uint8_t streaminfoBitsPerSample, drflac_frame_header* header)
{
assert(bs != NULL);
assert(header != NULL);
@@ -1983,7 +2004,7 @@ static drBool32 drflac__read_next_frame_header(drflac_bs* bs, uint8_t streaminfo
}
- drBool32 isVariableBlockSize = blockingStrategy == 1;
+ dr_bool32 isVariableBlockSize = blockingStrategy == 1;
if (isVariableBlockSize) {
uint64_t sampleNumber;
if (!drflac__read_utf8_coded_number(bs, &sampleNumber)) {
@@ -2055,7 +2076,7 @@ static drBool32 drflac__read_next_frame_header(drflac_bs* bs, uint8_t streaminfo
return DR_TRUE;
}
-static drBool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe)
+static dr_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe)
{
uint8_t header;
if (!drflac__read_uint8(bs, 8, &header)) {
@@ -2105,7 +2126,7 @@ static drBool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSu
return DR_TRUE;
}
-static drBool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, int32_t* pDecodedSamplesOut)
+static dr_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, int32_t* pDecodedSamplesOut)
{
assert(bs != NULL);
assert(frame != NULL);
@@ -2155,7 +2176,7 @@ static drBool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int
return DR_TRUE;
}
-static drBool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex)
+static dr_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex)
{
assert(bs != NULL);
assert(frame != NULL);
@@ -2249,7 +2270,7 @@ static DRFLAC_INLINE uint8_t drflac__get_channel_count_from_channel_assignment(i
return lookup[channelAssignment];
}
-static drBool32 drflac__decode_frame(drflac* pFlac)
+static dr_bool32 drflac__decode_frame(drflac* pFlac)
{
// This function should be called while the stream is sitting on the first byte after the frame header.
memset(pFlac->currentFrame.subframes, 0, sizeof(pFlac->currentFrame.subframes));
@@ -2273,7 +2294,7 @@ static drBool32 drflac__decode_frame(drflac* pFlac)
return DR_TRUE;
}
-static drBool32 drflac__seek_frame(drflac* pFlac)
+static dr_bool32 drflac__seek_frame(drflac* pFlac)
{
int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFrame.header.channelAssignment);
for (int i = 0; i < channelCount; ++i)
@@ -2287,7 +2308,7 @@ static drBool32 drflac__seek_frame(drflac* pFlac)
return drflac__seek_bits(&pFlac->bs, (DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7) + 16);
}
-static drBool32 drflac__read_and_decode_next_frame(drflac* pFlac)
+static dr_bool32 drflac__read_and_decode_next_frame(drflac* pFlac)
{
assert(pFlac != NULL);
@@ -2324,24 +2345,24 @@ static void drflac__get_current_frame_sample_range(drflac* pFlac, uint64_t* pFir
}
}
-static drBool32 drflac__seek_to_first_frame(drflac* pFlac)
+static dr_bool32 drflac__seek_to_first_frame(drflac* pFlac)
{
assert(pFlac != NULL);
- drBool32 result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos);
+ dr_bool32 result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFramePos);
memset(&pFlac->currentFrame, 0, sizeof(pFlac->currentFrame));
return result;
}
-static DRFLAC_INLINE drBool32 drflac__seek_to_next_frame(drflac* pFlac)
+static DRFLAC_INLINE dr_bool32 drflac__seek_to_next_frame(drflac* pFlac)
{
// This function should only ever be called while the decoder is sitting on the first byte past the FRAME_HEADER section.
assert(pFlac != NULL);
return drflac__seek_frame(pFlac);
}
-static drBool32 drflac__seek_to_frame_containing_sample(drflac* pFlac, uint64_t sampleIndex)
+static dr_bool32 drflac__seek_to_frame_containing_sample(drflac* pFlac, uint64_t sampleIndex)
{
assert(pFlac != NULL);
@@ -2372,7 +2393,7 @@ static drBool32 drflac__seek_to_frame_containing_sample(drflac* pFlac, uint64_t
return DR_TRUE;
}
-static drBool32 drflac__seek_to_sample__brute_force(drflac* pFlac, uint64_t sampleIndex)
+static dr_bool32 drflac__seek_to_sample__brute_force(drflac* pFlac, uint64_t sampleIndex)
{
if (!drflac__seek_to_frame_containing_sample(pFlac, sampleIndex)) {
return DR_FALSE;
@@ -2398,7 +2419,7 @@ static drBool32 drflac__seek_to_sample__brute_force(drflac* pFlac, uint64_t samp
}
-static drBool32 drflac__seek_to_sample__seek_table(drflac* pFlac, uint64_t sampleIndex)
+static dr_bool32 drflac__seek_to_sample__seek_table(drflac* pFlac, uint64_t sampleIndex)
{
assert(pFlac != NULL);
@@ -2508,7 +2529,7 @@ typedef struct
uint64_t totalSampleCount;
uint16_t maxBlockSize;
uint64_t runningFilePos;
- drBool32 hasMetadataBlocks;
+ dr_bool32 hasMetadataBlocks;
#ifndef DR_FLAC_NO_OGG
uint32_t oggSerial;
@@ -2525,7 +2546,7 @@ static DRFLAC_INLINE void drflac__decode_block_header(uint32_t blockHeader, uint
*blockSize = (blockHeader & 0xFFFFFF);
}
-static DRFLAC_INLINE drBool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, uint8_t* isLastBlock, uint8_t* blockType, uint32_t* blockSize)
+static DRFLAC_INLINE dr_bool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, uint8_t* isLastBlock, uint8_t* blockType, uint32_t* blockSize)
{
uint32_t blockHeader;
if (onRead(pUserData, &blockHeader, 4) != 4) {
@@ -2536,7 +2557,7 @@ static DRFLAC_INLINE drBool32 drflac__read_and_decode_block_header(drflac_read_p
return DR_TRUE;
}
-drBool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo)
+dr_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo)
{
// min/max block size.
uint32_t blockSizes;
@@ -2579,7 +2600,7 @@ drBool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drfla
return DR_TRUE;
}
-drBool32 drflac__read_and_decode_metadata(drflac* pFlac)
+dr_bool32 drflac__read_and_decode_metadata(drflac* pFlac)
{
assert(pFlac != NULL);
@@ -2823,7 +2844,7 @@ drBool32 drflac__read_and_decode_metadata(drflac* pFlac)
return DR_TRUE;
}
-drBool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
+dr_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
{
(void)onSeek;
@@ -2869,7 +2890,7 @@ drBool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc
}
#ifndef DR_FLAC_NO_OGG
-static DRFLAC_INLINE drBool32 drflac_ogg__is_capture_pattern(uint8_t pattern[4])
+static DRFLAC_INLINE dr_bool32 drflac_ogg__is_capture_pattern(uint8_t pattern[4])
{
return pattern[0] == 'O' && pattern[1] == 'g' && pattern[2] == 'g' && pattern[3] == 'S';
}
@@ -2889,7 +2910,7 @@ static DRFLAC_INLINE uint32_t drflac_ogg__get_page_body_size(drflac_ogg_page_hea
return pageBodySize;
}
-drBool32 drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, uint32_t* pHeaderSize)
+dr_bool32 drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, uint32_t* pHeaderSize)
{
if (onRead(pUserData, &pHeader->structureVersion, 1) != 1 || pHeader->structureVersion != 0) {
return DR_FALSE; // Unknown structure version. Possibly corrupt stream.
@@ -2920,7 +2941,7 @@ drBool32 drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onR
return DR_TRUE;
}
-drBool32 drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, uint32_t* pHeaderSize)
+dr_bool32 drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, uint32_t* pHeaderSize)
{
uint8_t id[4];
if (onRead(pUserData, id, 4) != 4) {
@@ -2961,7 +2982,7 @@ static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut,
return bytesActuallyRead;
}
-static drBool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, uint64_t offset, drflac_seek_origin origin)
+static dr_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, uint64_t offset, drflac_seek_origin origin)
{
if (origin == drflac_seek_origin_start)
{
@@ -3000,7 +3021,7 @@ static drBool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, uint64_t offset
}
}
-static drBool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs)
+static dr_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs)
{
drflac_ogg_page_header header;
for (;;)
@@ -3049,12 +3070,12 @@ static uint8_t drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, uint
return iSeg;
}
-static drBool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
+static dr_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
{
// The current packet ends when we get to the segment with a lacing value of < 255 which is not at the end of a page.
for (;;) // <-- Loop over pages.
{
- drBool32 atEndOfPage = DR_FALSE;
+ dr_bool32 atEndOfPage = DR_FALSE;
uint8_t bytesRemainingInSeg;
uint8_t iFirstSeg = drflac_oggbs__get_current_segment_index(oggbs, &bytesRemainingInSeg);
@@ -3099,7 +3120,7 @@ static drBool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
}
}
-static drBool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs)
+static dr_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs)
{
// The bitstream should be sitting on the first byte just after the header of the frame.
@@ -3148,7 +3169,7 @@ static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytes
return bytesRead;
}
-static drBool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin)
+static dr_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin)
{
drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
assert(oggbs != NULL);
@@ -3204,7 +3225,7 @@ static drBool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_ori
return DR_TRUE;
}
-drBool32 drflac_ogg__seek_to_sample(drflac* pFlac, uint64_t sample)
+dr_bool32 drflac_ogg__seek_to_sample(drflac* pFlac, uint64_t sample)
{
drflac_oggbs* oggbs = (drflac_oggbs*)(((int32_t*)pFlac->pExtraData) + pFlac->maxBlockSize*pFlac->channels);
@@ -3327,7 +3348,7 @@ drBool32 drflac_ogg__seek_to_sample(drflac* pFlac, uint64_t sample)
}
-drBool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
+dr_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
{
// Pre: The bit stream should be sitting just past the 4-byte OggS capture pattern.
@@ -3491,7 +3512,7 @@ drBool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onR
}
#endif
-drBool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
+dr_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD)
{
if (pInit == NULL || onRead == NULL || onSeek == NULL) {
return DR_FALSE;
@@ -3610,7 +3631,7 @@ static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t byt
return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData);
}
-static drBool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
+static dr_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
{
assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start));
@@ -3651,7 +3672,7 @@ static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t byt
return (size_t)bytesRead;
}
-static drBool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
+static dr_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
{
assert(offset > 0 || (offset == 0 && origin == drflac_seek_origin_start));
@@ -3727,7 +3748,7 @@ static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t by
return bytesToRead;
}
-static drBool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin)
+static dr_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin)
{
drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
assert(memoryStream != NULL);
@@ -4107,7 +4128,32 @@ uint64_t drflac_read_s32(drflac* pFlac, uint64_t samplesToRead, int32_t* bufferO
return samplesRead;
}
-drBool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex)
+uint64_t drflac_read_s16(drflac* pFlac, uint64_t samplesToRead, int16_t* pBufferOut)
+{
+ // This reads samples in 2 passes and can probably be optimized.
+ uint64_t samplesRead = 0;
+
+ while (samplesToRead > 0) {
+ int32_t samples32[4096];
+ uint64_t samplesJustRead = drflac_read_s32(pFlac, samplesToRead > 4096 ? 4096 : samplesToRead, samples32);
+ if (samplesJustRead == 0) {
+ break; // Reached the end.
+ }
+
+ // s32 -> s16
+ for (uint64_t i = 0; i < samplesJustRead; ++i) {
+ pBufferOut[i] = (int16_t)(samples32[i] >> 16);
+ }
+
+ samplesRead += samplesJustRead;
+ samplesToRead -= samplesJustRead;
+ pBufferOut += samplesJustRead;
+ }
+
+ return samplesRead;
+}
+
+dr_bool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex)
{
if (pFlac == NULL) {
return DR_FALSE;
@@ -4147,7 +4193,7 @@ drBool32 drflac_seek_to_sample(drflac* pFlac, uint64_t sampleIndex)
//// High Level APIs ////
-int32_t* drflac__full_decode_and_close(drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, uint64_t* totalSampleCountOut)
+int32_t* drflac__full_decode_and_close_s32(drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, uint64_t* totalSampleCountOut)
{
assert(pFlac != NULL);
@@ -4218,6 +4264,77 @@ on_error:
return NULL;
}
+int16_t* drflac__full_decode_and_close_s16(drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, uint64_t* totalSampleCountOut)
+{
+ assert(pFlac != NULL);
+
+ int16_t* pSampleData = NULL;
+ uint64_t totalSampleCount = pFlac->totalSampleCount;
+
+ if (totalSampleCount == 0)
+ {
+ int16_t buffer[4096];
+
+ size_t sampleDataBufferSize = sizeof(buffer);
+ pSampleData = (int16_t*)malloc(sampleDataBufferSize);
+ if (pSampleData == NULL) {
+ goto on_error;
+ }
+
+ uint64_t samplesRead;
+ while ((samplesRead = (uint64_t)drflac_read_s16(pFlac, sizeof(buffer)/sizeof(buffer[0]), buffer)) > 0)
+ {
+ if (((totalSampleCount + samplesRead) * sizeof(int16_t)) > sampleDataBufferSize) {
+ sampleDataBufferSize *= 2;
+ int16_t* pNewSampleData = (int16_t*)realloc(pSampleData, sampleDataBufferSize);
+ if (pNewSampleData == NULL) {
+ free(pSampleData);
+ goto on_error;
+ }
+
+ pSampleData = pNewSampleData;
+ }
+
+ memcpy(pSampleData + totalSampleCount, buffer, (size_t)(samplesRead*sizeof(int16_t)));
+ totalSampleCount += samplesRead;
+ }
+
+ // At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to
+ // protect those ears from random noise!
+ memset(pSampleData + totalSampleCount, 0, (size_t)(sampleDataBufferSize - totalSampleCount*sizeof(int16_t)));
+ }
+ else
+ {
+ uint64_t dataSize = totalSampleCount * sizeof(int16_t);
+ if (dataSize > SIZE_MAX) {
+ goto on_error; // The decoded data is too big.
+ }
+
+ pSampleData = (int16_t*)malloc((size_t)dataSize); // <-- Safe cast as per the check above.
+ if (pSampleData == NULL) {
+ goto on_error;
+ }
+
+ uint64_t samplesDecoded = drflac_read_s16(pFlac, pFlac->totalSampleCount, pSampleData);
+ if (samplesDecoded != pFlac->totalSampleCount) {
+ free(pSampleData);
+ goto on_error; // Something went wrong when decoding the FLAC stream.
+ }
+ }
+
+
+ if (sampleRateOut) *sampleRateOut = pFlac->sampleRate;
+ if (channelsOut) *channelsOut = pFlac->channels;
+ if (totalSampleCountOut) *totalSampleCountOut = totalSampleCount;
+
+ drflac_close(pFlac);
+ return pSampleData;
+
+on_error:
+ drflac_close(pFlac);
+ return NULL;
+}
+
int32_t* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
{
// Safety.
@@ -4230,7 +4347,22 @@ int32_t* drflac_open_and_decode_s32(drflac_read_proc onRead, drflac_seek_proc on
return NULL;
}
- return drflac__full_decode_and_close(pFlac, channels, sampleRate, totalSampleCount);
+ return drflac__full_decode_and_close_s32(pFlac, channels, sampleRate, totalSampleCount);
+}
+
+int16_t* drflac_open_and_decode_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
+{
+ // Safety.
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drflac* pFlac = drflac_open(onRead, onSeek, pUserData);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ return drflac__full_decode_and_close_s16(pFlac, channels, sampleRate, totalSampleCount);
}
#ifndef DR_FLAC_NO_STDIO
@@ -4245,7 +4377,21 @@ int32_t* drflac_open_and_decode_file_s32(const char* filename, unsigned int* cha
return NULL;
}
- return drflac__full_decode_and_close(pFlac, channels, sampleRate, totalSampleCount);
+ return drflac__full_decode_and_close_s32(pFlac, channels, sampleRate, totalSampleCount);
+}
+
+int16_t* drflac_open_and_decode_file_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drflac* pFlac = drflac_open_file(filename);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ return drflac__full_decode_and_close_s16(pFlac, channels, sampleRate, totalSampleCount);
}
#endif
@@ -4260,7 +4406,21 @@ int32_t* drflac_open_and_decode_memory_s32(const void* data, size_t dataSize, un
return NULL;
}
- return drflac__full_decode_and_close(pFlac, channels, sampleRate, totalSampleCount);
+ return drflac__full_decode_and_close_s32(pFlac, channels, sampleRate, totalSampleCount);
+}
+
+int16_t* drflac_open_and_decode_memory_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, uint64_t* totalSampleCount)
+{
+ if (sampleRate) *sampleRate = 0;
+ if (channels) *channels = 0;
+ if (totalSampleCount) *totalSampleCount = 0;
+
+ drflac* pFlac = drflac_open_memory(data, dataSize);
+ if (pFlac == NULL) {
+ return NULL;
+ }
+
+ return drflac__full_decode_and_close_s16(pFlac, channels, sampleRate, totalSampleCount);
}
void drflac_free(void* pSampleDataReturnedByOpenAndDecode)
@@ -4305,6 +4465,15 @@ const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, ui
// REVISION HISTORY
//
+// v0.4c - 2016-12-26
+// - Add support for signed 16-bit integer PCM decoding.
+//
+// v0.4b - 2016-10-23
+// - A minor change to dr_bool8 and dr_bool32 types.
+//
+// v0.4a - 2016-10-11
+// - Rename drBool32 to dr_bool32 for styling consistency.
+//
// v0.4 - 2016-09-29
// - API/ABI CHANGE: Use fixed size 32-bit booleans instead of the built-in bool type.
// - API CHANGE: Rename drflac_open_and_decode*() to drflac_open_and_decode*_s32()
diff --git a/src/external/jar_mod.h b/src/external/jar_mod.h
index bee9f6ee..c17130a6 100644
--- a/src/external/jar_mod.h
+++ b/src/external/jar_mod.h
@@ -83,8 +83,7 @@
#include <stdio.h>
#include <stdlib.h>
-#include <stdbool.h>
-
+//#include <stdbool.h>
#ifdef __cplusplus
diff --git a/src/external/stb_image.h b/src/external/stb_image.h
index 5572a880..4d8d0133 100644
--- a/src/external/stb_image.h
+++ b/src/external/stb_image.h
@@ -1,4 +1,4 @@
-/* stb_image - v2.12 - public domain image loader - http://nothings.org/stb_image.h
+/* stb_image - v2.14 - public domain image loader - http://nothings.org/stb_image.h
no warranty implied; use at your own risk
Do this:
@@ -146,6 +146,7 @@
Latest revision history:
+ 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64
RGB-format JPEG; remove white matting in PSD;
@@ -157,21 +158,6 @@
2.07 (2015-09-13) partial animated GIF support
limited 16-bit PSD support
minor bugs, code cleanup, and compiler warnings
- 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value
- 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning
- 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit
- 2.03 (2015-04-12) additional corruption checking
- stbi_set_flip_vertically_on_load
- fix NEON support; fix mingw support
- 2.02 (2015-01-19) fix incorrect assert, fix warning
- 2.01 (2015-01-17) fix various warnings
- 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
- 2.00 (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD
- progressive JPEG
- PGM/PPM support
- STBI_MALLOC,STBI_REALLOC,STBI_FREE
- STBI_NO_*, STBI_ONLY_*
- GIF bugfix
See end of file for full revision history.
@@ -186,9 +172,9 @@
Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG)
Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
- urraka@github (animated gif) Junggon Kim (PNM comments)
+ github:urraka (animated gif) Junggon Kim (PNM comments)
Daniel Gibson (16-bit TGA)
-
+ socks-the-fox (16-bit TGA)
Optimizations & bugfixes
Fabian "ryg" Giesen
Arseny Kapoulkine
@@ -199,13 +185,14 @@
Dave Moore Roy Eltham Hayaki Saito Phil Jordan
Won Chun Luke Graham Johan Duparc Nathan Reed
the Horde3D community Thomas Ruf Ronny Chevalier Nick Verigakis
- Janez Zemva John Bartholomew Michal Cichon svdijk@github
+ Janez Zemva John Bartholomew Michal Cichon github:svdijk
Jonathan Blow Ken Hamada Tero Hanninen Baldur Karlsson
- Laurent Gomila Cort Stratton Sergio Gonzalez romigrou@github
+ Laurent Gomila Cort Stratton Sergio Gonzalez github:romigrou
Aruelien Pocheville Thibault Reuille Cass Everitt Matthew Gregan
- Ryamond Barbiero Paul Du Bois Engin Manap snagar@github
- Michaelangel007@github Oriol Ferrer Mesia socks-the-fox
- Blazej Dariusz Roszkowski
+ Ryamond Barbiero Paul Du Bois Engin Manap github:snagar
+ Michaelangel007@github Oriol Ferrer Mesia Dale Weiler github:Zelex
+ Philipp Wiesemann Josh Tobin github:rlyeh github:grim210@github
+ Blazej Dariusz Roszkowski github:sammyhw
LICENSE
@@ -238,10 +225,10 @@ publish, and distribute this file as you see fit.
// stbi_image_free(data)
//
// Standard parameters:
-// int *x -- outputs image width in pixels
-// int *y -- outputs image height in pixels
-// int *comp -- outputs # of image components in image file
-// int req_comp -- if non-zero, # of image components requested in result
+// int *x -- outputs image width in pixels
+// int *y -- outputs image height in pixels
+// int *channels_in_file -- outputs # of image components in image file
+// int desired_channels -- if non-zero, # of image components requested in result
//
// The return value from an image loader is an 'unsigned char *' which points
// to the pixel data, or NULL on an allocation failure or if the image is
@@ -389,13 +376,13 @@ publish, and distribute this file as you see fit.
//
-#define STBI_NO_HDR // RaySan: not required by raylib
-//#define STBI_NO_SIMD // RaySan: issues when compiling with GCC 4.7.2
-
#ifndef STBI_NO_STDIO
#include <stdio.h>
#endif // STBI_NO_STDIO
+#define STBI_NO_HDR // RaySan: not required by raylib
+//#define STBI_NO_SIMD // RaySan: issues when compiling with GCC 4.7.2
+
// NOTE: Added to work with raylib on Android
#if defined(PLATFORM_ANDROID)
#include "utils.h" // RaySan: Android fopen function map
@@ -414,6 +401,7 @@ enum
};
typedef unsigned char stbi_uc;
+typedef unsigned short stbi_us;
#ifdef __cplusplus
extern "C" {
@@ -441,22 +429,42 @@ typedef struct
int (*eof) (void *user); // returns nonzero if we are at end of file/data
} stbi_io_callbacks;
-STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp);
-STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *comp, int req_comp);
-STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *comp, int req_comp);
+////////////////////////////////////
+//
+// 8-bits-per-channel interface
+//
+
+STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
#ifndef STBI_NO_STDIO
-STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
+STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
// for stbi_load_from_file, file pointer is left pointing immediately after image
#endif
+////////////////////////////////////
+//
+// 16-bits-per-channel interface
+//
+
+STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+#endif
+// @TODO the other variants
+
+////////////////////////////////////
+//
+// float-per-channel interface
+//
#ifndef STBI_NO_LINEAR
- STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp);
- STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
- STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);
+ STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+ STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
+ STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
#ifndef STBI_NO_STDIO
- STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp);
+ STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
#endif
#endif
@@ -574,6 +582,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch
#include <stddef.h> // ptrdiff_t on osx
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
#include <math.h> // ldexp
@@ -835,57 +844,70 @@ static void stbi__rewind(stbi__context *s)
s->img_buffer_end = s->img_buffer_original_end;
}
+enum
+{
+ STBI_ORDER_RGB,
+ STBI_ORDER_BGR
+};
+
+typedef struct
+{
+ int bits_per_channel;
+ int num_channels;
+ int channel_order;
+} stbi__result_info;
+
#ifndef STBI_NO_JPEG
static int stbi__jpeg_test(stbi__context *s);
-static stbi_uc *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);
#endif
#ifndef STBI_NO_PNG
static int stbi__png_test(stbi__context *s);
-static stbi_uc *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp);
#endif
#ifndef STBI_NO_BMP
static int stbi__bmp_test(stbi__context *s);
-static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp);
#endif
#ifndef STBI_NO_TGA
static int stbi__tga_test(stbi__context *s);
-static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);
#endif
#ifndef STBI_NO_PSD
static int stbi__psd_test(stbi__context *s);
-static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc);
static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);
#endif
#ifndef STBI_NO_HDR
static int stbi__hdr_test(stbi__context *s);
-static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp);
#endif
#ifndef STBI_NO_PIC
static int stbi__pic_test(stbi__context *s);
-static stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
#endif
#ifndef STBI_NO_GIF
static int stbi__gif_test(stbi__context *s);
-static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
#endif
#ifndef STBI_NO_PNM
static int stbi__pnm_test(stbi__context *s);
-static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);
#endif
@@ -908,6 +930,77 @@ static void *stbi__malloc(size_t size)
return STBI_MALLOC(size);
}
+// stb_image uses ints pervasively, including for offset calculations.
+// therefore the largest decoded image size we can support with the
+// current code, even on 64-bit targets, is INT_MAX. this is not a
+// significant limitation for the intended use case.
+//
+// we do, however, need to make sure our size calculations don't
+// overflow. hence a few helper functions for size calculations that
+// multiply integers together, making sure that they're non-negative
+// and no overflow occurs.
+
+// return 1 if the sum is valid, 0 on overflow.
+// negative terms are considered invalid.
+static int stbi__addsizes_valid(int a, int b)
+{
+ if (b < 0) return 0;
+ // now 0 <= b <= INT_MAX, hence also
+ // 0 <= INT_MAX - b <= INTMAX.
+ // And "a + b <= INT_MAX" (which might overflow) is the
+ // same as a <= INT_MAX - b (no overflow)
+ return a <= INT_MAX - b;
+}
+
+// returns 1 if the product is valid, 0 on overflow.
+// negative factors are considered invalid.
+static int stbi__mul2sizes_valid(int a, int b)
+{
+ if (a < 0 || b < 0) return 0;
+ if (b == 0) return 1; // mul-by-0 is always safe
+ // portable way to check for no overflows in a*b
+ return a <= INT_MAX/b;
+}
+
+// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow
+static int stbi__mad2sizes_valid(int a, int b, int add)
+{
+ return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);
+}
+
+// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow
+static int stbi__mad3sizes_valid(int a, int b, int c, int add)
+{
+ return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
+ stbi__addsizes_valid(a*b*c, add);
+}
+
+// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow
+static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
+{
+ return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
+ stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);
+}
+
+// mallocs with size overflow checking
+static void *stbi__malloc_mad2(int a, int b, int add)
+{
+ if (!stbi__mad2sizes_valid(a, b, add)) return NULL;
+ return stbi__malloc(a*b + add);
+}
+
+static void *stbi__malloc_mad3(int a, int b, int c, int add)
+{
+ if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL;
+ return stbi__malloc(a*b*c + add);
+}
+
+static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
+{
+ if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;
+ return stbi__malloc(a*b*c*d + add);
+}
+
// stbi__err - error
// stbi__errpf - error returning pointer to float
// stbi__errpuc - error returning pointer to unsigned char
@@ -943,33 +1036,38 @@ STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
stbi__vertically_flip_on_load = flag_true_if_should_flip;
}
-static unsigned char *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
{
+ memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields
+ ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed
+ ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order
+ ri->num_channels = 0;
+
#ifndef STBI_NO_JPEG
- if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp);
+ if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);
#endif
#ifndef STBI_NO_PNG
- if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp);
+ if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri);
#endif
#ifndef STBI_NO_BMP
- if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp);
+ if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri);
#endif
#ifndef STBI_NO_GIF
- if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp);
+ if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri);
#endif
#ifndef STBI_NO_PSD
- if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp);
+ if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc);
#endif
#ifndef STBI_NO_PIC
- if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp);
+ if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri);
#endif
#ifndef STBI_NO_PNM
- if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp);
+ if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri);
#endif
#ifndef STBI_NO_HDR
if (stbi__hdr_test(s)) {
- float *hdr = stbi__hdr_load(s, x,y,comp,req_comp);
+ float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri);
return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);
}
#endif
@@ -977,35 +1075,117 @@ static unsigned char *stbi__load_main(stbi__context *s, int *x, int *y, int *com
#ifndef STBI_NO_TGA
// test tga last because it's a crappy test!
if (stbi__tga_test(s))
- return stbi__tga_load(s,x,y,comp,req_comp);
+ return stbi__tga_load(s,x,y,comp,req_comp, ri);
#endif
return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt");
}
-static unsigned char *stbi__load_flip(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels)
{
- unsigned char *result = stbi__load_main(s, x, y, comp, req_comp);
+ int i;
+ int img_len = w * h * channels;
+ stbi_uc *reduced;
- if (stbi__vertically_flip_on_load && result != NULL) {
+ reduced = (stbi_uc *) stbi__malloc(img_len);
+ if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory");
+
+ for (i = 0; i < img_len; ++i)
+ reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling
+
+ STBI_FREE(orig);
+ return reduced;
+}
+
+static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels)
+{
+ int i;
+ int img_len = w * h * channels;
+ stbi__uint16 *enlarged;
+
+ enlarged = (stbi__uint16 *) stbi__malloc(img_len*2);
+ if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
+
+ for (i = 0; i < img_len; ++i)
+ enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff
+
+ STBI_FREE(orig);
+ return enlarged;
+}
+
+static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__result_info ri;
+ void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8);
+
+ if (result == NULL)
+ return NULL;
+
+ if (ri.bits_per_channel != 8) {
+ STBI_ASSERT(ri.bits_per_channel == 16);
+ result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
+ ri.bits_per_channel = 8;
+ }
+
+ // @TODO: move stbi__convert_format to here
+
+ if (stbi__vertically_flip_on_load) {
int w = *x, h = *y;
- int depth = req_comp ? req_comp : *comp;
+ int channels = req_comp ? req_comp : *comp;
int row,col,z;
- stbi_uc temp;
+ stbi_uc *image = (stbi_uc *) result;
// @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
for (row = 0; row < (h>>1); row++) {
for (col = 0; col < w; col++) {
- for (z = 0; z < depth; z++) {
- temp = result[(row * w + col) * depth + z];
- result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z];
- result[((h - row - 1) * w + col) * depth + z] = temp;
+ for (z = 0; z < channels; z++) {
+ stbi_uc temp = image[(row * w + col) * channels + z];
+ image[(row * w + col) * channels + z] = image[((h - row - 1) * w + col) * channels + z];
+ image[((h - row - 1) * w + col) * channels + z] = temp;
}
}
}
}
- return result;
+ return (unsigned char *) result;
+}
+
+static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__result_info ri;
+ void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16);
+
+ if (result == NULL)
+ return NULL;
+
+ if (ri.bits_per_channel != 16) {
+ STBI_ASSERT(ri.bits_per_channel == 8);
+ result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
+ ri.bits_per_channel = 16;
+ }
+
+ // @TODO: move stbi__convert_format16 to here
+ // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision
+
+ if (stbi__vertically_flip_on_load) {
+ int w = *x, h = *y;
+ int channels = req_comp ? req_comp : *comp;
+ int row,col,z;
+ stbi__uint16 *image = (stbi__uint16 *) result;
+
+ // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
+ for (row = 0; row < (h>>1); row++) {
+ for (col = 0; col < w; col++) {
+ for (z = 0; z < channels; z++) {
+ stbi__uint16 temp = image[(row * w + col) * channels + z];
+ image[(row * w + col) * channels + z] = image[((h - row - 1) * w + col) * channels + z];
+ image[((h - row - 1) * w + col) * channels + z] = temp;
+ }
+ }
+ }
+ }
+
+ return (stbi__uint16 *) result;
}
#ifndef STBI_NO_HDR
@@ -1061,27 +1241,52 @@ STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req
unsigned char *result;
stbi__context s;
stbi__start_file(&s,f);
- result = stbi__load_flip(&s,x,y,comp,req_comp);
+ result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
if (result) {
// need to 'unget' all the characters in the IO buffer
fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
}
return result;
}
+
+STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+ stbi__uint16 *result;
+ stbi__context s;
+ stbi__start_file(&s,f);
+ result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp);
+ if (result) {
+ // need to 'unget' all the characters in the IO buffer
+ fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
+ }
+ return result;
+}
+
+STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ stbi__uint16 *result;
+ if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file");
+ result = stbi_load_from_file_16(f,x,y,comp,req_comp);
+ fclose(f);
+ return result;
+}
+
+
#endif //!STBI_NO_STDIO
STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
{
stbi__context s;
stbi__start_mem(&s,buffer,len);
- return stbi__load_flip(&s,x,y,comp,req_comp);
+ return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
}
STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
{
stbi__context s;
stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
- return stbi__load_flip(&s,x,y,comp,req_comp);
+ return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
}
#ifndef STBI_NO_LINEAR
@@ -1090,13 +1295,14 @@ static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int
unsigned char *data;
#ifndef STBI_NO_HDR
if (stbi__hdr_test(s)) {
- float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp);
+ stbi__result_info ri;
+ float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri);
if (hdr_data)
stbi__float_postprocess(hdr_data,x,y,comp,req_comp);
return hdr_data;
}
#endif
- data = stbi__load_flip(s, x, y, comp, req_comp);
+ data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp);
if (data)
return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);
return stbi__errpf("unknown image type", "Image not of any known type, or corrupt");
@@ -1354,7 +1560,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
if (req_comp == img_n) return data;
STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
- good = (unsigned char *) stbi__malloc(req_comp * x * y);
+ good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0);
if (good == NULL) {
STBI_FREE(data);
return stbi__errpuc("outofmem", "Out of memory");
@@ -1364,26 +1570,75 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
unsigned char *src = data + j * x * img_n ;
unsigned char *dest = good + j * x * req_comp;
- #define COMBO(a,b) ((a)*8+(b))
- #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+ #define STBI__COMBO(a,b) ((a)*8+(b))
+ #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
// convert source image with img_n components to one with req_comp components;
// avoid switch per pixel, so use switch per scanline and massive macros
- switch (COMBO(img_n, req_comp)) {
- CASE(1,2) dest[0]=src[0], dest[1]=255; break;
- CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break;
- CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break;
- CASE(2,1) dest[0]=src[0]; break;
- CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break;
- CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break;
- CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break;
- CASE(3,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break;
- CASE(3,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; break;
- CASE(4,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break;
- CASE(4,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break;
- CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break;
+ switch (STBI__COMBO(img_n, req_comp)) {
+ STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break;
+ STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break;
+ STBI__CASE(2,1) { dest[0]=src[0]; } break;
+ STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break;
+ STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break;
+ STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
+ STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break;
+ STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
+ STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break;
+ STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break;
default: STBI_ASSERT(0);
}
- #undef CASE
+ #undef STBI__CASE
+ }
+
+ STBI_FREE(data);
+ return good;
+}
+
+static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
+{
+ return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8);
+}
+
+static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+{
+ int i,j;
+ stbi__uint16 *good;
+
+ if (req_comp == img_n) return data;
+ STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
+
+ good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2);
+ if (good == NULL) {
+ STBI_FREE(data);
+ return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
+ }
+
+ for (j=0; j < (int) y; ++j) {
+ stbi__uint16 *src = data + j * x * img_n ;
+ stbi__uint16 *dest = good + j * x * req_comp;
+
+ #define STBI__COMBO(a,b) ((a)*8+(b))
+ #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+ // convert source image with img_n components to one with req_comp components;
+ // avoid switch per pixel, so use switch per scanline and massive macros
+ switch (STBI__COMBO(img_n, req_comp)) {
+ STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break;
+ STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break;
+ STBI__CASE(2,1) { dest[0]=src[0]; } break;
+ STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+ STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break;
+ STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break;
+ STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
+ STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break;
+ STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
+ STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break;
+ STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break;
+ default: STBI_ASSERT(0);
+ }
+ #undef STBI__CASE
}
STBI_FREE(data);
@@ -1394,7 +1649,9 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
{
int i,k,n;
- float *output = (float *) stbi__malloc(x * y * comp * sizeof(float));
+ float *output;
+ if (!data) return NULL;
+ output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0);
if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); }
// compute number of non-alpha components
if (comp & 1) n = comp; else n = comp-1;
@@ -1414,7 +1671,9 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp)
{
int i,k,n;
- stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp);
+ stbi_uc *output;
+ if (!data) return NULL;
+ output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0);
if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); }
// compute number of non-alpha components
if (comp & 1) n = comp; else n = comp-1;
@@ -2709,6 +2968,28 @@ static int stbi__process_scan_header(stbi__jpeg *z)
return 1;
}
+static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why)
+{
+ int i;
+ for (i=0; i < ncomp; ++i) {
+ if (z->img_comp[i].raw_data) {
+ STBI_FREE(z->img_comp[i].raw_data);
+ z->img_comp[i].raw_data = NULL;
+ z->img_comp[i].data = NULL;
+ }
+ if (z->img_comp[i].raw_coeff) {
+ STBI_FREE(z->img_comp[i].raw_coeff);
+ z->img_comp[i].raw_coeff = 0;
+ z->img_comp[i].coeff = 0;
+ }
+ if (z->img_comp[i].linebuf) {
+ STBI_FREE(z->img_comp[i].linebuf);
+ z->img_comp[i].linebuf = NULL;
+ }
+ }
+ return why;
+}
+
static int stbi__process_frame_header(stbi__jpeg *z, int scan)
{
stbi__context *s = z->s;
@@ -2746,7 +3027,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
if (scan != STBI__SCAN_load) return 1;
- if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
+ if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode");
for (i=0; i < s->img_n; ++i) {
if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;
@@ -2758,6 +3039,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
z->img_v_max = v_max;
z->img_mcu_w = h_max * 8;
z->img_mcu_h = v_max * 8;
+ // these sizes can't be more than 17 bits
z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;
z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;
@@ -2769,28 +3051,27 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
// the bogus oversized data from using interleaved MCUs and their
// big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
// discard the extra data until colorspace conversion
+ //
+ // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier)
+ // so these muls can't overflow with 32-bit ints (which we require)
z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;
z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;
- z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15);
-
- if (z->img_comp[i].raw_data == NULL) {
- for(--i; i >= 0; --i) {
- STBI_FREE(z->img_comp[i].raw_data);
- z->img_comp[i].raw_data = NULL;
- }
- return stbi__err("outofmem", "Out of memory");
- }
+ z->img_comp[i].coeff = 0;
+ z->img_comp[i].raw_coeff = 0;
+ z->img_comp[i].linebuf = NULL;
+ z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15);
+ if (z->img_comp[i].raw_data == NULL)
+ return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory"));
// align blocks for idct using mmx/sse
z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);
- z->img_comp[i].linebuf = NULL;
if (z->progressive) {
- z->img_comp[i].coeff_w = (z->img_comp[i].w2 + 7) >> 3;
- z->img_comp[i].coeff_h = (z->img_comp[i].h2 + 7) >> 3;
- z->img_comp[i].raw_coeff = STBI_MALLOC(z->img_comp[i].coeff_w * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15);
+ // w2, h2 are multiples of 8 (see above)
+ z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8;
+ z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8;
+ z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15);
+ if (z->img_comp[i].raw_coeff == NULL)
+ return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory"));
z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);
- } else {
- z->img_comp[i].coeff = 0;
- z->img_comp[i].raw_coeff = 0;
}
}
@@ -3296,23 +3577,7 @@ static void stbi__setup_jpeg(stbi__jpeg *j)
// clean up the temporary component buffers
static void stbi__cleanup_jpeg(stbi__jpeg *j)
{
- int i;
- for (i=0; i < j->s->img_n; ++i) {
- if (j->img_comp[i].raw_data) {
- STBI_FREE(j->img_comp[i].raw_data);
- j->img_comp[i].raw_data = NULL;
- j->img_comp[i].data = NULL;
- }
- if (j->img_comp[i].raw_coeff) {
- STBI_FREE(j->img_comp[i].raw_coeff);
- j->img_comp[i].raw_coeff = 0;
- j->img_comp[i].coeff = 0;
- }
- if (j->img_comp[i].linebuf) {
- STBI_FREE(j->img_comp[i].linebuf);
- j->img_comp[i].linebuf = NULL;
- }
- }
+ stbi__free_jpeg_components(j, j->s->img_n, 0);
}
typedef struct
@@ -3376,7 +3641,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
}
// can't error after this so, this is safe
- output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1);
+ output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1);
if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
// now go ahead and resample
@@ -3432,7 +3697,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
}
}
-static unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
{
unsigned char* result;
stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));
@@ -3729,6 +3994,7 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a)
int hlit = stbi__zreceive(a,5) + 257;
int hdist = stbi__zreceive(a,5) + 1;
int hclen = stbi__zreceive(a,4) + 4;
+ int ntot = hlit + hdist;
memset(codelength_sizes, 0, sizeof(codelength_sizes));
for (i=0; i < hclen; ++i) {
@@ -3738,27 +4004,29 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a)
if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
n = 0;
- while (n < hlit + hdist) {
+ while (n < ntot) {
int c = stbi__zhuffman_decode(a, &z_codelength);
if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG");
if (c < 16)
lencodes[n++] = (stbi_uc) c;
- else if (c == 16) {
- c = stbi__zreceive(a,2)+3;
- memset(lencodes+n, lencodes[n-1], c);
- n += c;
- } else if (c == 17) {
- c = stbi__zreceive(a,3)+3;
- memset(lencodes+n, 0, c);
- n += c;
- } else {
- STBI_ASSERT(c == 18);
- c = stbi__zreceive(a,7)+11;
- memset(lencodes+n, 0, c);
+ else {
+ stbi_uc fill = 0;
+ if (c == 16) {
+ c = stbi__zreceive(a,2)+3;
+ if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG");
+ fill = lencodes[n-1];
+ } else if (c == 17)
+ c = stbi__zreceive(a,3)+3;
+ else {
+ STBI_ASSERT(c == 18);
+ c = stbi__zreceive(a,7)+11;
+ }
+ if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG");
+ memset(lencodes+n, fill, c);
n += c;
}
}
- if (n != hlit+hdist) return stbi__err("bad codelengths","Corrupt PNG");
+ if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG");
if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;
if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;
return 1;
@@ -4024,7 +4292,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
int width = x;
STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);
- a->out = (stbi_uc *) stbi__malloc(x * y * output_bytes); // extra bytes to write off the end into
+ a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
if (!a->out) return stbi__err("outofmem", "Out of memory");
img_width_bytes = (((img_n * x * depth) + 7) >> 3);
@@ -4089,37 +4357,37 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
// this is a little gross, so that we don't switch per-pixel or per-component
if (depth < 8 || img_n == out_n) {
int nk = (width - 1)*filter_bytes;
- #define CASE(f) \
+ #define STBI__CASE(f) \
case f: \
for (k=0; k < nk; ++k)
switch (filter) {
// "none" filter turns into a memcpy here; make that explicit.
case STBI__F_none: memcpy(cur, raw, nk); break;
- CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); break;
- CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
- CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); break;
- CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); break;
- CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); break;
- CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); break;
+ STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;
+ STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
+ STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;
+ STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
+ STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;
+ STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;
}
- #undef CASE
+ #undef STBI__CASE
raw += nk;
} else {
STBI_ASSERT(img_n+1 == out_n);
- #define CASE(f) \
+ #define STBI__CASE(f) \
case f: \
for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \
for (k=0; k < filter_bytes; ++k)
switch (filter) {
- CASE(STBI__F_none) cur[k] = raw[k]; break;
- CASE(STBI__F_sub) cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); break;
- CASE(STBI__F_up) cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
- CASE(STBI__F_avg) cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); break;
- CASE(STBI__F_paeth) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); break;
- CASE(STBI__F_avg_first) cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); break;
- CASE(STBI__F_paeth_first) cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); break;
+ STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break;
+ STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;
+ STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
+ STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;
+ STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;
+ STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;
+ STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;
}
- #undef CASE
+ #undef STBI__CASE
// the loop above sets the high byte of the pixels' alpha, but for
// 16 bit png files we also need the low byte set. we'll do that here.
@@ -4222,13 +4490,15 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)
{
+ int bytes = (depth == 16 ? 2 : 1);
+ int out_bytes = out_n * bytes;
stbi_uc *final;
int p;
if (!interlaced)
return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);
// de-interlacing
- final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n);
+ final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);
for (p=0; p < 7; ++p) {
int xorig[] = { 0,4,0,2,0,1,0 };
int yorig[] = { 0,0,4,0,2,0,1 };
@@ -4248,8 +4518,8 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3
for (i=0; i < x; ++i) {
int out_y = j*yspc[p]+yorig[p];
int out_x = i*xspc[p]+xorig[p];
- memcpy(final + out_y*a->s->img_x*out_n + out_x*out_n,
- a->out + (j*x+i)*out_n, out_n);
+ memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes,
+ a->out + (j*x+i)*out_bytes, out_bytes);
}
}
STBI_FREE(a->out);
@@ -4317,7 +4587,7 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int
stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;
stbi_uc *p, *temp_out, *orig = a->out;
- p = (stbi_uc *) stbi__malloc(pixel_count * pal_img_n);
+ p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0);
if (p == NULL) return stbi__err("outofmem", "Out of memory");
// between here and free(out) below, exitting would leak
@@ -4349,26 +4619,6 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int
return 1;
}
-static int stbi__reduce_png(stbi__png *p)
-{
- int i;
- int img_len = p->s->img_x * p->s->img_y * p->s->img_out_n;
- stbi_uc *reduced;
- stbi__uint16 *orig = (stbi__uint16*)p->out;
-
- if (p->depth != 16) return 1; // don't need to do anything if not 16-bit data
-
- reduced = (stbi_uc *)stbi__malloc(img_len);
- if (p == NULL) return stbi__err("outofmem", "Out of memory");
-
- for (i = 0; i < img_len; ++i) reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is a decent approx of 16->8 bit scaling
-
- p->out = reduced;
- STBI_FREE(orig);
-
- return 1;
-}
-
static int stbi__unpremultiply_on_load = 0;
static int stbi__de_iphone_flag = 0;
@@ -4508,7 +4758,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG");
has_trans = 1;
if (z->depth == 16) {
- for (k = 0; k < s->img_n; ++k) tc16[k] = stbi__get16be(s); // copy the values as-is
+ for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is
} else {
for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
}
@@ -4595,20 +4845,22 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
}
}
-static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp)
+static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri)
{
- unsigned char *result=NULL;
+ void *result=NULL;
if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {
- if (p->depth == 16) {
- if (!stbi__reduce_png(p)) {
- return result;
- }
- }
+ if (p->depth < 8)
+ ri->bits_per_channel = 8;
+ else
+ ri->bits_per_channel = p->depth;
result = p->out;
p->out = NULL;
if (req_comp && req_comp != p->s->img_out_n) {
- result = stbi__convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+ if (ri->bits_per_channel == 8)
+ result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+ else
+ result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
p->s->img_out_n = req_comp;
if (result == NULL) return result;
}
@@ -4623,11 +4875,11 @@ static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req
return result;
}
-static unsigned char *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
{
stbi__png p;
p.s = s;
- return stbi__do_png(&p, x,y,comp,req_comp);
+ return stbi__do_png(&p, x,y,comp,req_comp, ri);
}
static int stbi__png_test(stbi__context *s)
@@ -4815,7 +5067,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
}
-static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
{
stbi_uc *out;
unsigned int mr=0,mg=0,mb=0,ma=0, all_a;
@@ -4823,6 +5075,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
int psize=0,i,j,width;
int flip_vertically, pad, target;
stbi__bmp_data info;
+ STBI_NOTUSED(ri);
info.all_a = 255;
if (stbi__bmp_parse_header(s, &info) == NULL)
@@ -4851,7 +5104,11 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int
else
target = s->img_n; // if they want monochrome, we'll post-convert
- out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y);
+ // sanity-check size
+ if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0))
+ return stbi__errpuc("too large", "Corrupt BMP");
+
+ out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0);
if (!out) return stbi__errpuc("outofmem", "Out of memory");
if (info.bpp < 16) {
int z=0;
@@ -5085,18 +5342,18 @@ errorEnd:
}
// read 16bit value and convert to 24bit RGB
-void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)
+static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)
{
- stbi__uint16 px = stbi__get16le(s);
+ stbi__uint16 px = (stbi__uint16)stbi__get16le(s);
stbi__uint16 fiveBitMask = 31;
// we have 3 channels with 5bits each
int r = (px >> 10) & fiveBitMask;
int g = (px >> 5) & fiveBitMask;
int b = px & fiveBitMask;
// Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later
- out[0] = (r * 255)/31;
- out[1] = (g * 255)/31;
- out[2] = (b * 255)/31;
+ out[0] = (stbi_uc)((r * 255)/31);
+ out[1] = (stbi_uc)((g * 255)/31);
+ out[2] = (stbi_uc)((b * 255)/31);
// some people claim that the most significant bit might be used for alpha
// (possibly if an alpha-bit is set in the "image descriptor byte")
@@ -5104,7 +5361,7 @@ void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)
// so let's treat all 15 and 16bit TGAs as RGB with no alpha.
}
-static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
{
// read in the TGA header stuff
int tga_offset = stbi__get8(s);
@@ -5126,10 +5383,11 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
unsigned char *tga_data;
unsigned char *tga_palette = NULL;
int i, j;
- unsigned char raw_data[4];
+ unsigned char raw_data[4] = {0};
int RLE_count = 0;
int RLE_repeating = 0;
int read_next_pixel = 1;
+ STBI_NOTUSED(ri);
// do a tiny bit of precessing
if ( tga_image_type >= 8 )
@@ -5151,7 +5409,10 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
*y = tga_height;
if (comp) *comp = tga_comp;
- tga_data = (unsigned char*)stbi__malloc( (size_t)tga_width * tga_height * tga_comp );
+ if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0))
+ return stbi__errpuc("too large", "Corrupt TGA");
+
+ tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0);
if (!tga_data) return stbi__errpuc("outofmem", "Out of memory");
// skip to the data's starting position (offset usually = 0)
@@ -5170,7 +5431,7 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int
// any data to skip? (offset usually = 0)
stbi__skip(s, tga_palette_start );
// load the palette
- tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_comp );
+ tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0);
if (!tga_palette) {
STBI_FREE(tga_data);
return stbi__errpuc("outofmem", "Out of memory");
@@ -5306,14 +5567,53 @@ static int stbi__psd_test(stbi__context *s)
return r;
}
-static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount)
{
- int pixelCount;
+ int count, nleft, len;
+
+ count = 0;
+ while ((nleft = pixelCount - count) > 0) {
+ len = stbi__get8(s);
+ if (len == 128) {
+ // No-op.
+ } else if (len < 128) {
+ // Copy next len+1 bytes literally.
+ len++;
+ if (len > nleft) return 0; // corrupt data
+ count += len;
+ while (len) {
+ *p = stbi__get8(s);
+ p += 4;
+ len--;
+ }
+ } else if (len > 128) {
+ stbi_uc val;
+ // Next -len+1 bytes in the dest are replicated from next source byte.
+ // (Interpret len as a negative 8-bit int.)
+ len = 257 - len;
+ if (len > nleft) return 0; // corrupt data
+ val = stbi__get8(s);
+ count += len;
+ while (len) {
+ *p = val;
+ p += 4;
+ len--;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
+{
+ int pixelCount;
int channelCount, compression;
- int channel, i, count, len;
+ int channel, i;
int bitdepth;
int w,h;
stbi_uc *out;
+ STBI_NOTUSED(ri);
// Check identifier
if (stbi__get32be(s) != 0x38425053) // "8BPS"
@@ -5370,8 +5670,18 @@ static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int
if (compression > 1)
return stbi__errpuc("bad compression", "PSD has an unknown compression format");
+ // Check size
+ if (!stbi__mad3sizes_valid(4, w, h, 0))
+ return stbi__errpuc("too large", "Corrupt PSD");
+
// Create the destination image.
- out = (stbi_uc *) stbi__malloc(4 * w*h);
+
+ if (!compression && bitdepth == 16 && bpc == 16) {
+ out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0);
+ ri->bits_per_channel = 16;
+ } else
+ out = (stbi_uc *) stbi__malloc(4 * w*h);
+
if (!out) return stbi__errpuc("outofmem", "Out of memory");
pixelCount = w*h;
@@ -5403,82 +5713,86 @@ static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int
*p = (channel == 3 ? 255 : 0);
} else {
// Read the RLE data.
- count = 0;
- while (count < pixelCount) {
- len = stbi__get8(s);
- if (len == 128) {
- // No-op.
- } else if (len < 128) {
- // Copy next len+1 bytes literally.
- len++;
- count += len;
- while (len) {
- *p = stbi__get8(s);
- p += 4;
- len--;
- }
- } else if (len > 128) {
- stbi_uc val;
- // Next -len+1 bytes in the dest are replicated from next source byte.
- // (Interpret len as a negative 8-bit int.)
- len ^= 0x0FF;
- len += 2;
- val = stbi__get8(s);
- count += len;
- while (len) {
- *p = val;
- p += 4;
- len--;
- }
- }
+ if (!stbi__psd_decode_rle(s, p, pixelCount)) {
+ STBI_FREE(out);
+ return stbi__errpuc("corrupt", "bad RLE data");
}
}
}
} else {
// We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...)
- // where each channel consists of an 8-bit value for each pixel in the image.
+ // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image.
// Read the data by channel.
for (channel = 0; channel < 4; channel++) {
- stbi_uc *p;
-
- p = out + channel;
if (channel >= channelCount) {
// Fill this channel with default data.
- stbi_uc val = channel == 3 ? 255 : 0;
- for (i = 0; i < pixelCount; i++, p += 4)
- *p = val;
- } else {
- // Read the data.
- if (bitdepth == 16) {
- for (i = 0; i < pixelCount; i++, p += 4)
- *p = (stbi_uc) (stbi__get16be(s) >> 8);
+ if (bitdepth == 16 && bpc == 16) {
+ stbi__uint16 *q = ((stbi__uint16 *) out) + channel;
+ stbi__uint16 val = channel == 3 ? 65535 : 0;
+ for (i = 0; i < pixelCount; i++, q += 4)
+ *q = val;
} else {
+ stbi_uc *p = out+channel;
+ stbi_uc val = channel == 3 ? 255 : 0;
for (i = 0; i < pixelCount; i++, p += 4)
- *p = stbi__get8(s);
+ *p = val;
+ }
+ } else {
+ if (ri->bits_per_channel == 16) { // output bpc
+ stbi__uint16 *q = ((stbi__uint16 *) out) + channel;
+ for (i = 0; i < pixelCount; i++, q += 4)
+ *q = (stbi__uint16) stbi__get16be(s);
+ } else {
+ stbi_uc *p = out+channel;
+ if (bitdepth == 16) { // input bpc
+ for (i = 0; i < pixelCount; i++, p += 4)
+ *p = (stbi_uc) (stbi__get16be(s) >> 8);
+ } else {
+ for (i = 0; i < pixelCount; i++, p += 4)
+ *p = stbi__get8(s);
+ }
}
}
}
}
+ // remove weird white matte from PSD
if (channelCount >= 4) {
- for (i=0; i < w*h; ++i) {
- unsigned char *pixel = out + 4*i;
- if (pixel[3] != 0 && pixel[3] != 255) {
- // remove weird white matte from PSD
- float a = pixel[3] / 255.0f;
- float ra = 1.0f / a;
- float inv_a = 255.0f * (1 - ra);
- pixel[0] = (unsigned char) (pixel[0]*ra + inv_a);
- pixel[1] = (unsigned char) (pixel[1]*ra + inv_a);
- pixel[2] = (unsigned char) (pixel[2]*ra + inv_a);
+ if (ri->bits_per_channel == 16) {
+ for (i=0; i < w*h; ++i) {
+ stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i;
+ if (pixel[3] != 0 && pixel[3] != 65535) {
+ float a = pixel[3] / 65535.0f;
+ float ra = 1.0f / a;
+ float inv_a = 65535.0f * (1 - ra);
+ pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a);
+ pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a);
+ pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a);
+ }
+ }
+ } else {
+ for (i=0; i < w*h; ++i) {
+ unsigned char *pixel = out + 4*i;
+ if (pixel[3] != 0 && pixel[3] != 255) {
+ float a = pixel[3] / 255.0f;
+ float ra = 1.0f / a;
+ float inv_a = 255.0f * (1 - ra);
+ pixel[0] = (unsigned char) (pixel[0]*ra + inv_a);
+ pixel[1] = (unsigned char) (pixel[1]*ra + inv_a);
+ pixel[2] = (unsigned char) (pixel[2]*ra + inv_a);
+ }
}
}
}
+ // convert to desired output format
if (req_comp && req_comp != 4) {
- out = stbi__convert_format(out, 4, req_comp, w, h);
+ if (ri->bits_per_channel == 16)
+ out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h);
+ else
+ out = stbi__convert_format(out, 4, req_comp, w, h);
if (out == NULL) return out; // stbi__convert_format frees input on failure
}
@@ -5662,10 +5976,11 @@ static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *c
return result;
}
-static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp)
+static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri)
{
stbi_uc *result;
int i, x,y;
+ STBI_NOTUSED(ri);
for (i=0; i<92; ++i)
stbi__get8(s);
@@ -5673,14 +5988,14 @@ static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int re
x = stbi__get16be(s);
y = stbi__get16be(s);
if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)");
- if ((1 << 28) / x < y) return stbi__errpuc("too large", "Image too large to decode");
+ if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode");
stbi__get32be(s); //skip `ratio'
stbi__get16be(s); //skip `fields'
stbi__get16be(s); //skip `pad'
// intermediate buffer is RGBA
- result = (stbi_uc *) stbi__malloc(x*y*4);
+ result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0);
memset(result, 0xff, x*y*4);
if (!stbi__pic_load_core(s,x,y,comp, result)) {
@@ -5939,8 +6254,11 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
if (g->out == 0 && !stbi__gif_header(s, g, comp,0))
return 0; // stbi__g_failure_reason set by stbi__gif_header
+ if (!stbi__mad3sizes_valid(g->w, g->h, 4, 0))
+ return stbi__errpuc("too large", "GIF too large");
+
prev_out = g->out;
- g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
+ g->out = (stbi_uc *) stbi__malloc_mad3(4, g->w, g->h, 0);
if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory");
switch ((g->eflags & 0x1C) >> 2) {
@@ -6047,11 +6365,12 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
STBI_NOTUSED(req_comp);
}
-static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
{
stbi_uc *u = 0;
stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
memset(g, 0, sizeof(*g));
+ STBI_NOTUSED(ri);
u = stbi__gif_load_next(s, g, comp, req_comp);
if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
@@ -6077,20 +6396,24 @@ static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp)
// Radiance RGBE HDR loader
// originally by Nicolas Schulz
#ifndef STBI_NO_HDR
-static int stbi__hdr_test_core(stbi__context *s)
+static int stbi__hdr_test_core(stbi__context *s, const char *signature)
{
- const char *signature = "#?RADIANCE\n";
int i;
for (i=0; signature[i]; ++i)
if (stbi__get8(s) != signature[i])
- return 0;
+ return 0;
+ stbi__rewind(s);
return 1;
}
static int stbi__hdr_test(stbi__context* s)
{
- int r = stbi__hdr_test_core(s);
+ int r = stbi__hdr_test_core(s, "#?RADIANCE\n");
stbi__rewind(s);
+ if(!r) {
+ r = stbi__hdr_test_core(s, "#?RGBE\n");
+ stbi__rewind(s);
+ }
return r;
}
@@ -6144,7 +6467,7 @@ static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)
}
}
-static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
{
char buffer[STBI__HDR_BUFLEN];
char *token;
@@ -6155,10 +6478,12 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re
int len;
unsigned char count, value;
int i, j, k, c1,c2, z;
-
+ const char *headerToken;
+ STBI_NOTUSED(ri);
// Check identifier
- if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0)
+ headerToken = stbi__hdr_gettoken(s,buffer);
+ if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0)
return stbi__errpf("not HDR", "Corrupt HDR image");
// Parse header
@@ -6187,8 +6512,13 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re
if (comp) *comp = 3;
if (req_comp == 0) req_comp = 3;
+ if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0))
+ return stbi__errpf("too large", "HDR image is too large");
+
// Read data
- hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float));
+ hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0);
+ if (!hdr_data)
+ return stbi__errpf("outofmem", "Out of memory");
// Load image data
// image data is stored as some number of sca
@@ -6227,20 +6557,29 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re
len <<= 8;
len |= stbi__get8(s);
if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); }
- if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4);
+ if (scanline == NULL) {
+ scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0);
+ if (!scanline) {
+ STBI_FREE(hdr_data);
+ return stbi__errpf("outofmem", "Out of memory");
+ }
+ }
for (k = 0; k < 4; ++k) {
+ int nleft;
i = 0;
- while (i < width) {
+ while ((nleft = width - i) > 0) {
count = stbi__get8(s);
if (count > 128) {
// Run
value = stbi__get8(s);
count -= 128;
+ if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
for (z = 0; z < count; ++z)
scanline[i++ * 4 + k] = value;
} else {
// Dump
+ if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); }
for (z = 0; z < count; ++z)
scanline[i++ * 4 + k] = stbi__get8(s);
}
@@ -6249,7 +6588,8 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re
for (i=0; i < width; ++i)
stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);
}
- STBI_FREE(scanline);
+ if (scanline)
+ STBI_FREE(scanline);
}
return hdr_data;
@@ -6427,16 +6767,22 @@ static int stbi__pnm_test(stbi__context *s)
return 1;
}
-static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
{
stbi_uc *out;
+ STBI_NOTUSED(ri);
+
if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n))
return 0;
+
*x = s->img_x;
*y = s->img_y;
*comp = s->img_n;
- out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y);
+ if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0))
+ return stbi__errpuc("too large", "PNM too large");
+
+ out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0);
if (!out) return stbi__errpuc("outofmem", "Out of memory");
stbi__getn(s, out, s->img_n * s->img_x * s->img_y);
@@ -6601,6 +6947,7 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
/*
revision history:
+ 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now
2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
2.11 (2016-04-02) allocate large structures on the stack
remove white matting for transparent PSD
diff --git a/src/external/stb_image_resize.h b/src/external/stb_image_resize.h
index 4cabe540..5214ad6e 100644
--- a/src/external/stb_image_resize.h
+++ b/src/external/stb_image_resize.h
@@ -1,4 +1,4 @@
-/* stb_image_resize - v0.91 - public domain image resizing
+/* stb_image_resize - v0.92 - public domain image resizing
by Jorge L Rodriguez (@VinoBS) - 2014
http://github.com/nothings/stb
@@ -154,8 +154,10 @@
ADDITIONAL CONTRIBUTORS
Sean Barrett: API design, optimizations
+ Aras Pranckevicius: bugfix
REVISIONS
+ 0.92 (2017-01-02) fix integer overflow on large (>2GB) images
0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
0.90 (2014-09-17) first released version
@@ -1239,11 +1241,11 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
int type = stbir_info->type;
int colorspace = stbir_info->colorspace;
int input_w = stbir_info->input_w;
- int input_stride_bytes = stbir_info->input_stride_bytes;
+ size_t input_stride_bytes = stbir_info->input_stride_bytes;
float* decode_buffer = stbir__get_decode_buffer(stbir_info);
stbir_edge edge_horizontal = stbir_info->edge_horizontal;
stbir_edge edge_vertical = stbir_info->edge_vertical;
- int in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
+ size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset;
int max_x = input_w + stbir_info->horizontal_filter_pixel_margin;
int decode = STBIR__DECODE(type, colorspace);
diff --git a/src/external/stb_image_write.h b/src/external/stb_image_write.h
index 4319c0de..ae9180b0 100644
--- a/src/external/stb_image_write.h
+++ b/src/external/stb_image_write.h
@@ -1,4 +1,4 @@
-/* stb_image_write - v1.02 - public domain - http://nothings.org/stb/stb_image_write.h
+/* stb_image_write - v1.03 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk
@@ -103,6 +103,7 @@ CREDITS:
Jonas Karlsson
Filip Wasil
Thatcher Ulrich
+ github:poppolopoppo
LICENSE
@@ -475,7 +476,6 @@ int stbi_write_tga(char const *filename, int x, int y, int comp, const void *dat
// *************************************************************************************************
// Radiance RGBE HDR writer
// by Baldur Karlsson
-#ifndef STBI_WRITE_NO_STDIO
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
@@ -630,6 +630,7 @@ int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, i
return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
}
+#ifndef STBI_WRITE_NO_STDIO
int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
{
stbi__write_context s;
diff --git a/src/external/stb_rect_pack.h b/src/external/stb_rect_pack.h
index bd1cfc60..c75527da 100644
--- a/src/external/stb_rect_pack.h
+++ b/src/external/stb_rect_pack.h
@@ -1,4 +1,4 @@
-// stb_rect_pack.h - v0.08 - public domain - rectangle packing
+// stb_rect_pack.h - v0.10 - public domain - rectangle packing
// Sean Barrett 2014
//
// Useful for e.g. packing rectangular textures into an atlas.
@@ -32,6 +32,8 @@
//
// 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
@@ -148,7 +150,7 @@ enum
{
STBRP_HEURISTIC_Skyline_default=0,
STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,
- STBRP_HEURISTIC_Skyline_BF_sortHeight,
+ STBRP_HEURISTIC_Skyline_BF_sortHeight
};
@@ -198,9 +200,15 @@ struct stbrp_context
#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__INIT_skyline = 1
};
STBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)
@@ -273,6 +281,9 @@ static int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0
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
@@ -500,8 +511,8 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, i
static int rect_height_compare(const void *a, const void *b)
{
- stbrp_rect *p = (stbrp_rect *) a;
- stbrp_rect *q = (stbrp_rect *) 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)
@@ -511,8 +522,8 @@ static int rect_height_compare(const void *a, const void *b)
static int rect_width_compare(const void *a, const void *b)
{
- stbrp_rect *p = (stbrp_rect *) a;
- stbrp_rect *q = (stbrp_rect *) 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)
@@ -522,8 +533,8 @@ static int rect_width_compare(const void *a, const void *b)
static int rect_original_order(const void *a, const void *b)
{
- stbrp_rect *p = (stbrp_rect *) a;
- stbrp_rect *q = (stbrp_rect *) 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);
}
diff --git a/src/external/stb_truetype.h b/src/external/stb_truetype.h
index d360d609..92b9a875 100644
--- a/src/external/stb_truetype.h
+++ b/src/external/stb_truetype.h
@@ -1,5 +1,5 @@
-// stb_truetype.h - v1.11 - public domain
-// authored from 2009-2015 by Sean Barrett / RAD Game Tools
+// stb_truetype.h - v1.14 - public domain
+// authored from 2009-2016 by Sean Barrett / RAD Game Tools
//
// This library processes TrueType files:
// parse files
@@ -20,10 +20,12 @@
//
// Mikko Mononen: compound shape support, more cmap formats
// Tor Andersson: kerning, subpixel rendering
+// Dougall Johnson: OpenType / Type 2 font handling
//
// Misc other:
// Ryan Gordon
// Simon Glass
+// github:IntellectualKitty
//
// Bug/warning reports/fixes:
// "Zer" on mollyrocket (with fix)
@@ -51,6 +53,8 @@
//
// VERSION HISTORY
//
+// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts, num-fonts-in-TTC function
+// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
// 1.11 (2016-04-02) fix unused-variable warning
// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef
// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly
@@ -60,12 +64,6 @@
// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);
// fixed an assert() bug in the new rasterizer
// replace assert() with STBTT_assert() in new rasterizer
-// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine)
-// also more precise AA rasterizer, except if shapes overlap
-// remove need for STBTT_sort
-// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC
-// 1.04 (2015-04-15) typo in example
-// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes
//
// Full history can be found at the end of this file.
//
@@ -100,7 +98,8 @@
//
// "Load" a font file from a memory buffer (you have to keep the buffer loaded)
// stbtt_InitFont()
-// stbtt_GetFontOffsetForIndex() -- use for TTC font collections
+// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections
+// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections
//
// Render a unicode codepoint to a bitmap
// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap
@@ -458,6 +457,14 @@ int main(int arg, char **argv)
extern "C" {
#endif
+// private structure
+typedef struct
+{
+ unsigned char *data;
+ int cursor;
+ int size;
+} stbtt__buf;
+
//////////////////////////////////////////////////////////////////////////////
//
// TEXTURE BAKING API
@@ -527,7 +534,7 @@ typedef struct stbrp_rect stbrp_rect;
STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);
// Initializes a packing context stored in the passed-in stbtt_pack_context.
// Future calls using this context will pack characters into the bitmap passed
-// in here: a 1-channel bitmap that is weight x height. stride_in_bytes is
+// in here: a 1-channel bitmap that is width * height. stride_in_bytes is
// the distance from one row to the next (or 0 to mean they are packed tightly
// together). "padding" is the amount of padding to leave between each
// character (normally you want '1' for bitmaps you'll use as textures with
@@ -593,9 +600,9 @@ STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph,
stbtt_aligned_quad *q, // output: quad to draw
int align_to_integer);
-STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
+STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);
-STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
+STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);
// Calling these functions in sequence is roughly equivalent to calling
// stbtt_PackFontRanges(). If you more control over the packing of multiple
// fonts, or if you want to pack custom data into a font texture, take a look
@@ -626,14 +633,19 @@ struct stbtt_pack_context {
//
//
+STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data);
+// This function will determine the number of fonts in a font file. TrueType
+// collection (.ttc) files may contain multiple fonts, while TrueType font
+// (.ttf) files only contain one font. The number of fonts can be used for
+// indexing with the previous function where the index is between zero and one
+// less than the total fonts. If an error occurs, -1 is returned.
+
STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);
// Each .ttf/.ttc file may have more than one font. Each font has a sequential
// index number starting from 0. Call this function to get the font offset for
// a given index; it returns -1 if the index is out of range. A regular .ttf
// file will only define one font and it always be at offset 0, so it will
-// return '0' for index 0, and -1 for all other indices. You can just skip
-// this step if you know it's that kind of font.
-
+// return '0' for index 0, and -1 for all other indices.
// The following structure is defined publically so you can declare one on
// the stack or as a global or etc, but you should treat it as opaque.
@@ -648,6 +660,13 @@ struct stbtt_fontinfo
int loca,head,glyf,hhea,hmtx,kern; // table locations as offset from start of .ttf
int index_map; // a cmap mapping for our chosen character encoding
int indexToLocFormat; // format needed to map from glyph index to glyph
+
+ stbtt__buf cff; // cff font data
+ stbtt__buf charstrings; // the charstring index
+ stbtt__buf gsubrs; // global charstring subroutines index
+ stbtt__buf subrs; // private charstring subroutines index
+ stbtt__buf fontdicts; // array of font dicts
+ stbtt__buf fdselect; // map from glyph to fontdict
};
STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);
@@ -725,7 +744,8 @@ STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, in
enum {
STBTT_vmove=1,
STBTT_vline,
- STBTT_vcurve
+ STBTT_vcurve,
+ STBTT_vcubic
};
#endif
@@ -734,7 +754,7 @@ STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, in
#define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file
typedef struct
{
- stbtt_vertex_type x,y,cx,cy;
+ stbtt_vertex_type x,y,cx,cy,cx1,cy1;
unsigned char type,padding;
} stbtt_vertex;
#endif
@@ -958,6 +978,152 @@ typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERS
//////////////////////////////////////////////////////////////////////////
//
+// stbtt__buf helpers to parse data from file
+//
+
+static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b)
+{
+ if (b->cursor >= b->size)
+ return 0;
+ return b->data[b->cursor++];
+}
+
+static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b)
+{
+ if (b->cursor >= b->size)
+ return 0;
+ return b->data[b->cursor];
+}
+
+static void stbtt__buf_seek(stbtt__buf *b, int o)
+{
+ STBTT_assert(!(o > b->size || o < 0));
+ b->cursor = (o > b->size || o < 0) ? b->size : o;
+}
+
+static void stbtt__buf_skip(stbtt__buf *b, int o)
+{
+ stbtt__buf_seek(b, b->cursor + o);
+}
+
+static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n)
+{
+ stbtt_uint32 v = 0;
+ int i;
+ STBTT_assert(n >= 1 && n <= 4);
+ for (i = 0; i < n; i++)
+ v = (v << 8) | stbtt__buf_get8(b);
+ return v;
+}
+
+static stbtt__buf stbtt__new_buf(const void *p, size_t size)
+{
+ stbtt__buf r;
+ STBTT_assert(size < 0x40000000);
+ r.data = (stbtt_uint8*) p;
+ r.size = (int) size;
+ r.cursor = 0;
+ return r;
+}
+
+#define stbtt__buf_get16(b) stbtt__buf_get((b), 2)
+#define stbtt__buf_get32(b) stbtt__buf_get((b), 4)
+
+static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s)
+{
+ stbtt__buf r = stbtt__new_buf(NULL, 0);
+ if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r;
+ r.data = b->data + o;
+ r.size = s;
+ return r;
+}
+
+static stbtt__buf stbtt__cff_get_index(stbtt__buf *b)
+{
+ int count, start, offsize;
+ start = b->cursor;
+ count = stbtt__buf_get16(b);
+ if (count) {
+ offsize = stbtt__buf_get8(b);
+ STBTT_assert(offsize >= 1 && offsize <= 4);
+ stbtt__buf_skip(b, offsize * count);
+ stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1);
+ }
+ return stbtt__buf_range(b, start, b->cursor - start);
+}
+
+static stbtt_uint32 stbtt__cff_int(stbtt__buf *b)
+{
+ int b0 = stbtt__buf_get8(b);
+ if (b0 >= 32 && b0 <= 246) return b0 - 139;
+ else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;
+ else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;
+ else if (b0 == 28) return stbtt__buf_get16(b);
+ else if (b0 == 29) return stbtt__buf_get32(b);
+ STBTT_assert(0);
+ return 0;
+}
+
+static void stbtt__cff_skip_operand(stbtt__buf *b) {
+ int v, b0 = stbtt__buf_peek8(b);
+ STBTT_assert(b0 >= 28);
+ if (b0 == 30) {
+ stbtt__buf_skip(b, 1);
+ while (b->cursor < b->size) {
+ v = stbtt__buf_get8(b);
+ if ((v & 0xF) == 0xF || (v >> 4) == 0xF)
+ break;
+ }
+ } else {
+ stbtt__cff_int(b);
+ }
+}
+
+static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key)
+{
+ stbtt__buf_seek(b, 0);
+ while (b->cursor < b->size) {
+ int start = b->cursor, end, op;
+ while (stbtt__buf_peek8(b) >= 28)
+ stbtt__cff_skip_operand(b);
+ end = b->cursor;
+ op = stbtt__buf_get8(b);
+ if (op == 12) op = stbtt__buf_get8(b) | 0x100;
+ if (op == key) return stbtt__buf_range(b, start, end-start);
+ }
+ return stbtt__buf_range(b, 0, 0);
+}
+
+static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out)
+{
+ int i;
+ stbtt__buf operands = stbtt__dict_get(b, key);
+ for (i = 0; i < outcount && operands.cursor < operands.size; i++)
+ out[i] = stbtt__cff_int(&operands);
+}
+
+static int stbtt__cff_index_count(stbtt__buf *b)
+{
+ stbtt__buf_seek(b, 0);
+ return stbtt__buf_get16(b);
+}
+
+static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i)
+{
+ int count, offsize, start, end;
+ stbtt__buf_seek(&b, 0);
+ count = stbtt__buf_get16(&b);
+ offsize = stbtt__buf_get8(&b);
+ STBTT_assert(i >= 0 && i < count);
+ STBTT_assert(offsize >= 1 && offsize <= 4);
+ stbtt__buf_skip(&b, i*offsize);
+ start = stbtt__buf_get(&b, offsize);
+ end = stbtt__buf_get(&b, offsize);
+ return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
// accessors to parse data from file
//
@@ -968,32 +1134,22 @@ typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERS
#define ttCHAR(p) (* (stbtt_int8 *) (p))
#define ttFixed(p) ttLONG(p)
-#if defined(STB_TRUETYPE_BIGENDIAN) && !defined(ALLOW_UNALIGNED_TRUETYPE)
-
- #define ttUSHORT(p) (* (stbtt_uint16 *) (p))
- #define ttSHORT(p) (* (stbtt_int16 *) (p))
- #define ttULONG(p) (* (stbtt_uint32 *) (p))
- #define ttLONG(p) (* (stbtt_int32 *) (p))
-
-#else
-
- static stbtt_uint16 ttUSHORT(const stbtt_uint8 *p) { return p[0]*256 + p[1]; }
- static stbtt_int16 ttSHORT(const stbtt_uint8 *p) { return p[0]*256 + p[1]; }
- static stbtt_uint32 ttULONG(const stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
- static stbtt_int32 ttLONG(const stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
-
-#endif
+static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }
+static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }
+static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
+static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }
#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))
#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3])
-static int stbtt__isfont(const stbtt_uint8 *font)
+static int stbtt__isfont(stbtt_uint8 *font)
{
// check the version number
if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1
if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this!
if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF
if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0
+ if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts
return 0;
}
@@ -1011,7 +1167,7 @@ static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart,
return 0;
}
-STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *font_collection, int index)
+static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index)
{
// if it's just a font, there's only one valid index
if (stbtt__isfont(font_collection))
@@ -1030,14 +1186,43 @@ STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *font_collection,
return -1;
}
-STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data2, int fontstart)
+static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection)
+{
+ // if it's just a font, there's only one valid font
+ if (stbtt__isfont(font_collection))
+ return 1;
+
+ // check if it's a TTC
+ if (stbtt_tag(font_collection, "ttcf")) {
+ // version 1?
+ if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {
+ return ttLONG(font_collection+8);
+ }
+ }
+ return 0;
+}
+
+static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)
+{
+ stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 };
+ stbtt__buf pdict;
+ stbtt__dict_get_ints(&fontdict, 18, 2, private_loc);
+ if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0);
+ pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]);
+ stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);
+ if (!subrsoff) return stbtt__new_buf(NULL, 0);
+ stbtt__buf_seek(&cff, private_loc[1]+subrsoff);
+ return stbtt__cff_get_index(&cff);
+}
+
+static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)
{
- stbtt_uint8 *data = (stbtt_uint8 *) data2;
stbtt_uint32 cmap, t;
stbtt_int32 i,numTables;
info->data = data;
info->fontstart = fontstart;
+ info->cff = stbtt__new_buf(NULL, 0);
cmap = stbtt__find_table(data, fontstart, "cmap"); // required
info->loca = stbtt__find_table(data, fontstart, "loca"); // required
@@ -1046,8 +1231,61 @@ STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data2, i
info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required
info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required
info->kern = stbtt__find_table(data, fontstart, "kern"); // not required
- if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx)
+
+ if (!cmap || !info->head || !info->hhea || !info->hmtx)
return 0;
+ if (info->glyf) {
+ // required for truetype
+ if (!info->loca) return 0;
+ } else {
+ // initialization for CFF / Type2 fonts (OTF)
+ stbtt__buf b, topdict, topdictidx;
+ stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;
+ stbtt_uint32 cff;
+
+ cff = stbtt__find_table(data, fontstart, "CFF ");
+ if (!cff) return 0;
+
+ info->fontdicts = stbtt__new_buf(NULL, 0);
+ info->fdselect = stbtt__new_buf(NULL, 0);
+
+ // @TODO this should use size from table (not 512MB)
+ info->cff = stbtt__new_buf(data+cff, 512*1024*1024);
+ b = info->cff;
+
+ // read the header
+ stbtt__buf_skip(&b, 2);
+ stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize
+
+ // @TODO the name INDEX could list multiple fonts,
+ // but we just use the first one.
+ stbtt__cff_get_index(&b); // name INDEX
+ topdictidx = stbtt__cff_get_index(&b);
+ topdict = stbtt__cff_index_get(topdictidx, 0);
+ stbtt__cff_get_index(&b); // string INDEX
+ info->gsubrs = stbtt__cff_get_index(&b);
+
+ stbtt__dict_get_ints(&topdict, 17, 1, &charstrings);
+ stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype);
+ stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff);
+ stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff);
+ info->subrs = stbtt__get_subrs(b, topdict);
+
+ // we only support Type 2 charstrings
+ if (cstype != 2) return 0;
+ if (charstrings == 0) return 0;
+
+ if (fdarrayoff) {
+ // looks like a CID font
+ if (!fdselectoff) return 0;
+ stbtt__buf_seek(&b, fdarrayoff);
+ info->fontdicts = stbtt__cff_get_index(&b);
+ info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff);
+ }
+
+ stbtt__buf_seek(&b, charstrings);
+ info->charstrings = stbtt__cff_get_index(&b);
+ }
t = stbtt__find_table(data, fontstart, "maxp");
if (t)
@@ -1198,6 +1436,8 @@ static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)
{
int g1,g2;
+ STBTT_assert(!info->cff.size);
+
if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range
if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format
@@ -1212,15 +1452,21 @@ static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)
return g1==g2 ? -1 : g1; // if length is 0, return -1
}
+static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);
+
STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
{
- int g = stbtt__GetGlyfOffset(info, glyph_index);
- if (g < 0) return 0;
+ if (info->cff.size) {
+ stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);
+ } else {
+ int g = stbtt__GetGlyfOffset(info, glyph_index);
+ if (g < 0) return 0;
- if (x0) *x0 = ttSHORT(info->data + g + 2);
- if (y0) *y0 = ttSHORT(info->data + g + 4);
- if (x1) *x1 = ttSHORT(info->data + g + 6);
- if (y1) *y1 = ttSHORT(info->data + g + 8);
+ if (x0) *x0 = ttSHORT(info->data + g + 2);
+ if (y0) *y0 = ttSHORT(info->data + g + 4);
+ if (x1) *x1 = ttSHORT(info->data + g + 6);
+ if (y1) *y1 = ttSHORT(info->data + g + 8);
+ }
return 1;
}
@@ -1232,7 +1478,10 @@ STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, i
STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)
{
stbtt_int16 numberOfContours;
- int g = stbtt__GetGlyfOffset(info, glyph_index);
+ int g;
+ if (info->cff.size)
+ return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0;
+ g = stbtt__GetGlyfOffset(info, glyph_index);
if (g < 0) return 1;
numberOfContours = ttSHORT(info->data + g);
return numberOfContours == 0;
@@ -1254,7 +1503,7 @@ static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_
return num_vertices;
}
-STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
+static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
{
stbtt_int16 numberOfContours;
stbtt_uint8 *endPtsOfContours;
@@ -1480,6 +1729,416 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s
return num_vertices;
}
+typedef struct
+{
+ int bounds;
+ int started;
+ float first_x, first_y;
+ float x, y;
+ stbtt_int32 min_x, max_x, min_y, max_y;
+
+ stbtt_vertex *pvertices;
+ int num_vertices;
+} stbtt__csctx;
+
+#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0}
+
+static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y)
+{
+ if (x > c->max_x || !c->started) c->max_x = x;
+ if (y > c->max_y || !c->started) c->max_y = y;
+ if (x < c->min_x || !c->started) c->min_x = x;
+ if (y < c->min_y || !c->started) c->min_y = y;
+ c->started = 1;
+}
+
+static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1)
+{
+ if (c->bounds) {
+ stbtt__track_vertex(c, x, y);
+ if (type == STBTT_vcubic) {
+ stbtt__track_vertex(c, cx, cy);
+ stbtt__track_vertex(c, cx1, cy1);
+ }
+ } else {
+ stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy);
+ c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1;
+ c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1;
+ }
+ c->num_vertices++;
+}
+
+static void stbtt__csctx_close_shape(stbtt__csctx *ctx)
+{
+ if (ctx->first_x != ctx->x || ctx->first_y != ctx->y)
+ stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0);
+}
+
+static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy)
+{
+ stbtt__csctx_close_shape(ctx);
+ ctx->first_x = ctx->x = ctx->x + dx;
+ ctx->first_y = ctx->y = ctx->y + dy;
+ stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
+}
+
+static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy)
+{
+ ctx->x += dx;
+ ctx->y += dy;
+ stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);
+}
+
+static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)
+{
+ float cx1 = ctx->x + dx1;
+ float cy1 = ctx->y + dy1;
+ float cx2 = cx1 + dx2;
+ float cy2 = cy1 + dy2;
+ ctx->x = cx2 + dx3;
+ ctx->y = cy2 + dy3;
+ stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2);
+}
+
+static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n)
+{
+ int count = stbtt__cff_index_count(&idx);
+ int bias = 107;
+ if (count >= 33900)
+ bias = 32768;
+ else if (count >= 1240)
+ bias = 1131;
+ n += bias;
+ if (n < 0 || n >= count)
+ return stbtt__new_buf(NULL, 0);
+ return stbtt__cff_index_get(idx, n);
+}
+
+static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index)
+{
+ stbtt__buf fdselect = info->fdselect;
+ int nranges, start, end, v, fmt, fdselector = -1, i;
+
+ stbtt__buf_seek(&fdselect, 0);
+ fmt = stbtt__buf_get8(&fdselect);
+ if (fmt == 0) {
+ // untested
+ stbtt__buf_skip(&fdselect, glyph_index);
+ fdselector = stbtt__buf_get8(&fdselect);
+ } else if (fmt == 3) {
+ nranges = stbtt__buf_get16(&fdselect);
+ start = stbtt__buf_get16(&fdselect);
+ for (i = 0; i < nranges; i++) {
+ v = stbtt__buf_get8(&fdselect);
+ end = stbtt__buf_get16(&fdselect);
+ if (glyph_index >= start && glyph_index < end) {
+ fdselector = v;
+ break;
+ }
+ start = end;
+ }
+ }
+ if (fdselector == -1) stbtt__new_buf(NULL, 0);
+ return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector));
+}
+
+static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c)
+{
+ int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;
+ int has_subrs = 0, clear_stack;
+ float s[48];
+ stbtt__buf subr_stack[10], subrs = info->subrs, b;
+ float f;
+
+#define STBTT__CSERR(s) (0)
+
+ // this currently ignores the initial width value, which isn't needed if we have hmtx
+ b = stbtt__cff_index_get(info->charstrings, glyph_index);
+ while (b.cursor < b.size) {
+ i = 0;
+ clear_stack = 1;
+ b0 = stbtt__buf_get8(&b);
+ switch (b0) {
+ // @TODO implement hinting
+ case 0x13: // hintmask
+ case 0x14: // cntrmask
+ if (in_header)
+ maskbits += (sp / 2); // implicit "vstem"
+ in_header = 0;
+ stbtt__buf_skip(&b, (maskbits + 7) / 8);
+ break;
+
+ case 0x01: // hstem
+ case 0x03: // vstem
+ case 0x12: // hstemhm
+ case 0x17: // vstemhm
+ maskbits += (sp / 2);
+ break;
+
+ case 0x15: // rmoveto
+ in_header = 0;
+ if (sp < 2) return STBTT__CSERR("rmoveto stack");
+ stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);
+ break;
+ case 0x04: // vmoveto
+ in_header = 0;
+ if (sp < 1) return STBTT__CSERR("vmoveto stack");
+ stbtt__csctx_rmove_to(c, 0, s[sp-1]);
+ break;
+ case 0x16: // hmoveto
+ in_header = 0;
+ if (sp < 1) return STBTT__CSERR("hmoveto stack");
+ stbtt__csctx_rmove_to(c, s[sp-1], 0);
+ break;
+
+ case 0x05: // rlineto
+ if (sp < 2) return STBTT__CSERR("rlineto stack");
+ for (; i + 1 < sp; i += 2)
+ stbtt__csctx_rline_to(c, s[i], s[i+1]);
+ break;
+
+ // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical
+ // starting from a different place.
+
+ case 0x07: // vlineto
+ if (sp < 1) return STBTT__CSERR("vlineto stack");
+ goto vlineto;
+ case 0x06: // hlineto
+ if (sp < 1) return STBTT__CSERR("hlineto stack");
+ for (;;) {
+ if (i >= sp) break;
+ stbtt__csctx_rline_to(c, s[i], 0);
+ i++;
+ vlineto:
+ if (i >= sp) break;
+ stbtt__csctx_rline_to(c, 0, s[i]);
+ i++;
+ }
+ break;
+
+ case 0x1F: // hvcurveto
+ if (sp < 4) return STBTT__CSERR("hvcurveto stack");
+ goto hvcurveto;
+ case 0x1E: // vhcurveto
+ if (sp < 4) return STBTT__CSERR("vhcurveto stack");
+ for (;;) {
+ if (i + 3 >= sp) break;
+ stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f);
+ i += 4;
+ hvcurveto:
+ if (i + 3 >= sp) break;
+ stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]);
+ i += 4;
+ }
+ break;
+
+ case 0x08: // rrcurveto
+ if (sp < 6) return STBTT__CSERR("rcurveline stack");
+ for (; i + 5 < sp; i += 6)
+ stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
+ break;
+
+ case 0x18: // rcurveline
+ if (sp < 8) return STBTT__CSERR("rcurveline stack");
+ for (; i + 5 < sp - 2; i += 6)
+ stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
+ if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack");
+ stbtt__csctx_rline_to(c, s[i], s[i+1]);
+ break;
+
+ case 0x19: // rlinecurve
+ if (sp < 8) return STBTT__CSERR("rlinecurve stack");
+ for (; i + 1 < sp - 6; i += 2)
+ stbtt__csctx_rline_to(c, s[i], s[i+1]);
+ if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack");
+ stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);
+ break;
+
+ case 0x1A: // vvcurveto
+ case 0x1B: // hhcurveto
+ if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack");
+ f = 0.0;
+ if (sp & 1) { f = s[i]; i++; }
+ for (; i + 3 < sp; i += 4) {
+ if (b0 == 0x1B)
+ stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);
+ else
+ stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);
+ f = 0.0;
+ }
+ break;
+
+ case 0x0A: // callsubr
+ if (!has_subrs) {
+ if (info->fdselect.size)
+ subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
+ has_subrs = 1;
+ }
+ // fallthrough
+ case 0x1D: // callgsubr
+ if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
+ v = (int) s[--sp];
+ if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit");
+ subr_stack[subr_stack_height++] = b;
+ b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v);
+ if (b.size == 0) return STBTT__CSERR("subr not found");
+ b.cursor = 0;
+ clear_stack = 0;
+ break;
+
+ case 0x0B: // return
+ if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr");
+ b = subr_stack[--subr_stack_height];
+ clear_stack = 0;
+ break;
+
+ case 0x0E: // endchar
+ stbtt__csctx_close_shape(c);
+ return 1;
+
+ case 0x0C: { // two-byte escape
+ float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;
+ float dx, dy;
+ int b1 = stbtt__buf_get8(&b);
+ switch (b1) {
+ // @TODO These "flex" implementations ignore the flex-depth and resolution,
+ // and always draw beziers.
+ case 0x22: // hflex
+ if (sp < 7) return STBTT__CSERR("hflex stack");
+ dx1 = s[0];
+ dx2 = s[1];
+ dy2 = s[2];
+ dx3 = s[3];
+ dx4 = s[4];
+ dx5 = s[5];
+ dx6 = s[6];
+ stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);
+ stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);
+ break;
+
+ case 0x23: // flex
+ if (sp < 13) return STBTT__CSERR("flex stack");
+ dx1 = s[0];
+ dy1 = s[1];
+ dx2 = s[2];
+ dy2 = s[3];
+ dx3 = s[4];
+ dy3 = s[5];
+ dx4 = s[6];
+ dy4 = s[7];
+ dx5 = s[8];
+ dy5 = s[9];
+ dx6 = s[10];
+ dy6 = s[11];
+ //fd is s[12]
+ stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
+ stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
+ break;
+
+ case 0x24: // hflex1
+ if (sp < 9) return STBTT__CSERR("hflex1 stack");
+ dx1 = s[0];
+ dy1 = s[1];
+ dx2 = s[2];
+ dy2 = s[3];
+ dx3 = s[4];
+ dx4 = s[5];
+ dx5 = s[6];
+ dy5 = s[7];
+ dx6 = s[8];
+ stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);
+ stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));
+ break;
+
+ case 0x25: // flex1
+ if (sp < 11) return STBTT__CSERR("flex1 stack");
+ dx1 = s[0];
+ dy1 = s[1];
+ dx2 = s[2];
+ dy2 = s[3];
+ dx3 = s[4];
+ dy3 = s[5];
+ dx4 = s[6];
+ dy4 = s[7];
+ dx5 = s[8];
+ dy5 = s[9];
+ dx6 = dy6 = s[10];
+ dx = dx1+dx2+dx3+dx4+dx5;
+ dy = dy1+dy2+dy3+dy4+dy5;
+ if (STBTT_fabs(dx) > STBTT_fabs(dy))
+ dy6 = -dy;
+ else
+ dx6 = -dx;
+ stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);
+ stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);
+ break;
+
+ default:
+ return STBTT__CSERR("unimplemented");
+ }
+ } break;
+
+ default:
+ if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))
+ return STBTT__CSERR("reserved operator");
+
+ // push immediate
+ if (b0 == 255) {
+ f = (float)stbtt__buf_get32(&b) / 0x10000;
+ } else {
+ stbtt__buf_skip(&b, -1);
+ f = (float)(stbtt_int16)stbtt__cff_int(&b);
+ }
+ if (sp >= 48) return STBTT__CSERR("push stack overflow");
+ s[sp++] = f;
+ clear_stack = 0;
+ break;
+ }
+ if (clear_stack) sp = 0;
+ }
+ return STBTT__CSERR("no endchar");
+
+#undef STBTT__CSERR
+}
+
+static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
+{
+ // runs the charstring twice, once to count and once to output (to avoid realloc)
+ stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1);
+ stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0);
+ if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {
+ *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata);
+ output_ctx.pvertices = *pvertices;
+ if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {
+ STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices);
+ return output_ctx.num_vertices;
+ }
+ }
+ *pvertices = NULL;
+ return 0;
+}
+
+static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)
+{
+ stbtt__csctx c = STBTT__CSCTX_INIT(1);
+ int r = stbtt__run_charstring(info, glyph_index, &c);
+ if (x0) {
+ *x0 = r ? c.min_x : 0;
+ *y0 = r ? c.min_y : 0;
+ *x1 = r ? c.max_x : 0;
+ *y1 = r ? c.max_y : 0;
+ }
+ return r ? c.num_vertices : 0;
+}
+
+STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)
+{
+ if (!info->cff.size)
+ return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices);
+ else
+ return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices);
+}
+
STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)
{
stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);
@@ -2350,6 +3009,48 @@ static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x
return 1;
}
+static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n)
+{
+ // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough
+ float dx0 = x1-x0;
+ float dy0 = y1-y0;
+ float dx1 = x2-x1;
+ float dy1 = y2-y1;
+ float dx2 = x3-x2;
+ float dy2 = y3-y2;
+ float dx = x3-x0;
+ float dy = y3-y0;
+ float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2));
+ float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy);
+ float flatness_squared = longlen*longlen-shortlen*shortlen;
+
+ if (n > 16) // 65536 segments on one curve better be enough!
+ return;
+
+ if (flatness_squared > objspace_flatness_squared) {
+ float x01 = (x0+x1)/2;
+ float y01 = (y0+y1)/2;
+ float x12 = (x1+x2)/2;
+ float y12 = (y1+y2)/2;
+ float x23 = (x2+x3)/2;
+ float y23 = (y2+y3)/2;
+
+ float xa = (x01+x12)/2;
+ float ya = (y01+y12)/2;
+ float xb = (x12+x23)/2;
+ float yb = (y12+y23)/2;
+
+ float mx = (xa+xb)/2;
+ float my = (ya+yb)/2;
+
+ stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);
+ stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);
+ } else {
+ stbtt__add_point(points, *num_points,x3,y3);
+ *num_points = *num_points+1;
+ }
+}
+
// returns number of contours
static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)
{
@@ -2406,6 +3107,14 @@ static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts,
objspace_flatness_squared, 0);
x = vertices[i].x, y = vertices[i].y;
break;
+ case STBTT_vcubic:
+ stbtt__tesselate_cubic(points, &num_points, x,y,
+ vertices[i].cx, vertices[i].cy,
+ vertices[i].cx1, vertices[i].cy1,
+ vertices[i].x, vertices[i].y,
+ objspace_flatness_squared, 0);
+ x = vertices[i].x, y = vertices[i].y;
+ break;
}
}
(*contour_lengths)[n] = num_points - start;
@@ -2532,7 +3241,7 @@ STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned ch
//
// This is SUPER-CRAPPY packing to keep source code small
-STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf)
+static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf)
float pixel_height, // height of font in pixels
unsigned char *pixels, int pw, int ph, // bitmap to be filled in
int first_char, int num_chars, // characters to bake
@@ -2862,7 +3571,7 @@ static float stbtt__oversample_shift(int oversample)
}
// rects array must be big enough to accommodate all characters in the given ranges
-STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
+STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
{
int i,j,k;
@@ -2891,7 +3600,7 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, stbtt_fon
}
// rects array must be big enough to accommodate all characters in the given ranges
-STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
+STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
{
int i,j,k, return_value = 1;
@@ -3060,7 +3769,7 @@ STBTT_DEF void stbtt_GetPackedQuad(stbtt_packedchar *chardata, int pw, int ph, i
//
// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string
-static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(const stbtt_uint8 *s1, stbtt_int32 len1, const stbtt_uint8 *s2, stbtt_int32 len2)
+static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)
{
stbtt_int32 i=0;
@@ -3099,9 +3808,9 @@ static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(const stbtt_uint8
return i;
}
-STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2)
+static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2)
{
- return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((const stbtt_uint8*) s1, len1, (const stbtt_uint8*) s2, len2);
+ return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);
}
// returns results in whatever encoding you request... but note that 2-byte encodings
@@ -3157,7 +3866,7 @@ static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name,
return 1;
} else if (matchlen < nlen && name[matchlen] == ' ') {
++matchlen;
- if (stbtt_CompareUTF8toUTF16_bigendian((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))
+ if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))
return 1;
}
} else {
@@ -3203,7 +3912,7 @@ static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *nam
return 0;
}
-STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *font_collection, const char *name_utf8, stbtt_int32 flags)
+static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags)
{
stbtt_int32 i;
for (i=0;;++i) {
@@ -3214,11 +3923,53 @@ STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *font_collection, const
}
}
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+
+STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,
+ float pixel_height, unsigned char *pixels, int pw, int ph,
+ int first_char, int num_chars, stbtt_bakedchar *chardata)
+{
+ return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);
+}
+
+STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index)
+{
+ return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);
+}
+
+STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data)
+{
+ return stbtt_GetNumberOfFonts_internal((unsigned char *) data);
+}
+
+STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset)
+{
+ return stbtt_InitFont_internal(info, (unsigned char *) data, offset);
+}
+
+STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags)
+{
+ return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags);
+}
+
+STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2)
+{
+ return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2);
+}
+
+#if defined(__GNUC__) || defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
#endif // STB_TRUETYPE_IMPLEMENTATION
// FULL VERSION HISTORY
//
+// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
// 1.11 (2016-04-02) fix unused-variable warning
// 1.10 (2016-04-02) allow user-defined fabs() replacement
// fix memory leak if fontsize=0.0
diff --git a/src/gestures.h b/src/gestures.h
index 481ef317..99f49d2a 100644
--- a/src/gestures.h
+++ b/src/gestures.h
@@ -2,6 +2,10 @@
*
* raylib Gestures System - Gestures Processing based on input gesture events (touch/mouse)
*
+* NOTE: Memory footprint of this library is aproximately 128 bytes (global variables)
+*
+* CONFIGURATION:
+*
* #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
@@ -11,11 +15,16 @@
* 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
+* CONTRIBUTORS:
+* Marc Palau: Initial implementation (2014)
+* Albert Martos: Complete redesign and testing (2015)
+* Ian Eito: Complete redesign and testing (2015)
+* Ramon Santamaria: Supervision, review, update and maintenance
+*
*
-* Initial design by Marc Palau (2014)
-* Redesigned by Albert Martos and Ian Eito (2015)
-* Reviewed by Ramon Santamaria (2015-2016)
+* LICENSE: zlib/libpng
+*
+* 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.
@@ -65,17 +74,17 @@
// 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
+ 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;
#endif
@@ -179,7 +188,7 @@ static int tapCounter = 0; // TAP counter (one tap implies
// Hold gesture variables
static bool resetHold = false; // HOLD reset to get first touch point again
-static float timeHold = 0.0f; // HOLD duration in milliseconds
+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)
@@ -423,11 +432,11 @@ float GetGestureHoldDuration(void)
{
// NOTE: time is calculated on current gesture HOLD
- float time = 0.0f;
+ double time = 0.0;
- if (currentGesture == GESTURE_HOLD) time = (float)GetCurrentTime() - timeHold;
+ if (currentGesture == GESTURE_HOLD) time = GetCurrentTime() - timeHold;
- return time;
+ return (float)time;
}
// Get drag vector (between initial touch point to current)
@@ -474,7 +483,7 @@ static float Vector2Angle(Vector2 initialPosition, Vector2 finalPosition)
{
float angle;
- angle = atan2(finalPosition.y - initialPosition.y, finalPosition.x - initialPosition.x)*(180.0f/PI);
+ angle = atan2f(finalPosition.y - initialPosition.y, finalPosition.x - initialPosition.x)*(180.0f/PI);
if (angle < 0) angle += 360.0f;
@@ -489,7 +498,7 @@ static float Vector2Distance(Vector2 v1, Vector2 v2)
float dx = v2.x - v1.x;
float dy = v2.y - v1.y;
- result = sqrt(dx*dx + dy*dy);
+ result = (float)sqrt(dx*dx + dy*dy);
return result;
}
diff --git a/src/models.c b/src/models.c
index 48f8b813..bef19e10 100644
--- a/src/models.c
+++ b/src/models.c
@@ -1,14 +1,15 @@
/**********************************************************************************************
*
-* raylib.models
+* raylib.models - Basic functions to draw 3d shapes and 3d models
*
-* Basic functions to draw 3d shapes and load/draw 3d models (.OBJ)
+* CONFIGURATION:
*
-* External libs:
-* rlgl - raylib OpenGL abstraction layer
+* #define SUPPORT_FILEFORMAT_OBJ / SUPPORT_LOAD_OBJ
*
-* Module Configuration Flags:
-* ...
+* #define SUPPORT_FILEFORMAT_MTL
+*
+*
+* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
@@ -574,164 +575,71 @@ void DrawGizmo(Vector3 position)
rlPopMatrix();
}
-
-// Draw light in 3D world
-void DrawLight(Light light)
+// Load mesh from file
+Mesh LoadMesh(const char *fileName)
{
- switch (light->type)
- {
- case LIGHT_POINT:
- {
- DrawSphereWires(light->position, 0.3f*light->intensity, 8, 8, (light->enabled ? light->diffuse : GRAY));
-
- DrawCircle3D(light->position, light->radius, (Vector3){ 0, 0, 0 }, 0.0f, (light->enabled ? light->diffuse : GRAY));
- DrawCircle3D(light->position, light->radius, (Vector3){ 1, 0, 0 }, 90.0f, (light->enabled ? light->diffuse : GRAY));
- DrawCircle3D(light->position, light->radius, (Vector3){ 0, 1, 0 },90.0f, (light->enabled ? light->diffuse : GRAY));
- } break;
- case LIGHT_DIRECTIONAL:
- {
- DrawLine3D(light->position, light->target, (light->enabled ? light->diffuse : GRAY));
-
- DrawSphereWires(light->position, 0.3f*light->intensity, 8, 8, (light->enabled ? light->diffuse : GRAY));
- DrawCubeWires(light->target, 0.3f, 0.3f, 0.3f, (light->enabled ? light->diffuse : GRAY));
- } break;
- case LIGHT_SPOT:
- {
- DrawLine3D(light->position, light->target, (light->enabled ? light->diffuse : GRAY));
-
- Vector3 dir = VectorSubtract(light->target, light->position);
- VectorNormalize(&dir);
-
- DrawCircle3D(light->position, 0.5f, dir, 0.0f, (light->enabled ? light->diffuse : GRAY));
-
- //DrawCylinderWires(light->position, 0.0f, 0.3f*light->coneAngle/50, 0.6f, 5, (light->enabled ? light->diffuse : GRAY));
- DrawCubeWires(light->target, 0.3f, 0.3f, 0.3f, (light->enabled ? light->diffuse : GRAY));
- } break;
- default: break;
- }
-}
+ Mesh mesh = { 0 };
-// Load a 3d model (from file)
-Model LoadModel(const char *fileName)
-{
- Model model = { 0 };
+ if (strcmp(GetExtension(fileName), "obj") == 0) mesh = LoadOBJ(fileName);
+ else TraceLog(WARNING, "[%s] Mesh extension not recognized, it can't be loaded", fileName);
- // TODO: Initialize default data for model in case loading fails, maybe a cube?
+ if (mesh.vertexCount == 0) TraceLog(WARNING, "Mesh could not be loaded");
+ else rlglLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh)
- if (strcmp(GetExtension(fileName), "obj") == 0) model.mesh = LoadOBJ(fileName);
- else TraceLog(WARNING, "[%s] Model extension not recognized, it can't be loaded", fileName);
+ // TODO: Initialize default mesh data in case loading fails, maybe a cube?
- if (model.mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded");
- else
- {
- rlglLoadMesh(&model.mesh, false); // Upload vertex data to GPU (static model)
+ return mesh;
+}
- model.transform = MatrixIdentity();
- model.material = LoadDefaultMaterial();
- }
+// Load mesh from vertex data
+// NOTE: All vertex data arrays must be same size: numVertex
+Mesh LoadMeshEx(int numVertex, float *vData, float *vtData, float *vnData, Color *cData)
+{
+ Mesh mesh = { 0 };
- return model;
+ mesh.vertexCount = numVertex;
+ mesh.triangleCount = numVertex/3;
+ mesh.vertices = vData;
+ mesh.texcoords = vtData;
+ mesh.texcoords2 = NULL;
+ mesh.normals = vnData;
+ mesh.tangents = NULL;
+ mesh.colors = (unsigned char *)cData;
+ mesh.indices = NULL;
+
+ rlglLoadMesh(&mesh, false); // Upload vertex data to GPU (static mesh)
+
+ return mesh;
}
-// Load a 3d model (from vertex data)
-Model LoadModelEx(Mesh data, bool dynamic)
+// Load model from file
+Model LoadModel(const char *fileName)
{
Model model = { 0 };
- model.mesh = data;
-
- rlglLoadMesh(&model.mesh, dynamic); // Upload vertex data to GPU
-
+ model.mesh = LoadMesh(fileName);
model.transform = MatrixIdentity();
model.material = LoadDefaultMaterial();
return model;
}
-// Load a 3d model from rRES file (raylib Resource)
-Model LoadModelFromRES(const char *rresName, int resId)
+// Load model from mesh data
+Model LoadModelFromMesh(Mesh data, bool dynamic)
{
Model model = { 0 };
- bool found = false;
-
- char id[4]; // rRES file identifier
- unsigned char version; // rRES file version and subversion
- char useless; // rRES header reserved data
- short numRes;
-
- ResInfoHeader infoHeader;
- FILE *rresFile = fopen(rresName, "rb");
-
- if (rresFile == NULL)
- {
- TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName);
- }
- else
- {
- // Read rres file (basic file check - id)
- fread(&id[0], sizeof(char), 1, rresFile);
- fread(&id[1], sizeof(char), 1, rresFile);
- fread(&id[2], sizeof(char), 1, rresFile);
- fread(&id[3], sizeof(char), 1, rresFile);
- fread(&version, sizeof(char), 1, rresFile);
- fread(&useless, sizeof(char), 1, rresFile);
-
- if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S'))
- {
- TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName);
- }
- else
- {
- // Read number of resources embedded
- fread(&numRes, sizeof(short), 1, rresFile);
-
- for (int i = 0; i < numRes; i++)
- {
- fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile);
-
- if (infoHeader.id == resId)
- {
- found = true;
-
- // Check data is of valid MODEL type
- if (infoHeader.type == 8)
- {
- // TODO: Load model data
- }
- else
- {
- TraceLog(WARNING, "[%s] Required resource do not seem to be a valid MODEL resource", rresName);
- }
- }
- else
- {
- // Depending on type, skip the right amount of parameters
- switch (infoHeader.type)
- {
- case 0: fseek(rresFile, 6, SEEK_CUR); break; // IMAGE: Jump 6 bytes of parameters
- case 1: fseek(rresFile, 6, SEEK_CUR); break; // SOUND: Jump 6 bytes of parameters
- case 2: fseek(rresFile, 5, SEEK_CUR); break; // MODEL: Jump 5 bytes of parameters (TODO: Review)
- case 3: break; // TEXT: No parameters
- case 4: break; // RAW: No parameters
- default: break;
- }
-
- // Jump DATA to read next infoHeader
- fseek(rresFile, infoHeader.size, SEEK_CUR);
- }
- }
- }
+ model.mesh = data;
- fclose(rresFile);
- }
+ rlglLoadMesh(&model.mesh, dynamic); // Upload vertex data to GPU
- if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId);
+ model.transform = MatrixIdentity();
+ model.material = LoadDefaultMaterial();
return model;
}
-// Load a heightmap image as a 3d model
+// Load heightmap model from image data
// NOTE: model map size is defined in generic units
Model LoadHeightmap(Image heightmap, Vector3 size)
{
@@ -747,7 +655,7 @@ Model LoadHeightmap(Image heightmap, Vector3 size)
return model;
}
-// Load a map image as a 3d model (cubes based)
+// Load cubes-based map model from image data
Model LoadCubicmap(Image cubicmap)
{
Model model = { 0 };
@@ -762,14 +670,19 @@ Model LoadCubicmap(Image cubicmap)
return model;
}
-// Unload 3d model from memory (mesh and material)
-void UnloadModel(Model model)
+// Unload mesh from memory (RAM and/or VRAM)
+void UnloadMesh(Mesh *mesh)
{
- rlglUnloadMesh(&model.mesh);
+ rlglUnloadMesh(mesh);
+}
+// Unload model from memory (RAM and/or VRAM)
+void UnloadModel(Model model)
+{
+ UnloadMesh(&model.mesh);
UnloadMaterial(model.material);
- TraceLog(INFO, "Unloaded model data from RAM and VRAM");
+ TraceLog(INFO, "Unloaded model data (mesh and material) from RAM and VRAM");
}
// Load material data (from file)
@@ -802,17 +715,6 @@ Material LoadDefaultMaterial(void)
return material;
}
-// Load standard material (uses material attributes and lighting shader)
-// NOTE: Standard shader supports multiple maps and lights
-Material LoadStandardMaterial(void)
-{
- Material material = LoadDefaultMaterial();
-
- material.shader = GetStandardShader();
-
- return material;
-}
-
// Unload material from memory
void UnloadMaterial(Material material)
{
@@ -1517,14 +1419,143 @@ bool CheckCollisionRayBox(Ray ray, BoundingBox box)
t[3] = (box.max.y - ray.position.y)/ray.direction.y;
t[4] = (box.min.z - ray.position.z)/ray.direction.z;
t[5] = (box.max.z - ray.position.z)/ray.direction.z;
- t[6] = fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5]));
- t[7] = fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5]));
+ t[6] = (float)fmax(fmax(fmin(t[0], t[1]), fmin(t[2], t[3])), fmin(t[4], t[5]));
+ t[7] = (float)fmin(fmin(fmax(t[0], t[1]), fmax(t[2], t[3])), fmax(t[4], t[5]));
collision = !(t[7] < 0 || t[6] > t[7]);
return collision;
}
+// Get collision info between ray and mesh
+RayHitInfo GetCollisionRayMesh(Ray ray, Mesh *mesh)
+{
+ RayHitInfo result = { 0 };
+
+ // If mesh doesn't have vertex data on CPU, can't test it.
+ if (!mesh->vertices) return result;
+
+ // mesh->triangleCount may not be set, vertexCount is more reliable
+ int triangleCount = mesh->vertexCount/3;
+
+ // Test against all triangles in mesh
+ for (int i = 0; i < triangleCount; i++)
+ {
+ Vector3 a, b, c;
+ Vector3 *vertdata = (Vector3 *)mesh->vertices;
+
+ if (mesh->indices)
+ {
+ a = vertdata[mesh->indices[i*3 + 0]];
+ b = vertdata[mesh->indices[i*3 + 1]];
+ c = vertdata[mesh->indices[i*3 + 2]];
+ }
+ else
+ {
+ a = vertdata[i*3 + 0];
+ b = vertdata[i*3 + 1];
+ c = vertdata[i*3 + 2];
+ }
+
+ RayHitInfo triHitInfo = GetCollisionRayTriangle(ray, a, b, c);
+
+ if (triHitInfo.hit)
+ {
+ // Save the closest hit triangle
+ if ((!result.hit) || (result.distance > triHitInfo.distance)) result = triHitInfo;
+ }
+ }
+
+ return result;
+}
+
+// Get collision info between ray and triangle
+// NOTE: Based on https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
+RayHitInfo GetCollisionRayTriangle(Ray ray, Vector3 p1, Vector3 p2, Vector3 p3)
+{
+ #define EPSILON 0.000001 // A small number
+
+ Vector3 edge1, edge2;
+ Vector3 p, q, tv;
+ float det, invDet, u, v, t;
+ RayHitInfo result = {0};
+
+ // Find vectors for two edges sharing V1
+ edge1 = VectorSubtract(p2, p1);
+ edge2 = VectorSubtract(p3, p1);
+
+ // Begin calculating determinant - also used to calculate u parameter
+ p = VectorCrossProduct(ray.direction, edge2);
+
+ // If determinant is near zero, ray lies in plane of triangle or ray is parallel to plane of triangle
+ det = VectorDotProduct(edge1, p);
+
+ // Avoid culling!
+ if ((det > -EPSILON) && (det < EPSILON)) return result;
+
+ invDet = 1.0f/det;
+
+ // Calculate distance from V1 to ray origin
+ tv = VectorSubtract(ray.position, p1);
+
+ // Calculate u parameter and test bound
+ u = VectorDotProduct(tv, p)*invDet;
+
+ // The intersection lies outside of the triangle
+ if ((u < 0.0f) || (u > 1.0f)) return result;
+
+ // Prepare to test v parameter
+ q = VectorCrossProduct(tv, edge1);
+
+ // Calculate V parameter and test bound
+ v = VectorDotProduct(ray.direction, q)*invDet;
+
+ // The intersection lies outside of the triangle
+ if ((v < 0.0f) || ((u + v) > 1.0f)) return result;
+
+ t = VectorDotProduct(edge2, q)*invDet;
+
+ if (t > EPSILON)
+ {
+ // Ray hit, get hit point and normal
+ result.hit = true;
+ result.distance = t;
+ result.hit = true;
+ result.hitNormal = VectorCrossProduct(edge1, edge2);
+ VectorNormalize(&result.hitNormal);
+ Vector3 rayDir = ray.direction;
+ VectorScale(&rayDir, t);
+ result.hitPosition = VectorAdd(ray.position, rayDir);
+ }
+
+ return result;
+}
+
+// Get collision info between ray and ground plane (Y-normal plane)
+RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight)
+{
+ #define EPSILON 0.000001 // A small number
+
+ RayHitInfo result = { 0 };
+
+ if (fabsf(ray.direction.y) > EPSILON)
+ {
+ float t = (ray.position.y - groundHeight)/-ray.direction.y;
+
+ if (t >= 0.0)
+ {
+ Vector3 rayDir = ray.direction;
+ VectorScale(&rayDir, t);
+ result.hit = true;
+ result.distance = t;
+ result.hitNormal = (Vector3){ 0.0, 1.0, 0.0 };
+ result.hitPosition = VectorAdd(ray.position, rayDir);
+ }
+ }
+
+ return result;
+}
+
// Calculate mesh bounding box limits
// NOTE: minVertex and maxVertex should be transformed by model transform matrix (position, scale, rotate)
BoundingBox CalculateBoundingBox(Mesh mesh)
diff --git a/src/physac.h b/src/physac.h
index e807ffa6..cb0e3f3c 100644
--- a/src/physac.h
+++ b/src/physac.h
@@ -1,11 +1,13 @@
/**********************************************************************************************
*
-* Physac - 2D Physics library for videogames
+* Physac v1.0 - 2D Physics library for videogames
*
-* Description: Physac is a small 2D physics engine written in pure C. The engine uses a fixed time-step thread loop
-* to simluate physics. A physics step contains the following phases: get collision information, apply dynamics,
-* collision solving and position correction. It uses a very simple struct for physic bodies with a position vector
-* to be used in any 3D rendering API.
+* DESCRIPTION:
+*
+* Physac is a small 2D physics engine written in pure C. The engine uses a fixed time-step thread loop
+* to simluate physics. A physics step contains the following phases: get collision information,
+* apply dynamics, collision solving and position correction. It uses a very simple struct for physic
+* bodies with a position vector to be used in any 3D rendering API.
*
* CONFIGURATION:
*
@@ -37,7 +39,8 @@
* Otherwise it will include stdlib.h and use the C standard library malloc()/free() function.
*
* VERY THANKS TO:
-* - Ramón Santamaria (@raysan5)
+* Ramón Santamaria (@raysan5)
+*
*
* LICENSE: zlib/libpng
*
@@ -239,9 +242,10 @@ PHYSACDEF void ClosePhysics(void);
// 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)
+#elif defined(__linux) || defined(PLATFORM_WEB)
#include <sys/time.h> // Required for: timespec
#include <time.h> // Required for: clock_gettime()
+ #include <stdint.h>
#endif
//----------------------------------------------------------------------------------
@@ -266,7 +270,7 @@ PHYSACDEF void ClosePhysics(void);
static unsigned int usedMemory = 0; // Total allocated dynamic memory
static bool physicsThreadEnabled = false; // Physics thread enabled state
static double currentTime = 0; // Current time in milliseconds
-#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(__linux) || defined(PLATFORM_WEB)
static double baseTime = 0; // Android and RPI platforms base time
#endif
static double startTime = 0; // Start time in milliseconds
@@ -1942,7 +1946,7 @@ static double GetCurrentTime(void)
{
double time = 0;
- #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
+ #if defined(_WIN32)
unsigned long long int clockFrequency, currentTime;
QueryPerformanceFrequency(&clockFrequency);
@@ -1951,7 +1955,7 @@ static double GetCurrentTime(void)
time = (double)((double)currentTime/clockFrequency)*1000;
#endif
- #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
+ #if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(__linux) || defined(PLATFORM_WEB)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
uint64_t temp = (uint64_t)ts.tv_sec*1000000000LLU + (uint64_t)ts.tv_nsec;
diff --git a/src/raylib.h b/src/raylib.h
index 6d67051e..b0f03bbe 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -1,10 +1,10 @@
/**********************************************************************************************
*
-* raylib 1.6.0 (www.raylib.com)
+* raylib v1.7.0 (www.raylib.com)
*
* A simple and easy-to-use library to learn videogames programming
*
-* Features:
+* 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)
@@ -12,16 +12,21 @@
* 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
-* Materials (diffuse, normal, specular) and Lighting (point, directional, spot) support
* 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]
+* Complete binding for Lua [rlua]
*
-* External libs:
+* NOTES:
+* 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)
+*
+* DEPENDENCIES:
* 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]
@@ -34,13 +39,8 @@
* 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 --
+* LICENSE: zlib/libpng
*
* 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:
@@ -98,13 +98,13 @@
#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
+#define FLAG_SHOW_LOGO 1 // Set to show raylib logo at startup
+#define FLAG_FULLSCREEN_MODE 2 // Set to run program in fullscreen
+#define FLAG_WINDOW_RESIZABLE 4 // Set to allow resizable window
+#define FLAG_WINDOW_DECORATED 8 // Set to show window decoration (frame and buttons)
+#define FLAG_WINDOW_TRANSPARENT 16 // Set to allow transparent window
+#define FLAG_MSAA_4X_HINT 32 // Set to try enabling MSAA 4X
+#define FLAG_VSYNC_HINT 64 // Set to try enabling V-Sync on GPU
// Keyboard Function Keys
#define KEY_SPACE 32
@@ -297,13 +297,9 @@
//----------------------------------------------------------------------------------
#ifndef __cplusplus
// Boolean type
- #ifndef __APPLE__
- #if !defined(_STDBOOL_H)
- typedef enum { false, true } bool;
- #define _STDBOOL_H
- #endif
- #else
- #include <stdbool.h>
+ #if !defined(_STDBOOL_H)
+ typedef enum { false, true } bool;
+ #define _STDBOOL_H
#endif
#endif
@@ -351,7 +347,7 @@ typedef struct Image {
int width; // Image base width
int height; // Image base height
int mipmaps; // Mipmap levels, 1 by default
- int format; // Data format (TextureFormat)
+ int format; // Data format (TextureFormat type)
} Image;
// Texture2D type, bpp always RGBA (32bit)
@@ -361,25 +357,31 @@ typedef struct Texture2D {
int width; // Texture base width
int height; // Texture base height
int mipmaps; // Mipmap levels, 1 by default
- int format; // Data format (TextureFormat)
+ int format; // Data format (TextureFormat type)
} Texture2D;
// RenderTexture2D type, for texture rendering
typedef struct RenderTexture2D {
- unsigned int id; // Render texture (fbo) id
+ unsigned int id; // OpenGL Framebuffer Object (FBO) id
Texture2D texture; // Color buffer attachment texture
Texture2D depth; // Depth buffer attachment texture
} RenderTexture2D;
+// SpriteFont character info
+typedef struct CharInfo {
+ int value; // Character value (Unicode)
+ Rectangle rec; // Character rectangle in sprite font
+ int offsetX; // Character offset X when drawing
+ int offsetY; // Character offset Y when drawing
+ int advanceX; // Character advance position X
+} CharInfo;
+
// 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)
+ int baseSize; // Base size (default chars height)
+ int charsCount; // Number of characters
+ CharInfo *chars; // Characters info data
} SpriteFont;
// Camera type, defines a camera position/orientation in 3d space
@@ -466,31 +468,20 @@ typedef struct Model {
Material material; // Shader and textures data
} Model;
-// 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 direction: 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;
-
// 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
@@ -549,7 +540,7 @@ typedef enum {
// 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 {
+typedef enum {
FILTER_POINT = 0, // No filter, just pixel aproximation
FILTER_BILINEAR, // Linear filtering
FILTER_TRILINEAR, // Trilinear filtering (linear with mipmaps)
@@ -581,12 +572,12 @@ typedef enum {
} Gestures;
// Camera system modes
-typedef enum {
- CAMERA_CUSTOM = 0,
- CAMERA_FREE,
- CAMERA_ORBITAL,
- CAMERA_FIRST_PERSON,
- CAMERA_THIRD_PERSON
+typedef enum {
+ CAMERA_CUSTOM = 0,
+ CAMERA_FREE,
+ CAMERA_ORBITAL,
+ CAMERA_FIRST_PERSON,
+ CAMERA_THIRD_PERSON
} CameraMode;
// Head Mounted Display devices
@@ -602,6 +593,34 @@ typedef enum {
HMD_FOVE_VR,
} VrDevice;
+// rRES data returned when reading a resource,
+// it contains all required data for user (24 byte)
+typedef struct RRESData {
+ 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;
+
+// RRESData type
+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_CHARDATA, // CharInfo data array
+ RRES_TYPE_DIRECTORY
+} RRESDataType;
+
+// RRES type (pointer to RRESData array)
+typedef struct RRESData *RRES;
+
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
@@ -624,6 +643,9 @@ RLAPI void CloseWindow(void); // Close Windo
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 void SetWindowIcon(Image image); // Set icon for window (only PLATFORM_DESKTOP)
+RLAPI void SetWindowPosition(int x, int y); // Set window position on screen (only PLATFORM_DESKTOP)
+RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window (fullscreen mode)
RLAPI int GetScreenWidth(void); // Get current screen width
RLAPI int GetScreenHeight(void); // Get current screen height
@@ -651,7 +673,7 @@ RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the
RLAPI Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix)
RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum)
-RLAPI float GetFPS(void); // Returns current FPS
+RLAPI int GetFPS(void); // Returns current FPS
RLAPI float GetFrameTime(void); // Returns time in seconds for one frame
RLAPI Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value
@@ -741,12 +763,14 @@ RLAPI void DrawPixel(int posX, int posY, Color color);
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 DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color); // Draw a line defining thickness
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 DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters
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
@@ -767,21 +791,19 @@ RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Ve
//------------------------------------------------------------------------------------
// Texture Loading and Drawing Functions (Module: textures)
//------------------------------------------------------------------------------------
-RLAPI Image LoadImage(const char *fileName); // Load an image into CPU memory (RAM)
-RLAPI Image LoadImageEx(Color *pixels, int width, int height); // Load image data from Color array data (RGBA - 32bit)
-RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image data from RAW file
-RLAPI Image LoadImageFromRES(const char *rresName, int resId); // Load an image from rRES file (raylib Resource)
-RLAPI Texture2D LoadTexture(const char *fileName); // Load an image as texture into GPU memory
-RLAPI Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat); // Load a texture from raw data into GPU memory
-RLAPI Texture2D LoadTextureFromRES(const char *rresName, int resId); // Load an image as texture from rRES file (raylib Resource)
-RLAPI Texture2D LoadTextureFromImage(Image image); // Load a texture from image data
-RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load a texture to be used for rendering
+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
-RLAPI void UnloadRenderTexture(RenderTexture2D target); // Unload render texture from GPU memory
+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, void *pixels); // Update GPU texture with new data
+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
@@ -794,7 +816,8 @@ RLAPI Image ImageText(const char *text, int fontSize, Color color);
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 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
@@ -802,7 +825,7 @@ RLAPI void ImageColorInvert(Image *image);
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 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
@@ -817,9 +840,9 @@ RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle dest
// Font Loading and Text Drawing Functions (Module: text)
//------------------------------------------------------------------------------------
RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont
-RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load a SpriteFont image into GPU memory
-RLAPI SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars); // Load a SpriteFont from TTF font with parameters
-RLAPI void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory
+RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load SpriteFont from file into GPU memory (VRAM)
+RLAPI SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int charsCount, 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
@@ -849,50 +872,58 @@ RLAPI void DrawPlane(Vector3 centerPos, Vector2 size, Color color);
RLAPI void DrawRay(Ray ray, Color color); // Draw a ray line
RLAPI void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0))
RLAPI void DrawGizmo(Vector3 position); // Draw simple gizmo
-RLAPI void DrawLight(Light light); // Draw light in 3D world
//DrawTorus(), DrawTeapot() could be useful?
//------------------------------------------------------------------------------------
// Model 3d Loading and Drawing Functions (Module: models)
//------------------------------------------------------------------------------------
-RLAPI Model LoadModel(const char *fileName); // Load a 3d model (.OBJ)
-RLAPI Model LoadModelEx(Mesh data, bool dynamic); // Load a 3d model (from mesh data)
-RLAPI Model LoadModelFromRES(const char *rresName, int resId); // Load a 3d model from rRES file (raylib Resource)
-RLAPI Model LoadHeightmap(Image heightmap, Vector3 size); // Load a heightmap image as a 3d model
-RLAPI Model LoadCubicmap(Image cubicmap); // Load a map image as a 3d model (cubes based)
-RLAPI void UnloadModel(Model model); // Unload 3d model from memory
-
-RLAPI Material LoadMaterial(const char *fileName); // Load material data (.MTL)
-RLAPI Material LoadDefaultMaterial(void); // Load default material (uses default models shader)
-RLAPI Material LoadStandardMaterial(void); // Load standard material (uses material attributes and lighting shader)
-RLAPI void UnloadMaterial(Material material); // Unload material textures from 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 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 with extended parameters and collision point detection
-RLAPI bool CheckCollisionRayBox(Ray ray, BoundingBox box); // Detect collision between ray and box
+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 Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations
-RLAPI void UnloadShader(Shader shader); // Unload a custom shader from memory
+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 Shader GetStandardShader(void); // Get standard shader
RLAPI Texture2D GetDefaultTexture(void); // Get default texture
RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
@@ -908,9 +939,6 @@ RLAPI void EndShaderMode(void); // End
RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied)
RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending)
-RLAPI Light CreateLight(int type, Vector3 position, Color diffuse); // Create a new light, initialize it and add to pool
-RLAPI void DestroyLight(Light light); // Destroy a light and take it out of the list
-
//------------------------------------------------------------------------------------
// VR experience Functions (Module: rlgl)
// NOTE: This functions are useless when using OpenGL 1.1
@@ -928,13 +956,13 @@ RLAPI void ToggleVrMode(void); // Enable/Disable VR experienc
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 void SetMasterVolume(float volume); // Set master volume (listener)
-RLAPI Wave LoadWave(const char *fileName); // Load wave data from file into RAM
-RLAPI Wave LoadWaveEx(float *data, int sampleCount, int sampleRate, int sampleSize, int channels); // Load wave data from float array data (32bit)
-RLAPI Sound LoadSound(const char *fileName); // Load sound to memory
-RLAPI Sound LoadSoundFromWave(Wave wave); // Load sound to memory from wave data
-RLAPI Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource)
-RLAPI void UpdateSound(Sound sound, void *data, int numSamples); // Update sound buffer with new data
+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 samplesCount);// 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
@@ -958,13 +986,14 @@ RLAPI void ResumeMusicStream(Music music); // Resume
RLAPI bool IsMusicPlaying(Music music); // Check if music is playing
RLAPI void SetMusicVolume(Music music, float volume); // Set volume for music (1.0 is max level)
RLAPI void SetMusicPitch(Music music, float pitch); // Set pitch for a music (1.0 is base level)
+RLAPI void SetMusicLoopCount(Music music, float count); // Set music loop count (loop repeats)
RLAPI float GetMusicTimeLength(Music music); // Get music time length (in seconds)
RLAPI float GetMusicTimePlayed(Music music); // Get current music time played (in seconds)
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, void *data, int numSamples); // Update audio stream buffers with data
+RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // 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
diff --git a/src/raymath.h b/src/raymath.h
index 10eabb6b..a2263f19 100644
--- a/src/raymath.h
+++ b/src/raymath.h
@@ -1,22 +1,23 @@
/**********************************************************************************************
*
-* raymath (header only file)
+* raymath v1.0 - Some useful functions to work with Vector3, Matrix and Quaternions
*
-* Some useful functions to work with Vector3, Matrix and Quaternions
+* CONFIGURATION:
*
-* You must:
-* #define RAYMATH_IMPLEMENTATION
-* before you include this file in *only one* C or C++ file to create the implementation.
+* #define RAYMATH_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.
*
-* Example:
-* #define RAYMATH_IMPLEMENTATION
-* #include "raymath.h"
+* #define RAYMATH_EXTERN_INLINE
+* Inlines all functions code, so it runs faster. This requires lots of memory on system.
+*
+* #define RAYMATH_STANDALONE
+* Avoid raylib.h header inclusion in this file.
+* Vector3 and Matrix data types are defined internally in raymath module.
*
-* You can also use:
-* #define RAYMATH_EXTERN_INLINE // Inlines all functions code, so it runs faster.
-* // This requires lots of memory on system.
-* #define RAYMATH_STANDALONE // Not dependent on raylib.h structs: Vector3, Matrix.
*
+* LICENSE: zlib/libpng
*
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
*
@@ -130,6 +131,7 @@ RMDEF void VectorTransform(Vector3 *v, Matrix mat); // Transforms a Ve
RMDEF Vector3 VectorZero(void); // Return a Vector3 init to zero
RMDEF Vector3 VectorMin(Vector3 vec1, Vector3 vec2); // Return min value for each pair of components
RMDEF Vector3 VectorMax(Vector3 vec1, Vector3 vec2); // Return max value for each pair of components
+RMDEF Vector3 Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c); // Barycenter coords for p in triangle abc
//------------------------------------------------------------------------------------
// Functions Declaration to work with Matrix
@@ -222,16 +224,16 @@ RMDEF Vector3 VectorPerpendicular(Vector3 v)
{
Vector3 result;
- float min = fabs(v.x);
+ float min = fabsf(v.x);
Vector3 cardinalAxis = {1.0f, 0.0f, 0.0f};
- if (fabs(v.y) < min)
+ if (fabsf(v.y) < min)
{
- min = fabs(v.y);
+ min = fabsf(v.y);
cardinalAxis = (Vector3){0.0f, 1.0f, 0.0f};
}
- if(fabs(v.z) < min)
+ if(fabsf(v.z) < min)
{
cardinalAxis = (Vector3){0.0f, 0.0f, 1.0f};
}
@@ -256,7 +258,7 @@ RMDEF float VectorLength(const Vector3 v)
{
float length;
- length = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
+ length = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
return length;
}
@@ -284,7 +286,7 @@ RMDEF void VectorNormalize(Vector3 *v)
length = VectorLength(*v);
- if (length == 0) length = 1.0f;
+ if (length == 0.0f) length = 1.0f;
ilength = 1.0f/length;
@@ -302,7 +304,7 @@ RMDEF float VectorDistance(Vector3 v1, Vector3 v2)
float dy = v2.y - v1.y;
float dz = v2.z - v1.z;
- result = sqrt(dx*dx + dy*dy + dz*dz);
+ result = sqrtf(dx*dx + dy*dy + dz*dz);
return result;
}
@@ -382,6 +384,32 @@ RMDEF Vector3 VectorMax(Vector3 vec1, Vector3 vec2)
return result;
}
+// Compute barycenter coordinates (u, v, w) for point p with respect to triangle (a, b, c)
+// NOTE: Assumes P is on the plane of the triangle
+RMDEF Vector3 Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c)
+{
+ //Vector v0 = b - a, v1 = c - a, v2 = p - a;
+
+ Vector3 v0 = VectorSubtract(b, a);
+ Vector3 v1 = VectorSubtract(c, a);
+ Vector3 v2 = VectorSubtract(p, a);
+ float d00 = VectorDotProduct(v0, v0);
+ float d01 = VectorDotProduct(v0, v1);
+ float d11 = VectorDotProduct(v1, v1);
+ float d20 = VectorDotProduct(v2, v0);
+ float d21 = VectorDotProduct(v2, v1);
+
+ float denom = d00*d11 - d01*d01;
+
+ Vector3 result;
+
+ result.y = (d11*d20 - d01*d21)/denom;
+ result.z = (d00*d21 - d01*d20)/denom;
+ result.x = 1.0f - (result.z + result.y);
+
+ return result;
+}
+
//----------------------------------------------------------------------------------
// Module Functions Definition - Matrix math
//----------------------------------------------------------------------------------
@@ -590,7 +618,7 @@ RMDEF Matrix MatrixRotate(Vector3 axis, float angle)
float x = axis.x, y = axis.y, z = axis.z;
- float length = sqrt(x*x + y*y + z*z);
+ float length = sqrtf(x*x + y*y + z*z);
if ((length != 1.0f) && (length != 0.0f))
{
diff --git a/src/rlgl.c b/src/rlgl.c
index b567f8fd..ffc9d741 100644
--- a/src/rlgl.c
+++ b/src/rlgl.c
@@ -2,30 +2,55 @@
*
* 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).
+* DESCRIPTION:
*
-* When chosing an OpenGL version greater than OpenGL 1.1, rlgl stores vertex data on internal
+* 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:
+* CONFIGURATION:
+*
+* #define GRAPHICS_API_OPENGL_11
+* Use OpenGL 1.1 backend
+*
+* #define GRAPHICS_API_OPENGL_21
+* Use OpenGL 2.1 backend
+*
+* #define GRAPHICS_API_OPENGL_33
+* Use OpenGL 3.3 Core profile backend
+*
+* #define GRAPHICS_API_OPENGL_ES2
+* Use OpenGL ES 2.0 backend
+*
+* #define RLGL_STANDALONE
+* Use rlgl as standalone library (no raylib dependency)
+*
+* #define RLGL_NO_DISTORTION_SHADER
+* Avoid stereo rendering distortion sahder (shader_distortion.h) inclusion
+*
+* #define SUPPORT_SHADER_DEFAULT / ENABLE_SHADER_DEFAULT
+*
+* #define SUPPORT_SHADER_DISTORTION
+*
+*
+* #define SUPPORT_OCULUS_RIFT_CV1 / RLGL_OCULUS_SUPPORT
+* Enable Oculus Rift CV1 functionality
+*
+* #define SUPPORT_STEREO_RENDERING
+*
+* #define RLGL_NO_DEFAULT_SHADER
+*
+* DEPENDENCIES:
* 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)
-* RLGL_NO_STANDARD_SHADER - Avoid standard shader (shader_standard.h) inclusion
-* RLGL_NO_DISTORTION_SHADER - Avoid stereo rendering distortion sahder (shader_distortion.h) inclusion
-* RLGL_OCULUS_SUPPORT - Enable Oculus Rift CV1 functionality
*
+* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
@@ -48,7 +73,7 @@
#include "rlgl.h"
-#include <stdio.h> // Required for: fopen(), fclose(), fread()... [Used only on ReadTextFile()]
+#include <stdio.h> // Required for: fopen(), fclose(), fread()... [Used only on LoadText()]
#include <stdlib.h> // Required for: malloc(), free(), rand()
#include <string.h> // Required for: strcmp(), strlen(), strtok()
#include <math.h> // Required for: atan2()
@@ -58,7 +83,7 @@
#endif
#if defined(GRAPHICS_API_OPENGL_11)
- #ifdef __APPLE__
+ #ifdef __APPLE__
#include <OpenGL/gl.h> // OpenGL 1.1 library for OSX
#else
#include <GL/gl.h> // OpenGL 1.1 library
@@ -70,7 +95,7 @@
#endif
#if defined(GRAPHICS_API_OPENGL_33)
- #ifdef __APPLE__
+ #ifdef __APPLE__
#include <OpenGL/gl3.h> // OpenGL 3 library for OSX
#else
#define GLAD_IMPLEMENTATION
@@ -92,10 +117,6 @@
#include <stdarg.h> // Required for: va_list, va_start(), vfprintf(), va_end() [Used only on TraceLog()]
#endif
-#if !defined(GRAPHICS_API_OPENGL_11) && !defined(RLGL_NO_STANDARD_SHADER)
- #include "shader_standard.h" // Standard shader to be embedded
-#endif
-
#if !defined(GRAPHICS_API_OPENGL_11) && !defined(RLGL_NO_DISTORTION_SHADER)
#include "shader_distortion.h" // Distortion shader to be embedded
#endif
@@ -118,8 +139,6 @@
#define MAX_DRAWS_BY_TEXTURE 256 // Draws are organized by texture changes
#define TEMP_VERTEX_BUFFER_SIZE 4096 // Temporal Vertex Buffer (required for vertex-transformations)
// NOTE: Every vertex are 3 floats (12 bytes)
-
-#define MAX_LIGHTS 8 // Max lights supported by standard shader
#ifndef GL_SHADING_LANGUAGE_VERSION
#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
@@ -175,7 +194,7 @@
#if defined(GRAPHICS_API_OPENGL_ES2)
#define glClearDepth glClearDepthf
- #define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER
+ #define GL_READ_FRAMEBUFFER GL_FRAMEBUFFER
#define GL_DRAW_FRAMEBUFFER GL_FRAMEBUFFER
#endif
@@ -192,7 +211,7 @@
//----------------------------------------------------------------------------------
// Dynamic vertex buffers (position + texcoords + colors + indices arrays)
-typedef struct {
+typedef struct DynamicBuffer {
int vCounter; // vertex position counter to process (and draw) from full buffer
int tcCounter; // vertex texcoord counter to process (and draw) from full buffer
int cCounter; // vertex color counter to process (and draw) from full buffer
@@ -211,7 +230,7 @@ typedef struct {
// Draw call type
// NOTE: Used to track required draw-calls, organized by texture
-typedef struct {
+typedef struct DrawCall {
int vertexCount;
GLuint vaoId;
GLuint textureId;
@@ -226,7 +245,7 @@ typedef struct {
} DrawCall;
// Head-Mounted-Display device parameters
-typedef struct {
+typedef struct VrDeviceInfo {
int hResolution; // HMD horizontal resolution in pixels
int vResolution; // HMD vertical resolution in pixels
float hScreenSize; // HMD horizontal size in meters
@@ -240,7 +259,7 @@ typedef struct {
} VrDeviceInfo;
// VR Stereo rendering configuration for simulator
-typedef struct {
+typedef struct VrStereoConfig {
RenderTexture2D stereoFbo; // VR stereo rendering framebuffer
Shader distortionShader; // VR stereo rendering distortion shader
//Rectangle eyesViewport[2]; // VR stereo rendering eyes viewports
@@ -305,10 +324,7 @@ static bool useTempBuffer = false;
// Shader Programs
static Shader defaultShader; // Basic shader, support vertex color and diffuse texture
-static Shader standardShader; // Shader with support for lighting and materials
- // NOTE: Lazy initialization when GetStandardShader()
static Shader currentShader; // Shader to be used on rendering (by default, defaultShader)
-static bool standardShaderLoaded = false; // Flag to track if standard shader has been loaded
// Extension supported flag: VAO
static bool vaoSupported = false; // VAO support (OpenGL ES2 could not support VAO extension)
@@ -318,6 +334,7 @@ static bool texCompETC1Supported = false; // ETC1 texture compression support
static bool texCompETC2Supported = false; // ETC2/EAC texture compression support
static bool texCompPVRTSupported = false; // PVR texture compression support
static bool texCompASTCSupported = false; // ASTC texture compression support
+#endif
// Extension supported flag: Anisotropic filtering
static bool texAnisotropicFilterSupported = false; // Anisotropic texture filtering support
@@ -325,7 +342,6 @@ static float maxAnisotropicLevel = 0.0f; // Maximum anisotropy level supp
// Extension supported flag: Clamp mirror wrap mode
static bool texClampMirrorSupported = false; // Clamp mirror wrap mode supported
-#endif
#if defined(RLGL_OCULUS_SUPPORT)
// OVR device variables
@@ -368,12 +384,6 @@ static unsigned int whiteTexture;
static int screenWidth; // Default framebuffer width
static int screenHeight; // Default framebuffer height
-// Lighting data
-static Light lights[MAX_LIGHTS]; // Lights pool
-static int lightsCount = 0; // Enabled lights counter
-static int lightsLocs[MAX_LIGHTS][8]; // Lights location points in shader: 8 possible points per light:
- // enabled, type, position, target, radius, diffuse, intensity, coneAngle
-
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
@@ -382,10 +392,8 @@ static void LoadCompressedTexture(unsigned char *data, int width, int height, in
static unsigned int LoadShaderProgram(const char *vShaderStr, const char *fShaderStr); // Load custom shader strings and return program id
static Shader LoadDefaultShader(void); // Load default shader (just vertex positioning and texture coloring)
-static Shader LoadStandardShader(void); // Load standard shader (support materials and lighting)
static void LoadDefaultShaderLocations(Shader *shader); // Bind default shader locations (attributes and uniforms)
static void UnloadDefaultShader(void); // Unload default shader
-static void UnloadStandardShader(void); // Unload standard shader
static void LoadDefaultBuffers(void); // Load default internal buffers (lines, triangles, quads)
static void UpdateDefaultBuffers(void); // Update default internal buffers (VAOs/VBOs) with vertex data
@@ -397,11 +405,6 @@ static void SetStereoConfig(VrDeviceInfo info);
// Set internal projection and modelview matrix depending on eyes tracking data
static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView);
-
-static void GetShaderLightsLocations(Shader shader); // Get shader locations for lights (up to MAX_LIGHTS)
-static void SetShaderLightsValues(Shader shader); // Set shader uniform values for lights
-
-static char *ReadTextFile(const char *fileName); // Read chars array from text file
#endif
#if defined(RLGL_OCULUS_SUPPORT)
@@ -718,7 +721,7 @@ void rlEnd(void)
} break;
default: break;
}
-
+
// NOTE: Depth increment is dependant on rlOrtho(): z-near and z-far values,
// as well as depth buffer bit-depth (16bit or 24bit or 32bit)
// Correct increment formula would be: depthInc = (zfar - znear)/pow(2, bits)
@@ -902,6 +905,10 @@ void rlDisableTexture(void)
#if defined(GRAPHICS_API_OPENGL_11)
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
+#else
+ // NOTE: If quads batch limit is reached,
+ // we force a draw call and next batch starts
+ if (quads.vCounter/4 >= MAX_QUADS_BATCH) rlglDraw();
#endif
}
@@ -922,11 +929,11 @@ void rlTextureParameters(unsigned int id, int param, int value)
case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break;
case RL_TEXTURE_ANISOTROPIC_FILTER:
{
- if (value <= maxAnisotropicLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, value);
+ if (value <= maxAnisotropicLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value);
else if (maxAnisotropicLevel > 0.0f)
{
TraceLog(WARNING, "[TEX ID %i] Maximum anisotropic filter level supported is %iX", id, maxAnisotropicLevel);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, value);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, (float)value);
}
else TraceLog(WARNING, "Anisotropic filtering not supported");
} break;
@@ -1001,7 +1008,7 @@ void rlDeleteRenderTextures(RenderTexture2D target)
if (target.id != 0) glDeleteFramebuffers(1, &target.id);
if (target.texture.id != 0) glDeleteTextures(1, &target.texture.id);
if (target.depth.id != 0) glDeleteTextures(1, &target.depth.id);
-
+
TraceLog(INFO, "[FBO ID %i] Unloaded render texture data from VRAM (GPU)", target.id);
#endif
}
@@ -1018,7 +1025,7 @@ void rlDeleteShader(unsigned int id)
void rlDeleteVertexArrays(unsigned int id)
{
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
- if (vaoSupported)
+ if (vaoSupported)
{
if (id != 0) glDeleteVertexArrays(1, &id);
TraceLog(INFO, "[VAO ID %i] Unloaded model data from VRAM (GPU)", id);
@@ -1080,7 +1087,7 @@ void rlglInit(int width, int height)
{
// Check OpenGL information and capabilities
//------------------------------------------------------------------------------
-
+
// Print current OpenGL and GLSL version
TraceLog(INFO, "GPU: Vendor: %s", glGetString(GL_VENDOR));
TraceLog(INFO, "GPU: Renderer: %s", glGetString(GL_RENDERER));
@@ -1091,14 +1098,14 @@ void rlglInit(int width, int height)
//int maxTexSize;
//glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
//TraceLog(INFO, "GL_MAX_TEXTURE_SIZE: %i", maxTexSize);
-
+
//GL_MAX_TEXTURE_IMAGE_UNITS
//GL_MAX_VIEWPORT_DIMS
//int numAuxBuffers;
//glGetIntegerv(GL_AUX_BUFFERS, &numAuxBuffers);
//TraceLog(INFO, "GL_AUX_BUFFERS: %i", numAuxBuffers);
-
+
//GLint numComp = 0;
//GLint format[32] = { 0 };
//glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &numComp);
@@ -1106,7 +1113,7 @@ void rlglInit(int width, int height)
//for (int i = 0; i < numComp; i++) TraceLog(INFO, "Supported compressed format: 0x%x", format[i]);
// NOTE: We don't need that much data on screen... right now...
-
+
#if defined(GRAPHICS_API_OPENGL_11)
//TraceLog(INFO, "OpenGL 1.1 (or driver default) profile initialized");
#endif
@@ -1114,7 +1121,7 @@ void rlglInit(int width, int height)
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Get supported extensions list
GLint numExt = 0;
-
+
#if defined(GRAPHICS_API_OPENGL_33)
// NOTE: On OpenGL 3.3 VAO and NPOT are supported by default
@@ -1124,18 +1131,18 @@ void rlglInit(int width, int height)
// We get a list of available extensions and we check for some of them (compressed textures)
// NOTE: We don't need to check again supported extensions but we do (GLAD already dealt with that)
glGetIntegerv(GL_NUM_EXTENSIONS, &numExt);
-
+
#ifdef _MSC_VER
const char **extList = malloc(sizeof(const char *)*numExt);
#else
const char *extList[numExt];
#endif
-
+
for (int i = 0; i < numExt; i++) extList[i] = (char *)glGetStringi(GL_EXTENSIONS, i);
-
+
#elif defined(GRAPHICS_API_OPENGL_ES2)
char *extensions = (char *)glGetString(GL_EXTENSIONS); // One big const string
-
+
// NOTE: We have to duplicate string because glGetString() returns a const value
// If not duplicated, it fails in some systems (Raspberry Pi)
// Equivalent to function: char *strdup(const char *str)
@@ -1144,12 +1151,12 @@ void rlglInit(int width, int height)
void *newstr = malloc(len);
if (newstr == NULL) extensionsDup = NULL;
extensionsDup = (char *)memcpy(newstr, extensions, len);
-
+
// NOTE: String could be splitted using strtok() function (string.h)
// NOTE: strtok() modifies the received string, it can not be const
-
+
char *extList[512]; // Allocate 512 strings pointers (2 KB)
-
+
extList[numExt] = strtok(extensionsDup, " ");
while (extList[numExt] != NULL)
@@ -1157,9 +1164,9 @@ void rlglInit(int width, int height)
numExt++;
extList[numExt] = strtok(NULL, " ");
}
-
+
free(extensionsDup); // Duplicated string must be deallocated
-
+
numExt -= 1;
#endif
@@ -1177,25 +1184,25 @@ void rlglInit(int width, int height)
if (strcmp(extList[i], (const char *)"GL_OES_vertex_array_object") == 0)
{
vaoSupported = true;
-
- // The extension is supported by our hardware and driver, try to get related functions pointers
+
+ // The extension is supported by our hardware and driver, try to get related functions pointers
// NOTE: emscripten does not support VAOs natively, it uses emulation and it reduces overall performance...
glGenVertexArrays = (PFNGLGENVERTEXARRAYSOESPROC)eglGetProcAddress("glGenVertexArraysOES");
glBindVertexArray = (PFNGLBINDVERTEXARRAYOESPROC)eglGetProcAddress("glBindVertexArrayOES");
glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSOESPROC)eglGetProcAddress("glDeleteVertexArraysOES");
//glIsVertexArray = (PFNGLISVERTEXARRAYOESPROC)eglGetProcAddress("glIsVertexArrayOES"); // NOTE: Fails in WebGL, omitted
}
-
+
// Check NPOT textures support
// NOTE: Only check on OpenGL ES, OpenGL 3.3 has NPOT textures full support as core feature
if (strcmp(extList[i], (const char *)"GL_OES_texture_npot") == 0) npotSupported = true;
#endif
-
+
// DDS texture compression support
if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) ||
(strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_s3tc") == 0) ||
- (strcmp(extList[i], (const char *)"GL_WEBKIT_WEBGL_compressed_texture_s3tc") == 0)) texCompDXTSupported = true;
-
+ (strcmp(extList[i], (const char *)"GL_WEBKIT_WEBGL_compressed_texture_s3tc") == 0)) texCompDXTSupported = true;
+
// ETC1 texture compression support
if ((strcmp(extList[i], (const char *)"GL_OES_compressed_ETC1_RGB8_texture") == 0) ||
(strcmp(extList[i], (const char *)"GL_WEBGL_compressed_texture_etc1") == 0)) texCompETC1Supported = true;
@@ -1208,26 +1215,26 @@ void rlglInit(int width, int height)
// ASTC texture compression support
if (strcmp(extList[i], (const char *)"GL_KHR_texture_compression_astc_hdr") == 0) texCompASTCSupported = true;
-
+
// Anisotropic texture filter support
if (strcmp(extList[i], (const char *)"GL_EXT_texture_filter_anisotropic") == 0)
{
texAnisotropicFilterSupported = true;
- glGetFloatv(0x84FF, &maxAnisotropicLevel); // GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
+ glGetFloatv(0x84FF, &maxAnisotropicLevel); // GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
}
-
+
// Clamp mirror wrap mode supported
if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) texClampMirrorSupported = true;
}
-
+
#ifdef _MSC_VER
free(extList);
#endif
-
+
#if defined(GRAPHICS_API_OPENGL_ES2)
if (vaoSupported) TraceLog(INFO, "[EXTENSION] VAO extension detected, VAO functions initialized successfully");
else TraceLog(WARNING, "[EXTENSION] VAO extension not found, VAO usage not supported");
-
+
if (npotSupported) TraceLog(INFO, "[EXTENSION] NPOT textures extension detected, full NPOT textures supported");
else TraceLog(WARNING, "[EXTENSION] NPOT textures extension not found, limited NPOT support (no-mipmaps, no-repeat)");
#endif
@@ -1237,13 +1244,13 @@ void rlglInit(int width, int height)
if (texCompETC2Supported) TraceLog(INFO, "[EXTENSION] ETC2/EAC compressed textures supported");
if (texCompPVRTSupported) TraceLog(INFO, "[EXTENSION] PVRT compressed textures supported");
if (texCompASTCSupported) TraceLog(INFO, "[EXTENSION] ASTC compressed textures supported");
-
+
if (texAnisotropicFilterSupported) TraceLog(INFO, "[EXTENSION] Anisotropic textures filtering supported (max: %.0fX)", maxAnisotropicLevel);
if (texClampMirrorSupported) TraceLog(INFO, "[EXTENSION] Clamp mirror wrap texture mode supported");
// Initialize buffers, default shaders and default textures
//----------------------------------------------------------
-
+
// Init default white texture
unsigned char pixels[4] = { 255, 255, 255, 255 }; // 1 pixel RGBA (4 bytes)
@@ -1257,7 +1264,7 @@ void rlglInit(int width, int height)
currentShader = defaultShader;
// Init default vertex arrays buffers (lines, triangles, quads)
- LoadDefaultBuffers();
+ LoadDefaultBuffers();
// Init temp vertex buffer, used when transformation required (translate, rotate, scale)
tempBuffer = (Vector3 *)malloc(sizeof(Vector3)*TEMP_VERTEX_BUFFER_SIZE);
@@ -1276,7 +1283,7 @@ void rlglInit(int width, int height)
drawsCounter = 1;
draws[drawsCounter - 1].textureId = whiteTexture;
currentDrawMode = RL_TRIANGLES; // Set default draw mode
-
+
// Init internal matrix stack (emulating OpenGL 1.1)
for (int i = 0; i < MATRIX_STACK_SIZE; i++) stack[i] = MatrixIdentity();
@@ -1305,7 +1312,7 @@ void rlglInit(int width, int height)
#if defined(GRAPHICS_API_OPENGL_11)
// Init state: Color hints (deprecated in OpenGL 3.0+)
- glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation
+ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation
glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation)
#endif
@@ -1313,7 +1320,7 @@ void rlglInit(int width, int height)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set clear color (black)
glClearDepth(1.0f); // Set clear depth value (default)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear color and depth buffers (depth buffer required for 3D)
-
+
// Store screen size into global variables
screenWidth = width;
screenHeight = height;
@@ -1326,19 +1333,11 @@ void rlglClose(void)
{
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
UnloadDefaultShader();
- UnloadStandardShader();
UnloadDefaultBuffers();
-
+
// Delete default white texture
glDeleteTextures(1, &whiteTexture);
TraceLog(INFO, "[TEX ID %i] Unloaded texture data (base white texture) from VRAM", whiteTexture);
-
- // Unload lights
- if (lightsCount > 0)
- {
- for (int i = 0; i < lightsCount; i++) free(lights[i]);
- lightsCount = 0;
- }
free(draws);
#endif
@@ -1353,7 +1352,7 @@ void rlglDraw(void)
// NOTE: Default buffers upload and draw
UpdateDefaultBuffers();
-
+
if (vrEnabled && vrRendering) DrawDefaultBuffers(2);
else DrawDefaultBuffers(1);
#endif
@@ -1369,7 +1368,7 @@ void rlglLoadExtensions(void *loader)
if (!gladLoadGLLoader((GLADloadproc)loader)) TraceLog(WARNING, "GLAD: Cannot load OpenGL extensions");
else TraceLog(INFO, "GLAD: OpenGL extensions loaded successfully");
#endif
-
+
#if defined(GRAPHICS_API_OPENGL_21)
#ifndef __APPLE__
if (GLAD_GL_VERSION_2_1) TraceLog(INFO, "OpenGL 2.1 profile supported");
@@ -1390,17 +1389,17 @@ void rlglLoadExtensions(void *loader)
Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view)
{
Vector3 result = { 0.0f, 0.0f, 0.0f };
-
+
// Calculate unproject matrix (multiply projection matrix and view matrix) and invert it
Matrix matProjView = MatrixMultiply(proj, view);
MatrixInvert(&matProjView);
-
+
// Create quaternion from source point
Quaternion quat = { source.x, source.y, source.z, 1.0f };
-
+
// Multiply quat point by unproject matrix
QuaternionTransform(&quat, matProjView);
-
+
// Normalized world points in vectors
result.x = quat.x/quat.w;
result.y = quat.y/quat.w;
@@ -1415,41 +1414,41 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding
GLuint id = 0;
-
+
// Check texture format support by OpenGL 1.1 (compressed textures not supported)
-#if defined(GRAPHICS_API_OPENGL_11)
+#if defined(GRAPHICS_API_OPENGL_11)
if (textureFormat >= 8)
{
TraceLog(WARNING, "OpenGL 1.1 does not support GPU compressed texture formats");
return id;
}
#endif
-
+
if ((!texCompDXTSupported) && ((textureFormat == COMPRESSED_DXT1_RGB) || (textureFormat == COMPRESSED_DXT1_RGBA) ||
(textureFormat == COMPRESSED_DXT3_RGBA) || (textureFormat == COMPRESSED_DXT5_RGBA)))
{
TraceLog(WARNING, "DXT compressed texture format not supported");
return id;
}
-#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
if ((!texCompETC1Supported) && (textureFormat == COMPRESSED_ETC1_RGB))
{
TraceLog(WARNING, "ETC1 compressed texture format not supported");
return id;
}
-
+
if ((!texCompETC2Supported) && ((textureFormat == COMPRESSED_ETC2_RGB) || (textureFormat == COMPRESSED_ETC2_EAC_RGBA)))
{
TraceLog(WARNING, "ETC2 compressed texture format not supported");
return id;
}
-
+
if ((!texCompPVRTSupported) && ((textureFormat == COMPRESSED_PVRT_RGB) || (textureFormat == COMPRESSED_PVRT_RGBA)))
{
TraceLog(WARNING, "PVRT compressed texture format not supported");
return id;
}
-
+
if ((!texCompASTCSupported) && ((textureFormat == COMPRESSED_ASTC_4x4_RGBA) || (textureFormat == COMPRESSED_ASTC_8x8_RGBA)))
{
TraceLog(WARNING, "ASTC compressed texture format not supported");
@@ -1477,24 +1476,24 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
// GL_RGBA4 GL_RGBA GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_4_4_4_4
// GL_RGBA8 GL_RGBA GL_UNSIGNED_BYTE
// GL_RGB8 GL_RGB GL_UNSIGNED_BYTE
-
+
switch (textureFormat)
{
case UNCOMPRESSED_GRAYSCALE:
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, (unsigned char *)data);
-
+
// With swizzleMask we define how a one channel texture will be mapped to RGBA
// Required GL >= 3.3 or EXT_texture_swizzle/ARB_texture_swizzle
GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_ONE };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
-
+
TraceLog(INFO, "[TEX ID %i] Grayscale texture loaded and swizzled", id);
} break;
case UNCOMPRESSED_GRAY_ALPHA:
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, width, height, 0, GL_RG, GL_UNSIGNED_BYTE, (unsigned char *)data);
-
+
GLint swizzleMask[] = { GL_RED, GL_RED, GL_RED, GL_GREEN };
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
} break;
@@ -1568,7 +1567,7 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
// Magnification and minification filters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Alternative: GL_LINEAR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Alternative: GL_LINEAR
-
+
#if defined(GRAPHICS_API_OPENGL_33)
if (mipmapCount > 1)
{
@@ -1578,7 +1577,7 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
#endif
// At this point we have the texture loaded in GPU and texture parameters configured
-
+
// NOTE: If mipmaps were not in data, they are not generated automatically
// Unbind current texture
@@ -1594,15 +1593,15 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
RenderTexture2D rlglLoadRenderTexture(int width, int height)
{
RenderTexture2D target;
-
+
target.id = 0;
-
+
target.texture.id = 0;
target.texture.width = width;
target.texture.height = height;
target.texture.format = UNCOMPRESSED_R8G8B8A8;
target.texture.mipmaps = 1;
-
+
target.depth.id = 0;
target.depth.width = width;
target.depth.height = height;
@@ -1619,13 +1618,13 @@ RenderTexture2D rlglLoadRenderTexture(int width, int height)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
-
+
#if defined(GRAPHICS_API_OPENGL_33)
#define USE_DEPTH_TEXTURE
#else
#define USE_DEPTH_RENDERBUFFER
#endif
-
+
#if defined(USE_DEPTH_RENDERBUFFER)
// Create the renderbuffer that will serve as the depth attachment for the framebuffer.
glGenRenderbuffers(1, &target.depth.id);
@@ -1661,7 +1660,7 @@ RenderTexture2D rlglLoadRenderTexture(int width, int height)
if (status != GL_FRAMEBUFFER_COMPLETE)
{
TraceLog(WARNING, "Framebuffer object could not be created...");
-
+
switch (status)
{
case GL_FRAMEBUFFER_UNSUPPORTED: TraceLog(WARNING, "Framebuffer is unsupported"); break;
@@ -1672,21 +1671,21 @@ RenderTexture2D rlglLoadRenderTexture(int width, int height)
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete missing attachment"); break;
default: break;
}
-
+
glDeleteTextures(1, &target.texture.id);
glDeleteTextures(1, &target.depth.id);
glDeleteFramebuffers(1, &target.id);
}
else TraceLog(INFO, "[FBO ID %i] Framebuffer object created successfully", target.id);
-
+
glBindFramebuffer(GL_FRAMEBUFFER, 0);
#endif
- return target;
+ return target;
}
// Update already loaded texture in GPU with new data
-void rlglUpdateTexture(unsigned int id, int width, int height, int format, void *data)
+void rlglUpdateTexture(unsigned int id, int width, int height, int format, const void *data)
{
glBindTexture(GL_TEXTURE_2D, id);
@@ -1719,31 +1718,31 @@ void rlglUpdateTexture(unsigned int id, int width, int height, int format, void
}
// Generate mipmap data for selected texture
-void rlglGenerateMipmaps(Texture2D texture)
+void rlglGenerateMipmaps(Texture2D *texture)
{
- glBindTexture(GL_TEXTURE_2D, texture.id);
-
+ glBindTexture(GL_TEXTURE_2D, texture->id);
+
// Check if texture is power-of-two (POT)
bool texIsPOT = false;
-
- if (((texture.width > 0) && ((texture.width & (texture.width - 1)) == 0)) &&
- ((texture.height > 0) && ((texture.height & (texture.height - 1)) == 0))) texIsPOT = true;
+
+ if (((texture->width > 0) && ((texture->width & (texture->width - 1)) == 0)) &&
+ ((texture->height > 0) && ((texture->height & (texture->height - 1)) == 0))) texIsPOT = true;
if ((texIsPOT) || (npotSupported))
{
#if defined(GRAPHICS_API_OPENGL_11)
// Compute required mipmaps
- void *data = rlglReadTexturePixels(texture);
-
+ void *data = rlglReadTexturePixels(*texture);
+
// NOTE: data size is reallocated to fit mipmaps data
// NOTE: CPU mipmap generation only supports RGBA 32bit data
- int mipmapCount = GenerateMipmaps(data, texture.width, texture.height);
+ int mipmapCount = GenerateMipmaps(data, texture->width, texture->height);
- int size = texture.width*texture.height*4; // RGBA 32bit only
+ int size = texture->width*texture->height*4; // RGBA 32bit only
int offset = size;
- int mipWidth = texture.width/2;
- int mipHeight = texture.height/2;
+ int mipWidth = texture->width/2;
+ int mipHeight = texture->height/2;
// Load the mipmaps
for (int level = 1; level < mipmapCount; level++)
@@ -1756,24 +1755,30 @@ void rlglGenerateMipmaps(Texture2D texture)
mipWidth /= 2;
mipHeight /= 2;
}
-
- TraceLog(WARNING, "[TEX ID %i] Mipmaps generated manually on CPU side", texture.id);
-
+
+ TraceLog(WARNING, "[TEX ID %i] Mipmaps generated manually on CPU side", texture->id);
+
// NOTE: Once mipmaps have been generated and data has been uploaded to GPU VRAM, we can discard RAM data
free(data);
-
+
+ texture->mipmaps = mipmapCount + 1;
#endif
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
//glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE); // Hint for mipmaps generation algorythm: GL_FASTEST, GL_NICEST, GL_DONT_CARE
glGenerateMipmap(GL_TEXTURE_2D); // Generate mipmaps automatically
- TraceLog(INFO, "[TEX ID %i] Mipmaps generated automatically", texture.id);
+ TraceLog(INFO, "[TEX ID %i] Mipmaps generated automatically", texture->id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate Trilinear filtering for mipmaps (must be available)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate Trilinear filtering for mipmaps
+
+ #define MIN(a,b) (((a)<(b))?(a):(b))
+ #define MAX(a,b) (((a)>(b))?(a):(b))
+
+ texture->mipmaps = 1 + (int)floor(log(MAX(texture->width, texture->height))/log(2));
#endif
}
- else TraceLog(WARNING, "[TEX ID %i] Mipmaps can not be generated", texture.id);
+ else TraceLog(WARNING, "[TEX ID %i] Mipmaps can not be generated", texture->id);
glBindTexture(GL_TEXTURE_2D, 0);
}
@@ -1789,7 +1794,7 @@ void rlglLoadMesh(Mesh *mesh, bool dynamic)
mesh->vboId[4] = 0; // Vertex tangents VBO
mesh->vboId[5] = 0; // Vertex texcoords2 VBO
mesh->vboId[6] = 0; // Vertex indices VBO
-
+
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
int drawHint = GL_STATIC_DRAW;
if (dynamic) drawHint = GL_DYNAMIC_DRAW;
@@ -1804,8 +1809,8 @@ void rlglLoadMesh(Mesh *mesh, bool dynamic)
glBindVertexArray(vaoId);
}
- // NOTE: Attributes must be uploaded considering default locations points
-
+ // NOTE: Attributes must be uploaded considering default locations points
+
// Enable vertex attributes: position (shader-location = 0)
glGenBuffers(1, &vboId[0]);
glBindBuffer(GL_ARRAY_BUFFER, vboId[0]);
@@ -1835,7 +1840,7 @@ void rlglLoadMesh(Mesh *mesh, bool dynamic)
glVertexAttrib3f(2, 1.0f, 1.0f, 1.0f);
glDisableVertexAttribArray(2);
}
-
+
// Default color vertex attribute (shader-location = 3)
if (mesh->colors != NULL)
{
@@ -1851,7 +1856,7 @@ void rlglLoadMesh(Mesh *mesh, bool dynamic)
glVertexAttrib4f(3, 1.0f, 1.0f, 1.0f, 1.0f);
glDisableVertexAttribArray(3);
}
-
+
// Default tangent vertex attribute (shader-location = 4)
if (mesh->tangents != NULL)
{
@@ -1867,7 +1872,7 @@ void rlglLoadMesh(Mesh *mesh, bool dynamic)
glVertexAttrib3f(4, 0.0f, 0.0f, 0.0f);
glDisableVertexAttribArray(4);
}
-
+
// Default texcoord2 vertex attribute (shader-location = 5)
if (mesh->texcoords2 != NULL)
{
@@ -1883,7 +1888,7 @@ void rlglLoadMesh(Mesh *mesh, bool dynamic)
glVertexAttrib2f(5, 0.0f, 0.0f);
glDisableVertexAttribArray(5);
}
-
+
if (mesh->indices != NULL)
{
glGenBuffers(1, &vboId[6]);
@@ -1921,7 +1926,7 @@ void rlglUpdateMesh(Mesh mesh, int buffer, int numVertex)
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Activate mesh VAO
if (vaoSupported) glBindVertexArray(mesh.vaoId);
-
+
switch (buffer)
{
case 0: // Update vertices (vertex position)
@@ -1929,44 +1934,44 @@ void rlglUpdateMesh(Mesh mesh, int buffer, int numVertex)
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*numVertex, mesh.vertices, GL_DYNAMIC_DRAW);
else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*numVertex, mesh.vertices);
-
+
} break;
case 1: // Update texcoords (vertex texture coordinates)
{
glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*numVertex, mesh.texcoords, GL_DYNAMIC_DRAW);
else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*numVertex, mesh.texcoords);
-
+
} break;
case 2: // Update normals (vertex normals)
{
- glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
+ glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]);
if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*numVertex, mesh.normals, GL_DYNAMIC_DRAW);
else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*numVertex, mesh.normals);
-
+
} break;
case 3: // Update colors (vertex colors)
{
- glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]);
+ glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[3]);
if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*numVertex, mesh.colors, GL_DYNAMIC_DRAW);
else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*numVertex, mesh.colors);
-
+
} break;
case 4: // Update tangents (vertex tangents)
{
- glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
+ glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]);
if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*numVertex, mesh.tangents, GL_DYNAMIC_DRAW);
else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*numVertex, mesh.tangents);
} break;
case 5: // Update texcoords2 (vertex second texture coordinates)
{
- glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
+ glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[5]);
if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*numVertex, mesh.texcoords2, GL_DYNAMIC_DRAW);
else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*numVertex, mesh.texcoords2);
} break;
default: break;
}
-
+
// Unbind the current VAO
if (vaoSupported) glBindVertexArray(0);
@@ -1994,13 +1999,11 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords); // Pointer to texture coords array
if (mesh.normals != NULL) glNormalPointer(GL_FLOAT, 0, mesh.normals); // Pointer to normals array
if (mesh.colors != NULL) glColorPointer(4, GL_UNSIGNED_BYTE, 0, mesh.colors); // Pointer to colors array
-
- // TODO: Support OpenGL 1.1 lighting system
rlPushMatrix();
rlMultMatrixf(MatrixToFloat(transform));
rlColor4ub(material.colDiffuse.r, material.colDiffuse.g, material.colDiffuse.b, material.colDiffuse.a);
-
+
if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, mesh.indices);
else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
rlPopMatrix();
@@ -2019,13 +2022,13 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
if (vrEnabled) eyesCount = 2;
glUseProgram(material.shader.id);
-
+
// Upload to shader material.colDiffuse
glUniform4f(material.shader.colDiffuseLoc, (float)material.colDiffuse.r/255, (float)material.colDiffuse.g/255, (float)material.colDiffuse.b/255, (float)material.colDiffuse.a/255);
-
+
// Upload to shader material.colAmbient (if available)
if (material.shader.colAmbientLoc != -1) glUniform4f(material.shader.colAmbientLoc, (float)material.colAmbient.r/255, (float)material.colAmbient.g/255, (float)material.colAmbient.b/255, (float)material.colAmbient.a/255);
-
+
// Upload to shader material.colSpecular (if available)
if (material.shader.colSpecularLoc != -1) glUniform4f(material.shader.colSpecularLoc, (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255);
@@ -2033,7 +2036,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
// That's because Begin3dMode() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix()
Matrix matView = modelview; // View matrix (camera)
Matrix matProjection = projection; // Projection matrix (perspective)
-
+
// Calculate model-view matrix combining matModel and matView
Matrix matModelView = MatrixMultiply(transform, matView); // Transform to camera-space coordinates
@@ -2049,7 +2052,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
Matrix transInvTransform = transform;
MatrixTranspose(&transInvTransform);
MatrixInvert(&transInvTransform);
-
+
// Send model transformations matrix to shader
glUniformMatrix4fv(modelMatrixLoc, 1, false, MatrixToFloat(transInvTransform));
}
@@ -2062,11 +2065,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
// Check if glossiness is located in shader and upload value
int glossinessLoc = glGetUniformLocation(material.shader.id, "glossiness");
if (glossinessLoc != -1) glUniform1f(glossinessLoc, material.glossiness);
-
- // Set shader lights values for enabled lights
- // NOTE: Lights array location points are obtained on shader loading (if available)
- if (lightsCount > 0) SetShaderLightsValues(material.shader);
- }
+ }
// Set shader textures (diffuse, normal, specular)
glActiveTexture(GL_TEXTURE0);
@@ -2077,22 +2076,22 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
{
// Upload to shader specular map flag
glUniform1i(glGetUniformLocation(material.shader.id, "useNormal"), 1);
-
+
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, material.texNormal.id);
glUniform1i(material.shader.mapTexture1Loc, 1); // Normal texture fits in active texture unit 1
}
-
+
if ((material.texSpecular.id != 0) && (material.shader.mapTexture2Loc != -1))
{
// Upload to shader specular map flag
glUniform1i(glGetUniformLocation(material.shader.id, "useSpecular"), 1);
-
+
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, material.texSpecular.id);
glUniform1i(material.shader.mapTexture2Loc, 2); // Specular texture fits in active texture unit 2
}
-
+
if (vaoSupported)
{
glBindVertexArray(mesh.vaoId);
@@ -2116,7 +2115,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
glVertexAttribPointer(material.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(material.shader.normalLoc);
}
-
+
// Bind mesh VBO data: vertex colors (shader-location = 3, if available)
if (material.shader.colorLoc != -1)
{
@@ -2134,7 +2133,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
glDisableVertexAttribArray(material.shader.colorLoc);
}
}
-
+
// Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
if (material.shader.tangentLoc != -1)
{
@@ -2142,7 +2141,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
glVertexAttribPointer(material.shader.tangentLoc, 3, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(material.shader.tangentLoc);
}
-
+
// Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
if (material.shader.texcoord2Loc != -1)
{
@@ -2150,7 +2149,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
glVertexAttribPointer(material.shader.texcoord2Loc, 2, GL_FLOAT, 0, 0, 0);
glEnableVertexAttribArray(material.shader.texcoord2Loc);
}
-
+
if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]);
}
@@ -2169,13 +2168,13 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, 0); // Indexed vertices draw
else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
}
-
+
if (material.texNormal.id != 0)
{
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
}
-
+
if (material.texSpecular.id != 0)
{
glActiveTexture(GL_TEXTURE2);
@@ -2193,7 +2192,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
}
glUseProgram(0); // Unbind shader program
-
+
// Restore projection/modelview matrices
projection = matProjection;
modelview = matView;
@@ -2225,7 +2224,7 @@ void rlglUnloadMesh(Mesh *mesh)
// Read screen pixel data (color buffer)
unsigned char *rlglReadScreenPixels(int width, int height)
{
- unsigned char *screenData = (unsigned char *)malloc(width*height*sizeof(unsigned char)*4);
+ unsigned char *screenData = (unsigned char *)calloc(width*height*4, sizeof(unsigned char));
// NOTE: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, screenData);
@@ -2239,7 +2238,7 @@ unsigned char *rlglReadScreenPixels(int width, int height)
{
// Flip line
imgData[((height - 1) - y)*width*4 + x] = screenData[(y*width*4) + x];
-
+
// Set alpha component value to 255 (no trasparent image retrieval)
// NOTE: Alpha value has already been applied to RGB in framebuffer, we don't need it!
if (((x + 1)%4) == 0) imgData[((height - 1) - y)*width*4 + x] = 255;
@@ -2257,10 +2256,10 @@ unsigned char *rlglReadScreenPixels(int width, int height)
void *rlglReadTexturePixels(Texture2D texture)
{
void *pixels = NULL;
-
+
#if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
glBindTexture(GL_TEXTURE_2D, texture.id);
-
+
// NOTE: Using texture.id, we can retrieve some texture info (but not on OpenGL ES 2.0)
/*
int width, height, format;
@@ -2269,11 +2268,11 @@ void *rlglReadTexturePixels(Texture2D texture)
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &format);
// Other texture info: GL_TEXTURE_RED_SIZE, GL_TEXTURE_GREEN_SIZE, GL_TEXTURE_BLUE_SIZE, GL_TEXTURE_ALPHA_SIZE
*/
-
+
int glFormat = 0, glType = 0;
unsigned int size = texture.width*texture.height;
-
+
// NOTE: GL_LUMINANCE and GL_LUMINANCE_ALPHA are removed since OpenGL 3.1
// Must be replaced by GL_RED and GL_RG on Core OpenGL 3.3
@@ -2282,8 +2281,8 @@ void *rlglReadTexturePixels(Texture2D texture)
#if defined(GRAPHICS_API_OPENGL_11)
case UNCOMPRESSED_GRAYSCALE: pixels = (unsigned char *)malloc(size); glFormat = GL_LUMINANCE; glType = GL_UNSIGNED_BYTE; break; // 8 bit per pixel (no alpha)
case UNCOMPRESSED_GRAY_ALPHA: pixels = (unsigned char *)malloc(size*2); glFormat = GL_LUMINANCE_ALPHA; glType = GL_UNSIGNED_BYTE; break; // 16 bpp (2 channels)
-#elif defined(GRAPHICS_API_OPENGL_33)
- case UNCOMPRESSED_GRAYSCALE: pixels = (unsigned char *)malloc(size); glFormat = GL_RED; glType = GL_UNSIGNED_BYTE; break;
+#elif defined(GRAPHICS_API_OPENGL_33)
+ case UNCOMPRESSED_GRAYSCALE: pixels = (unsigned char *)malloc(size); glFormat = GL_RED; glType = GL_UNSIGNED_BYTE; break;
case UNCOMPRESSED_GRAY_ALPHA: pixels = (unsigned char *)malloc(size*2); glFormat = GL_RG; glType = GL_UNSIGNED_BYTE; break;
#endif
case UNCOMPRESSED_R5G6B5: pixels = (unsigned short *)malloc(size); glFormat = GL_RGB; glType = GL_UNSIGNED_SHORT_5_6_5; break; // 16 bpp
@@ -2293,15 +2292,15 @@ void *rlglReadTexturePixels(Texture2D texture)
case UNCOMPRESSED_R8G8B8A8: pixels = (unsigned char *)malloc(size*4); glFormat = GL_RGBA; glType = GL_UNSIGNED_BYTE; break; // 32 bpp
default: TraceLog(WARNING, "Texture data retrieval, format not suported"); break;
}
-
+
// NOTE: Each row written to or read from by OpenGL pixel operations like glGetTexImage are aligned to a 4 byte boundary by default, which may add some padding.
- // Use glPixelStorei to modify padding with the GL_[UN]PACK_ALIGNMENT setting.
- // GL_PACK_ALIGNMENT affects operations that read from OpenGL memory (glReadPixels, glGetTexImage, etc.)
+ // Use glPixelStorei to modify padding with the GL_[UN]PACK_ALIGNMENT setting.
+ // GL_PACK_ALIGNMENT affects operations that read from OpenGL memory (glReadPixels, glGetTexImage, etc.)
// GL_UNPACK_ALIGNMENT affects operations that write to OpenGL memory (glTexImage, etc.)
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glGetTexImage(GL_TEXTURE_2D, 0, glFormat, glType, pixels);
-
+
glBindTexture(GL_TEXTURE_2D, 0);
#endif
@@ -2312,7 +2311,7 @@ void *rlglReadTexturePixels(Texture2D texture)
// NOTE: Two possible Options:
// 1 - Bind texture to color fbo attachment and glReadPixels()
// 2 - Create an fbo, activate it, render quad with texture, glReadPixels()
-
+
#define GET_TEXTURE_FBO_OPTION_1 // It works
#if defined(GET_TEXTURE_FBO_OPTION_1)
@@ -2322,48 +2321,48 @@ void *rlglReadTexturePixels(Texture2D texture)
// Attach our texture to FBO -> Texture must be RGB
// NOTE: Previoust attached texture is automatically detached
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.id, 0);
-
+
pixels = (unsigned char *)malloc(texture.width*texture.height*4*sizeof(unsigned char));
-
+
// NOTE: Despite FBO color texture is RGB, we read data as RGBA... reading as RGB doesn't work... o__O
glReadPixels(0, 0, texture.width, texture.height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
-
+
// Re-attach internal FBO color texture before deleting it
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo.texture.id, 0);
-
+
glBindFramebuffer(GL_FRAMEBUFFER, 0);
-
+
#elif defined(GET_TEXTURE_FBO_OPTION_2)
// Render texture to fbo
glBindFramebuffer(GL_FRAMEBUFFER, fbo.id);
-
+
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepthf(1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, width, height);
//glMatrixMode(GL_PROJECTION);
//glLoadIdentity();
- rlOrtho(0.0, width, height, 0.0, 0.0, 1.0);
+ rlOrtho(0.0, width, height, 0.0, 0.0, 1.0);
//glMatrixMode(GL_MODELVIEW);
//glLoadIdentity();
//glDisable(GL_TEXTURE_2D);
//glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
-
+
Model quad;
//quad.mesh = GenMeshQuad(width, height);
quad.transform = MatrixIdentity();
quad.shader = defaultShader;
-
+
DrawModel(quad, (Vector3){ 0.0f, 0.0f, 0.0f }, 1.0f, WHITE);
-
+
pixels = (unsigned char *)malloc(texture.width*texture.height*3*sizeof(unsigned char));
-
+
glReadPixels(0, 0, texture.width, texture.height, GL_RGB, GL_UNSIGNED_BYTE, pixels);
// Bind framebuffer 0, which means render to back buffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
-
+
UnloadModel(quad);
#endif // GET_TEXTURE_FBO_OPTION
@@ -2388,7 +2387,7 @@ void rlglRecordDraw(void)
draws[drawsCounter].projection = projection;
draws[drawsCounter].modelview = modelview;
draws[drawsCounter].vertexCount = currentState.vertexCount;
-
+
drawsCounter++;
#endif
}
@@ -2403,49 +2402,83 @@ void rlglRecordDraw(void)
Texture2D GetDefaultTexture(void)
{
Texture2D texture;
-
+
texture.id = whiteTexture;
texture.width = 1;
texture.height = 1;
texture.mipmaps = 1;
texture.format = UNCOMPRESSED_R8G8B8A8;
-
+
return texture;
}
-// Load a custom shader and bind default locations
+// Load text data from file
+// NOTE: text chars array should be freed manually
+char *LoadText(const char *fileName)
+{
+ FILE *textFile;
+ char *text = NULL;
+
+ int count = 0;
+
+ if (fileName != NULL)
+ {
+ textFile = fopen(fileName,"rt");
+
+ if (textFile != NULL)
+ {
+ fseek(textFile, 0, SEEK_END);
+ count = ftell(textFile);
+ rewind(textFile);
+
+ if (count > 0)
+ {
+ text = (char *)malloc(sizeof(char)*(count + 1));
+ count = fread(text, sizeof(char), count, textFile);
+ text[count] = '\0';
+ }
+
+ fclose(textFile);
+ }
+ else TraceLog(WARNING, "[%s] Text file could not be opened", fileName);
+ }
+
+ return text;
+}
+
+// Load shader from files and bind default locations
Shader LoadShader(char *vsFileName, char *fsFileName)
{
Shader shader = { 0 };
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
// Shaders loading from external text file
- char *vShaderStr = ReadTextFile(vsFileName);
- char *fShaderStr = ReadTextFile(fsFileName);
-
+ char *vShaderStr = LoadText(vsFileName);
+ char *fShaderStr = LoadText(fsFileName);
+
if ((vShaderStr != NULL) && (fShaderStr != NULL))
{
shader.id = LoadShaderProgram(vShaderStr, fShaderStr);
// After shader loading, we try to load default location names
if (shader.id != 0) LoadDefaultShaderLocations(&shader);
-
+
// Shader strings must be freed
free(vShaderStr);
free(fShaderStr);
}
-
+
if (shader.id == 0)
{
TraceLog(WARNING, "Custom shader could not be loaded");
shader = defaultShader;
- }
+ }
#endif
return shader;
}
-// Unload a custom shader from memory
+// Unload shader from GPU memory (VRAM)
void UnloadShader(Shader shader)
{
if (shader.id != 0)
@@ -2486,32 +2519,13 @@ Shader GetDefaultShader(void)
#endif
}
-// Get default shader
-// NOTE: Inits global variable standardShader
-Shader GetStandardShader(void)
-{
- Shader shader = { 0 };
-
-#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
- if (standardShaderLoaded) shader = standardShader;
- else
- {
- // Lazy initialization of standard shader
- standardShader = LoadStandardShader();
- shader = standardShader;
- }
-#endif
-
- return shader;
-}
-
// Get shader uniform location
int GetShaderLocation(Shader shader, const char *uniformName)
{
int location = -1;
-#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
location = glGetUniformLocation(shader.id, uniformName);
-
+
if (location == -1) TraceLog(DEBUG, "[SHDR ID %i] Shader location for %s could not be found", shader.id, uniformName);
#endif
return location;
@@ -2528,8 +2542,8 @@ void SetShaderValue(Shader shader, int uniformLoc, float *value, int size)
else if (size == 3) glUniform3fv(uniformLoc, 1, value); // Shader uniform type: vec3
else if (size == 4) glUniform4fv(uniformLoc, 1, value); // Shader uniform type: vec4
else TraceLog(WARNING, "Shader value float array size not supported");
-
- glUseProgram(0);
+
+ //glUseProgram(0); // Avoid reseting current shader program, in case other uniforms are set
#endif
}
@@ -2544,8 +2558,8 @@ void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size)
else if (size == 3) glUniform3iv(uniformLoc, 1, value); // Shader uniform type: ivec3
else if (size == 4) glUniform4iv(uniformLoc, 1, value); // Shader uniform type: ivec4
else TraceLog(WARNING, "Shader value int array size not supported");
-
- glUseProgram(0);
+
+ //glUseProgram(0);
#endif
}
@@ -2556,8 +2570,8 @@ void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat)
glUseProgram(shader.id);
glUniformMatrix4fv(uniformLoc, 1, false, MatrixToFloat(mat));
-
- glUseProgram(0);
+
+ //glUseProgram(0);
#endif
}
@@ -2584,7 +2598,7 @@ void BeginBlendMode(int mode)
if ((blendMode != mode) && (mode < 3))
{
rlglDraw();
-
+
switch (mode)
{
case BLEND_ALPHA: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break;
@@ -2592,7 +2606,7 @@ void BeginBlendMode(int mode)
case BLEND_MULTIPLIED: glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA); break;
default: break;
}
-
+
blendMode = mode;
}
}
@@ -2603,73 +2617,6 @@ void EndBlendMode(void)
BeginBlendMode(BLEND_ALPHA);
}
-// Create a new light, initialize it and add to pool
-Light CreateLight(int type, Vector3 position, Color diffuse)
-{
- Light light = NULL;
-
- if (lightsCount < MAX_LIGHTS)
- {
- // Allocate dynamic memory
- light = (Light)malloc(sizeof(LightData));
-
- // Initialize light values with generic values
- light->id = lightsCount;
- light->type = type;
- light->enabled = true;
-
- light->position = position;
- light->target = (Vector3){ 0.0f, 0.0f, 0.0f };
- light->intensity = 1.0f;
- light->diffuse = diffuse;
-
- // Add new light to the array
- lights[lightsCount] = light;
-
- // Increase enabled lights count
- lightsCount++;
- }
- else
- {
- TraceLog(WARNING, "Too many lights, only supported up to %i lights", MAX_LIGHTS);
-
- // NOTE: Returning latest created light to avoid crashes
- light = lights[lightsCount];
- }
-
-#if defined(GRAPHICS_API_OPENGL_11)
- TraceLog(WARNING, "Lighting currently not supported on OpenGL 1.1");
-#endif
-
- return light;
-}
-
-// Destroy a light and take it out of the list
-void DestroyLight(Light light)
-{
- if (light != NULL)
- {
- int lightId = light->id;
-
- // Free dynamic memory allocation
- free(lights[lightId]);
-
- // Remove *obj from the pointers array
- for (int i = lightId; i < lightsCount; i++)
- {
- // Resort all the following pointers of the array
- if ((i + 1) < lightsCount)
- {
- lights[i] = lights[i + 1];
- lights[i]->id = lights[i + 1]->id;
- }
- }
-
- // Decrease enabled physic objects count
- lightsCount--;
- }
-}
-
// Init VR device (or simulator)
// NOTE: If device is not available, it fallbacks to default device (simulator)
// NOTE: It modifies the global variable: VrDeviceInfo hmd
@@ -2725,9 +2672,9 @@ void InitVrDevice(int vrDevice)
{
// Oculus Rift CV1 parameters
// NOTE: CV1 represents a complete HMD redesign compared to previous versions,
- // new Fresnel-hybrid-asymmetric lenses have been added and, consequently,
- // previous parameters (DK2) and distortion shader (DK2) doesn't work any more.
- // I just defined a set of parameters for simulator that approximate to CV1 stereo rendering
+ // new Fresnel-hybrid-asymmetric lenses have been added and, consequently,
+ // previous parameters (DK2) and distortion shader (DK2) doesn't work any more.
+ // I just defined a set of parameters for simulator that approximate to CV1 stereo rendering
// but result is not the same obtained with Oculus PC SDK.
hmd.hResolution = 2160; // HMD horizontal resolution in pixels
hmd.vResolution = 1200; // HMD vertical resolution in pixels
@@ -2746,17 +2693,17 @@ void InitVrDevice(int vrDevice)
hmd.chromaAbCorrection[2] = 1.014f; // HMD chromatic aberration correction parameter 2
hmd.chromaAbCorrection[3] = 0.0f; // HMD chromatic aberration correction parameter 3
}
-
+
// Initialize framebuffer and textures for stereo rendering
// NOTE: screen size should match HMD aspect ratio
vrConfig.stereoFbo = rlglLoadRenderTexture(screenWidth, screenHeight);
-
+
// Load distortion shader (initialized by default with Oculus Rift CV1 parameters)
vrConfig.distortionShader.id = LoadShaderProgram(vDistortionShaderStr, fDistortionShaderStr);
if (vrConfig.distortionShader.id != 0) LoadDefaultShaderLocations(&vrConfig.distortionShader);
SetStereoConfig(hmd);
-
+
vrSimulator = true;
vrEnabled = true;
}
@@ -2801,9 +2748,9 @@ void ToggleVrMode(void)
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
if (vrDeviceReady || vrSimulator) vrEnabled = !vrEnabled;
else vrEnabled = false;
-
+
if (!vrEnabled)
- {
+ {
// Reset viewport and default projection-modelview matrices
rlViewport(0, 0, screenWidth, screenHeight);
projection = MatrixOrtho(0, screenWidth, screenHeight, 0, 0.0f, 1.0f);
@@ -2838,15 +2785,15 @@ void BeginVrDrawing(void)
rlEnableRenderTexture(vrConfig.stereoFbo.id);
}
- // NOTE: If your application is configured to treat the texture as a linear format (e.g. GL_RGBA)
+ // NOTE: If your application is configured to treat the texture as a linear format (e.g. GL_RGBA)
// and performs linear-to-gamma conversion in GLSL or does not care about gamma-correction, then:
// - Require OculusBuffer format to be OVR_FORMAT_R8G8B8A8_UNORM_SRGB
// - Do NOT enable GL_FRAMEBUFFER_SRGB
//glEnable(GL_FRAMEBUFFER_SRGB);
-
+
//glViewport(0, 0, buffer.width, buffer.height); // Useful if rendering to separate framebuffers (every eye)
rlClearScreenBuffers(); // Clear current framebuffer(s)
-
+
vrRendering = true;
#endif
}
@@ -2865,12 +2812,12 @@ void EndVrDrawing(void)
{
// Unbind current framebuffer
rlDisableRenderTexture();
-
+
rlClearScreenBuffers(); // Clear current framebuffer
// Set viewport to default framebuffer size (screen size)
rlViewport(0, 0, screenWidth, screenHeight);
-
+
// Let rlgl reconfigure internal matrices
rlMatrixMode(RL_PROJECTION); // Enable internal projection matrix
rlLoadIdentity(); // Reset internal projection matrix
@@ -2878,7 +2825,7 @@ void EndVrDrawing(void)
rlMatrixMode(RL_MODELVIEW); // Enable internal modelview matrix
rlLoadIdentity(); // Reset internal modelview matrix
- // Draw RenderTexture (stereoFbo) using distortion shader
+ // Draw RenderTexture (stereoFbo) using distortion shader
currentShader = vrConfig.distortionShader;
rlEnableTexture(vrConfig.stereoFbo.texture.id);
@@ -2915,7 +2862,7 @@ void EndVrDrawing(void)
}
rlDisableDepthTest();
-
+
vrRendering = false;
#endif
}
@@ -2946,7 +2893,7 @@ static void LoadCompressedTexture(unsigned char *data, int width, int height, in
for (int level = 0; level < mipmapCount && (width || height); level++)
{
unsigned int size = 0;
-
+
size = ((width + 3)/4)*((height + 3)/4)*blockSize;
glCompressedTexImage2D(GL_TEXTURE_2D, level, compressedFormat, width, height, 0, size, data + offset);
@@ -3002,7 +2949,7 @@ static unsigned int LoadShaderProgram(const char *vShaderStr, const char *fShade
glGetShaderInfoLog(vertexShader, maxLength, &length, log);
TraceLog(INFO, "%s", log);
-
+
#ifdef _MSC_VER
free(log);
#endif
@@ -3041,7 +2988,7 @@ static unsigned int LoadShaderProgram(const char *vShaderStr, const char *fShade
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
-
+
// NOTE: Default attribute shader locations must be binded before linking
glBindAttribLocation(program, 0, DEFAULT_ATTRIB_POSITION_NAME);
glBindAttribLocation(program, 1, DEFAULT_ATTRIB_TEXCOORD_NAME);
@@ -3049,11 +2996,11 @@ static unsigned int LoadShaderProgram(const char *vShaderStr, const char *fShade
glBindAttribLocation(program, 3, DEFAULT_ATTRIB_COLOR_NAME);
glBindAttribLocation(program, 4, DEFAULT_ATTRIB_TANGENT_NAME);
glBindAttribLocation(program, 5, DEFAULT_ATTRIB_TEXCOORD2_NAME);
-
+
// NOTE: If some attrib name is no found on the shader, it locations becomes -1
-
+
glLinkProgram(program);
-
+
// NOTE: All uniform variables are intitialised to 0 when a program links
glGetProgramiv(program, GL_LINK_STATUS, &success);
@@ -3075,7 +3022,7 @@ static unsigned int LoadShaderProgram(const char *vShaderStr, const char *fShade
glGetProgramInfoLog(program, maxLength, &length, log);
TraceLog(INFO, "%s", log);
-
+
#ifdef _MSC_VER
free(log);
#endif
@@ -3167,39 +3114,6 @@ static Shader LoadDefaultShader(void)
return shader;
}
-// Load standard shader
-// NOTE: This shader supports:
-// - Up to 3 different maps: diffuse, normal, specular
-// - Material properties: colAmbient, colDiffuse, colSpecular, glossiness
-// - Up to 8 lights: Point, Directional or Spot
-static Shader LoadStandardShader(void)
-{
- Shader shader;
-
-#if !defined(RLGL_NO_STANDARD_SHADER)
- // Load standard shader (embeded in standard_shader.h)
- shader.id = LoadShaderProgram(vStandardShaderStr, fStandardShaderStr);
-
- if (shader.id != 0)
- {
- LoadDefaultShaderLocations(&shader);
- TraceLog(INFO, "[SHDR ID %i] Standard shader loaded successfully", shader.id);
-
- standardShaderLoaded = true;
- }
- else
- {
- TraceLog(WARNING, "[SHDR ID %i] Standard shader could not be loaded, using default shader", shader.id);
- shader = GetDefaultShader();
- }
-#else
- shader = GetDefaultShader();
- TraceLog(WARNING, "[SHDR ID %i] Standard shader not available, using default shader", shader.id);
-#endif
-
- return shader;
-}
-
// Get location handlers to for shader attributes and uniforms
// NOTE: If any location is not found, loc point becomes -1
static void LoadDefaultShaderLocations(Shader *shader)
@@ -3211,7 +3125,7 @@ static void LoadDefaultShaderLocations(Shader *shader)
// vertex color location = 3
// vertex tangent location = 4
// vertex texcoord2 location = 5
-
+
// Get handles to GLSL input attibute locations
shader->vertexLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_POSITION_NAME);
shader->texcoordLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TEXCOORD_NAME);
@@ -3227,18 +3141,15 @@ static void LoadDefaultShaderLocations(Shader *shader)
shader->colDiffuseLoc = glGetUniformLocation(shader->id, "colDiffuse");
shader->colAmbientLoc = glGetUniformLocation(shader->id, "colAmbient");
shader->colSpecularLoc = glGetUniformLocation(shader->id, "colSpecular");
-
+
shader->mapTexture0Loc = glGetUniformLocation(shader->id, "texture0");
shader->mapTexture1Loc = glGetUniformLocation(shader->id, "texture1");
shader->mapTexture2Loc = glGetUniformLocation(shader->id, "texture2");
-
+
// TODO: Try to find all expected/recognized shader locations (predefined names, must be documented)
-
- // Try to get lights location points (if available)
- GetShaderLightsLocations(*shader);
}
-// Unload default shader
+// Unload default shader
static void UnloadDefaultShader(void)
{
glUseProgram(0);
@@ -3250,26 +3161,12 @@ static void UnloadDefaultShader(void)
glDeleteProgram(defaultShader.id);
}
-// Unload standard shader
-static void UnloadStandardShader(void)
-{
- glUseProgram(0);
-#if !defined(RLGL_NO_STANDARD_SHADER)
- //glDetachShader(defaultShader, vertexShader);
- //glDetachShader(defaultShader, fragmentShader);
- //glDeleteShader(vertexShader); // Already deleted on shader compilation
- //glDeleteShader(fragmentShader); // Already deleted on shader compilation
- glDeleteProgram(standardShader.id);
-#endif
-}
-
-
// Load default internal buffers (lines, triangles, quads)
static void LoadDefaultBuffers(void)
{
// [CPU] Allocate and initialize float array buffers to store vertex data (lines, triangles, quads)
//--------------------------------------------------------------------------------------------
-
+
// Lines - Initialize arrays (vertex position and color data)
lines.vertices = (float *)malloc(sizeof(float)*3*2*MAX_LINES_BATCH); // 3 float by vertex, 2 vertex by line
lines.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*2*MAX_LINES_BATCH); // 4 float by color, 2 colors by line
@@ -3331,11 +3228,11 @@ static void LoadDefaultBuffers(void)
TraceLog(INFO, "[CPU] Default buffers initialized successfully (lines, triangles, quads)");
//--------------------------------------------------------------------------------------------
-
+
// [GPU] Upload vertex data and initialize VAOs/VBOs (lines, triangles, quads)
// NOTE: Default buffers are linked to use currentShader (defaultShader)
//--------------------------------------------------------------------------------------------
-
+
// Upload and link lines vertex buffers
if (vaoSupported)
{
@@ -3344,7 +3241,7 @@ static void LoadDefaultBuffers(void)
glBindVertexArray(lines.vaoId);
}
- // Lines - Vertex buffers binding and attributes enable
+ // Lines - Vertex buffers binding and attributes enable
// Vertex position buffer (shader-location = 0)
glGenBuffers(2, &lines.vboId[0]);
glBindBuffer(GL_ARRAY_BUFFER, lines.vboId[0]);
@@ -3370,7 +3267,7 @@ static void LoadDefaultBuffers(void)
glBindVertexArray(triangles.vaoId);
}
- // Triangles - Vertex buffers binding and attributes enable
+ // Triangles - Vertex buffers binding and attributes enable
// Vertex position buffer (shader-location = 0)
glGenBuffers(1, &triangles.vboId[0]);
glBindBuffer(GL_ARRAY_BUFFER, triangles.vboId[0]);
@@ -3396,7 +3293,7 @@ static void LoadDefaultBuffers(void)
glBindVertexArray(quads.vaoId);
}
- // Quads - Vertex buffers binding and attributes enable
+ // Quads - Vertex buffers binding and attributes enable
// Vertex position buffer (shader-location = 0)
glGenBuffers(1, &quads.vboId[0]);
glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[0]);
@@ -3512,7 +3409,7 @@ static void DrawDefaultBuffers(int eyesCount)
{
Matrix matProjection = projection;
Matrix matModelView = modelview;
-
+
for (int eye = 0; eye < eyesCount; eye++)
{
if (eyesCount == 2) SetStereoView(eye, matProjection, matModelView);
@@ -3521,17 +3418,17 @@ static void DrawDefaultBuffers(int eyesCount)
if ((lines.vCounter > 0) || (triangles.vCounter > 0) || (quads.vCounter > 0))
{
glUseProgram(currentShader.id);
-
+
// Create modelview-projection matrix
Matrix matMVP = MatrixMultiply(modelview, projection);
glUniformMatrix4fv(currentShader.mvpLoc, 1, false, MatrixToFloat(matMVP));
glUniform4f(currentShader.colDiffuseLoc, 1.0f, 1.0f, 1.0f, 1.0f);
glUniform1i(currentShader.mapTexture0Loc, 0);
-
+
// NOTE: Additional map textures not considered for default buffers drawing
}
-
+
// Draw lines buffers
if (lines.vCounter > 0)
{
@@ -3615,7 +3512,7 @@ static void DrawDefaultBuffers(int eyesCount)
glBindBuffer(GL_ARRAY_BUFFER, quads.vboId[2]);
glVertexAttribPointer(currentShader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
glEnableVertexAttribArray(currentShader.colorLoc);
-
+
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]);
}
@@ -3655,7 +3552,7 @@ static void DrawDefaultBuffers(int eyesCount)
glUseProgram(0); // Unbind shader program
}
-
+
// Reset draws counter
drawsCounter = 1;
draws[0].textureId = whiteTexture;
@@ -3669,10 +3566,10 @@ static void DrawDefaultBuffers(int eyesCount)
quads.vCounter = 0;
quads.tcCounter = 0;
quads.cCounter = 0;
-
+
// Reset depth for next draw
currentDepth = -1.0f;
-
+
// Restore projection/modelview matrices
projection = matProjection;
modelview = matModelView;
@@ -3721,138 +3618,6 @@ static void UnloadDefaultBuffers(void)
free(quads.indices);
}
-// Get shader locations for lights (up to MAX_LIGHTS)
-static void GetShaderLightsLocations(Shader shader)
-{
- char locName[32] = "lights[x].\0";
- char locNameUpdated[64];
-
- for (int i = 0; i < MAX_LIGHTS; i++)
- {
- locName[7] = '0' + i;
-
- strcpy(locNameUpdated, locName);
- strcat(locNameUpdated, "enabled\0");
- lightsLocs[i][0] = glGetUniformLocation(shader.id, locNameUpdated);
-
- locNameUpdated[0] = '\0';
- strcpy(locNameUpdated, locName);
- strcat(locNameUpdated, "type\0");
- lightsLocs[i][1] = glGetUniformLocation(shader.id, locNameUpdated);
-
- locNameUpdated[0] = '\0';
- strcpy(locNameUpdated, locName);
- strcat(locNameUpdated, "position\0");
- lightsLocs[i][2] = glGetUniformLocation(shader.id, locNameUpdated);
-
- locNameUpdated[0] = '\0';
- strcpy(locNameUpdated, locName);
- strcat(locNameUpdated, "direction\0");
- lightsLocs[i][3] = glGetUniformLocation(shader.id, locNameUpdated);
-
- locNameUpdated[0] = '\0';
- strcpy(locNameUpdated, locName);
- strcat(locNameUpdated, "radius\0");
- lightsLocs[i][4] = glGetUniformLocation(shader.id, locNameUpdated);
-
- locNameUpdated[0] = '\0';
- strcpy(locNameUpdated, locName);
- strcat(locNameUpdated, "diffuse\0");
- lightsLocs[i][5] = glGetUniformLocation(shader.id, locNameUpdated);
-
- locNameUpdated[0] = '\0';
- strcpy(locNameUpdated, locName);
- strcat(locNameUpdated, "intensity\0");
- lightsLocs[i][6] = glGetUniformLocation(shader.id, locNameUpdated);
-
- locNameUpdated[0] = '\0';
- strcpy(locNameUpdated, locName);
- strcat(locNameUpdated, "coneAngle\0");
- lightsLocs[i][7] = glGetUniformLocation(shader.id, locNameUpdated);
- }
-}
-
-// Set shader uniform values for lights
-// NOTE: It would be far easier with shader UBOs but are not supported on OpenGL ES 2.0
-static void SetShaderLightsValues(Shader shader)
-{
- for (int i = 0; i < MAX_LIGHTS; i++)
- {
- if (i < lightsCount)
- {
- glUniform1i(lightsLocs[i][0], lights[i]->enabled);
-
- glUniform1i(lightsLocs[i][1], lights[i]->type);
- glUniform4f(lightsLocs[i][5], (float)lights[i]->diffuse.r/255, (float)lights[i]->diffuse.g/255, (float)lights[i]->diffuse.b/255, (float)lights[i]->diffuse.a/255);
- glUniform1f(lightsLocs[i][6], lights[i]->intensity);
-
- switch (lights[i]->type)
- {
- case LIGHT_POINT:
- {
- glUniform3f(lightsLocs[i][2], lights[i]->position.x, lights[i]->position.y, lights[i]->position.z);
- glUniform1f(lightsLocs[i][4], lights[i]->radius);
- } break;
- case LIGHT_DIRECTIONAL:
- {
- Vector3 direction = VectorSubtract(lights[i]->target, lights[i]->position);
- VectorNormalize(&direction);
- glUniform3f(lightsLocs[i][3], direction.x, direction.y, direction.z);
- } break;
- case LIGHT_SPOT:
- {
- glUniform3f(lightsLocs[i][2], lights[i]->position.x, lights[i]->position.y, lights[i]->position.z);
-
- Vector3 direction = VectorSubtract(lights[i]->target, lights[i]->position);
- VectorNormalize(&direction);
- glUniform3f(lightsLocs[i][3], direction.x, direction.y, direction.z);
-
- glUniform1f(lightsLocs[i][7], lights[i]->coneAngle);
- } break;
- default: break;
- }
- }
- else
- {
- glUniform1i(lightsLocs[i][0], 0); // Light disabled
- }
- }
-}
-
-// Read text data from file
-// NOTE: text chars array should be freed manually
-static char *ReadTextFile(const char *fileName)
-{
- FILE *textFile;
- char *text = NULL;
-
- int count = 0;
-
- if (fileName != NULL)
- {
- textFile = fopen(fileName,"rt");
-
- if (textFile != NULL)
- {
- fseek(textFile, 0, SEEK_END);
- count = ftell(textFile);
- rewind(textFile);
-
- if (count > 0)
- {
- text = (char *)malloc(sizeof(char)*(count + 1));
- count = fread(text, sizeof(char), count, textFile);
- text[count] = '\0';
- }
-
- fclose(textFile);
- }
- else TraceLog(WARNING, "[%s] Text file could not be opened", fileName);
- }
-
- return text;
-}
-
// Configure stereo rendering (including distortion shader) with HMD device parameters
static void SetStereoConfig(VrDeviceInfo hmd)
{
@@ -3865,34 +3630,34 @@ static void SetStereoConfig(VrDeviceInfo hmd)
float rightLensCenter[2] = { 0.75f - lensShift, 0.5f };
float leftScreenCenter[2] = { 0.25f, 0.5f };
float rightScreenCenter[2] = { 0.75f, 0.5f };
-
+
// Compute distortion scale parameters
// NOTE: To get lens max radius, lensShift must be normalized to [-1..1]
float lensRadius = fabsf(-1.0f - 4.0f*lensShift);
float lensRadiusSq = lensRadius*lensRadius;
- float distortionScale = hmd.distortionK[0] +
- hmd.distortionK[1]*lensRadiusSq +
- hmd.distortionK[2]*lensRadiusSq*lensRadiusSq +
+ float distortionScale = hmd.distortionK[0] +
+ hmd.distortionK[1]*lensRadiusSq +
+ hmd.distortionK[2]*lensRadiusSq*lensRadiusSq +
hmd.distortionK[3]*lensRadiusSq*lensRadiusSq*lensRadiusSq;
-
+
TraceLog(DEBUG, "VR: Distortion Scale: %f", distortionScale);
-
+
float normScreenWidth = 0.5f;
float normScreenHeight = 1.0f;
float scaleIn[2] = { 2.0f/normScreenWidth, 2.0f/normScreenHeight/aspect };
float scale[2] = { normScreenWidth*0.5f/distortionScale, normScreenHeight*0.5f*aspect/distortionScale };
-
+
TraceLog(DEBUG, "VR: Distortion Shader: LeftLensCenter = { %f, %f }", leftLensCenter[0], leftLensCenter[1]);
TraceLog(DEBUG, "VR: Distortion Shader: RightLensCenter = { %f, %f }", rightLensCenter[0], rightLensCenter[1]);
TraceLog(DEBUG, "VR: Distortion Shader: Scale = { %f, %f }", scale[0], scale[1]);
TraceLog(DEBUG, "VR: Distortion Shader: ScaleIn = { %f, %f }", scaleIn[0], scaleIn[1]);
-
+
// Update distortion shader with lens and distortion-scale parameters
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "leftLensCenter"), leftLensCenter, 2);
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "rightLensCenter"), rightLensCenter, 2);
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "leftScreenCenter"), leftScreenCenter, 2);
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "rightScreenCenter"), rightScreenCenter, 2);
-
+
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "scale"), scale, 2);
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "scaleIn"), scaleIn, 2);
SetShaderValue(vrConfig.distortionShader, GetShaderLocation(vrConfig.distortionShader, "hmdWarpParam"), hmd.distortionK, 4);
@@ -3902,24 +3667,24 @@ static void SetStereoConfig(VrDeviceInfo hmd)
// ...but with lens distortion it is increased (see Oculus SDK Documentation)
//float fovy = 2.0f*atan2(hmd.vScreenSize*0.5f*distortionScale, hmd.eyeToScreenDistance)*RAD2DEG; // Really need distortionScale?
float fovy = 2.0f*(float)atan2(hmd.vScreenSize*0.5f, hmd.eyeToScreenDistance)*RAD2DEG;
-
+
// Compute camera projection matrices
float projOffset = 4.0f*lensShift; // Scaled to projection space coordinates [-1..1]
Matrix proj = MatrixPerspective(fovy, aspect, 0.01, 1000.0);
vrConfig.eyesProjection[0] = MatrixMultiply(proj, MatrixTranslate(projOffset, 0.0f, 0.0f));
vrConfig.eyesProjection[1] = MatrixMultiply(proj, MatrixTranslate(-projOffset, 0.0f, 0.0f));
-
+
// NOTE: Projection matrices must be transposed due to raymath convention
MatrixTranspose(&vrConfig.eyesProjection[0]);
MatrixTranspose(&vrConfig.eyesProjection[1]);
-
+
// Compute camera transformation matrices
- // NOTE: Camera movement might seem more natural if we model the head.
- // Our axis of rotation is the base of our head, so we might want to add
+ // NOTE: Camera movement might seem more natural if we model the head.
+ // Our axis of rotation is the base of our head, so we might want to add
// some y (base of head to eye level) and -z (center of head to eye protrusion) to the camera positions.
vrConfig.eyesViewOffset[0] = MatrixTranslate(-hmd.interpupillaryDistance*0.5f, 0.075f, 0.045f);
vrConfig.eyesViewOffset[1] = MatrixTranslate(hmd.interpupillaryDistance*0.5f, 0.075f, 0.045f);
-
+
// Compute eyes Viewports
//vrConfig.eyesViewport[0] = (Rectangle){ 0, 0, hmd.hResolution/2, hmd.vResolution };
//vrConfig.eyesViewport[1] = (Rectangle){ hmd.hResolution/2, 0, hmd.hResolution/2, hmd.vResolution };
@@ -3936,17 +3701,17 @@ static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView)
#if defined(RLGL_OCULUS_SUPPORT)
if (vrDeviceReady)
{
- rlViewport(layer.eyeLayer.Viewport[eye].Pos.x, layer.eyeLayer.Viewport[eye].Pos.y,
+ rlViewport(layer.eyeLayer.Viewport[eye].Pos.x, layer.eyeLayer.Viewport[eye].Pos.y,
layer.eyeLayer.Viewport[eye].Size.w, layer.eyeLayer.Viewport[eye].Size.h);
- Quaternion eyeRenderPose = (Quaternion){ layer.eyeLayer.RenderPose[eye].Orientation.x,
- layer.eyeLayer.RenderPose[eye].Orientation.y,
- layer.eyeLayer.RenderPose[eye].Orientation.z,
+ Quaternion eyeRenderPose = (Quaternion){ layer.eyeLayer.RenderPose[eye].Orientation.x,
+ layer.eyeLayer.RenderPose[eye].Orientation.y,
+ layer.eyeLayer.RenderPose[eye].Orientation.z,
layer.eyeLayer.RenderPose[eye].Orientation.w };
QuaternionInvert(&eyeRenderPose);
Matrix eyeOrientation = QuaternionToMatrix(eyeRenderPose);
- Matrix eyeTranslation = MatrixTranslate(-layer.eyeLayer.RenderPose[eye].Position.x,
- -layer.eyeLayer.RenderPose[eye].Position.y,
+ Matrix eyeTranslation = MatrixTranslate(-layer.eyeLayer.RenderPose[eye].Position.x,
+ -layer.eyeLayer.RenderPose[eye].Position.y,
-layer.eyeLayer.RenderPose[eye].Position.z);
Matrix eyeView = MatrixMultiply(eyeTranslation, eyeOrientation); // Matrix containing eye-head movement
@@ -3962,7 +3727,7 @@ static void SetStereoView(int eye, Matrix matProjection, Matrix matModelView)
// Apply view offset to modelview matrix
eyeModelView = MatrixMultiply(matModelView, vrConfig.eyesViewOffset[eye]);
-
+
eyeProjection = vrConfig.eyesProjection[eye];
}
@@ -4106,7 +3871,7 @@ OCULUSAPI bool InitOculusDevice(void)
bool oculusReady = false;
ovrResult result = ovr_Initialize(NULL);
-
+
if (OVR_FAILURE(result)) TraceLog(WARNING, "OVR: Could not initialize Oculus device");
else
{
@@ -4126,24 +3891,24 @@ OCULUSAPI bool InitOculusDevice(void)
TraceLog(INFO, "OVR: Product Type: %i", hmdDesc.Type);
//TraceLog(INFO, "OVR: Serial Number: %s", hmdDesc.SerialNumber);
TraceLog(INFO, "OVR: Resolution: %ix%i", hmdDesc.Resolution.w, hmdDesc.Resolution.h);
-
+
// NOTE: Oculus mirror is set to defined screenWidth and screenHeight...
// ...ideally, it should be (hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2)
-
+
// Initialize Oculus Buffers
- layer = InitOculusLayer(session);
+ layer = InitOculusLayer(session);
buffer = LoadOculusBuffer(session, layer.width, layer.height);
mirror = LoadOculusMirror(session, hmdDesc.Resolution.w/2, hmdDesc.Resolution.h/2); // NOTE: hardcoded...
layer.eyeLayer.ColorTexture[0] = buffer.textureChain; //SetOculusLayerTexture(eyeLayer, buffer.textureChain);
-
+
// Recenter OVR tracking origin
ovr_RecenterTrackingOrigin(session);
-
+
oculusReady = true;
vrEnabled = true;
}
}
-
+
return oculusReady;
}
@@ -4164,18 +3929,18 @@ OCULUSAPI void UpdateOculusTracking(Camera *camera)
ovrPosef eyePoses[2];
ovr_GetEyePoses(session, frameIndex, ovrTrue, layer.viewScaleDesc.HmdToEyeOffset, eyePoses, &layer.eyeLayer.SensorSampleTime);
-
+
layer.eyeLayer.RenderPose[0] = eyePoses[0];
layer.eyeLayer.RenderPose[1] = eyePoses[1];
-
+
// TODO: Update external camera with eyePoses data (position, orientation)
// NOTE: We can simplify to simple camera if we consider IPD and HMD device configuration again later
// it will be useful for the user to draw, lets say, billboards oriented to camera
-
+
// Get session status information
ovrSessionStatus sessionStatus;
ovr_GetSessionStatus(session, &sessionStatus);
-
+
if (sessionStatus.ShouldQuit) TraceLog(WARNING, "OVR: Session should quit...");
if (sessionStatus.ShouldRecenter) ovr_RecenterTrackingOrigin(session);
//if (sessionStatus.HmdPresent) // HMD is present.
@@ -4189,7 +3954,7 @@ OCULUSAPI void BeginOculusDrawing(void)
{
GLuint currentTexId;
int currentIndex;
-
+
ovr_GetTextureSwapChainCurrentIndex(session, buffer.textureChain, &currentIndex);
ovr_GetTextureSwapChainBufferGL(session, buffer.textureChain, currentIndex, &currentTexId);
@@ -4204,9 +3969,9 @@ OCULUSAPI void EndOculusDrawing(void)
// Unbind current framebuffer (Oculus buffer)
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-
+
ovr_CommitTextureSwapChain(session, buffer.textureChain);
-
+
ovrLayerHeader *layers = &layer.eyeLayer.Header;
ovr_SubmitFrame(session, frameIndex, &layer.viewScaleDesc, &layers, 1);
@@ -4220,7 +3985,7 @@ static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height)
OculusBuffer buffer;
buffer.width = width;
buffer.height = height;
-
+
// Create OVR texture chain
ovrTextureSwapChainDesc desc = {};
desc.Type = ovrTexture_2D;
@@ -4233,12 +3998,12 @@ static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height)
desc.StaticImage = ovrFalse;
ovrResult result = ovr_CreateTextureSwapChainGL(session, &desc, &buffer.textureChain);
-
+
if (!OVR_SUCCESS(result)) TraceLog(WARNING, "OVR: Failed to create swap textures buffer");
int textureCount = 0;
ovr_GetTextureSwapChainLength(session, buffer.textureChain, &textureCount);
-
+
if (!OVR_SUCCESS(result) || !textureCount) TraceLog(WARNING, "OVR: Unable to count swap chain textures");
for (int i = 0; i < textureCount; ++i)
@@ -4251,9 +4016,9 @@ static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
-
+
glBindTexture(GL_TEXTURE_2D, 0);
-
+
/*
// Setup framebuffer object (using depth texture)
glGenFramebuffers(1, &buffer.fboId);
@@ -4265,7 +4030,7 @@ static OculusBuffer LoadOculusBuffer(ovrSession session, int width, int height)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, buffer.width, buffer.height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
*/
-
+
// Setup framebuffer object (using depth renderbuffer)
glGenFramebuffers(1, &buffer.fboId);
glGenRenderbuffers(1, &buffer.depthId);
@@ -4298,13 +4063,13 @@ static OculusMirror LoadOculusMirror(ovrSession session, int width, int height)
OculusMirror mirror;
mirror.width = width;
mirror.height = height;
-
+
ovrMirrorTextureDesc mirrorDesc;
memset(&mirrorDesc, 0, sizeof(mirrorDesc));
mirrorDesc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
mirrorDesc.Width = mirror.width;
mirrorDesc.Height = mirror.height;
-
+
if (!OVR_SUCCESS(ovr_CreateMirrorTextureGL(session, &mirrorDesc, &mirror.texture))) TraceLog(WARNING, "Could not create mirror texture");
glGenFramebuffers(1, &mirror.fboId);
@@ -4323,9 +4088,9 @@ static void UnloadOculusMirror(ovrSession session, OculusMirror mirror)
static void BlitOculusMirror(ovrSession session, OculusMirror mirror)
{
GLuint mirrorTextureId;
-
+
ovr_GetMirrorTextureBufferGL(session, mirror.texture, &mirrorTextureId);
-
+
glBindFramebuffer(GL_READ_FRAMEBUFFER, mirror.fboId);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mirrorTextureId, 0);
#if defined(GRAPHICS_API_OPENGL_33)
@@ -4339,7 +4104,7 @@ static void BlitOculusMirror(ovrSession session, OculusMirror mirror)
static OculusLayer InitOculusLayer(ovrSession session)
{
OculusLayer layer = { 0 };
-
+
layer.viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f;
memset(&layer.eyeLayer, 0, sizeof(ovrLayerEyeFov));
@@ -4347,7 +4112,7 @@ static OculusLayer InitOculusLayer(ovrSession session)
layer.eyeLayer.Header.Flags = ovrLayerFlag_TextureOriginAtBottomLeft;
ovrEyeRenderDesc eyeRenderDescs[2];
-
+
for (int eye = 0; eye < 2; eye++)
{
eyeRenderDescs[eye] = ovr_GetRenderDesc(session, eye, hmdDesc.DefaultEyeFov[eye]);
@@ -4356,7 +4121,7 @@ static OculusLayer InitOculusLayer(ovrSession session)
layer.viewScaleDesc.HmdToEyeOffset[eye] = eyeRenderDescs[eye].HmdToEyeOffset;
layer.eyeLayer.Fov[eye] = eyeRenderDescs[eye].Fov;
-
+
ovrSizei eyeSize = ovr_GetFovTextureSize(session, eye, layer.eyeLayer.Fov[eye], 1.0f);
layer.eyeLayer.Viewport[eye].Size = eyeSize;
layer.eyeLayer.Viewport[eye].Pos.x = layer.width;
@@ -4365,7 +4130,7 @@ static OculusLayer InitOculusLayer(ovrSession session)
layer.height = eyeSize.h; //std::max(renderTargetSize.y, (uint32_t)eyeSize.h);
layer.width += eyeSize.w;
}
-
+
return layer;
}
@@ -4373,7 +4138,7 @@ static OculusLayer InitOculusLayer(ovrSession session)
static Matrix FromOvrMatrix(ovrMatrix4f ovrmat)
{
Matrix rmat;
-
+
rmat.m0 = ovrmat.M[0][0];
rmat.m1 = ovrmat.M[1][0];
rmat.m2 = ovrmat.M[2][0];
@@ -4390,9 +4155,9 @@ static Matrix FromOvrMatrix(ovrMatrix4f ovrmat)
rmat.m13 = ovrmat.M[1][3];
rmat.m14 = ovrmat.M[2][3];
rmat.m15 = ovrmat.M[3][3];
-
+
MatrixTranspose(&rmat);
-
+
return rmat;
}
#endif
@@ -4423,7 +4188,7 @@ void TraceLog(int msgType, const char *text, ...)
}
// Converts Matrix to float array
-// NOTE: Returned vector is a transposed version of the Matrix struct,
+// NOTE: Returned vector is a transposed version of the Matrix struct,
// it should be this way because, despite raymath use OpenGL column-major convention,
// Matrix struct memory alignment and variables naming are not coherent
float *MatrixToFloat(Matrix mat)
diff --git a/src/rlgl.h b/src/rlgl.h
index 7d328a52..41f671e6 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -97,7 +97,7 @@
// 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 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...
@@ -251,25 +251,6 @@ typedef unsigned char byte;
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
@@ -370,8 +351,8 @@ 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, void *data); // Update GPU texture with new data
-void rlglGenerateMipmaps(Texture2D texture); // Generate mipmap data for selected texture
+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)
@@ -415,9 +396,6 @@ void EndShaderMode(void); // End custo
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);
diff --git a/src/rlua.h b/src/rlua.h
deleted file mode 100644
index c801a328..00000000
--- a/src/rlua.h
+++ /dev/null
@@ -1,4318 +0,0 @@
-/**********************************************************************************************
-*
-* rlua - raylib Lua bindings
-*
-* NOTE 01:
-* The following types:
-* Color, Vector2, Vector3, Rectangle, Ray, Camera, Camera2D
-* are treated as objects with named fields, same as in C.
-*
-* Lua defines utility functions for creating those objects.
-* Usage:
-* local cl = Color(255,255,255,255)
-* local rec = Rectangle(10, 10, 100, 100)
-* local ray = Ray(Vector3(20, 20, 20), Vector3(50, 50, 50))
-* local x2 = rec.x + rec.width
-*
-* The following types:
-* Image, Texture2D, RenderTexture2D, SpriteFont
-* are immutable, and you can only read their non-pointer arguments (e.g. sprfnt.size).
-*
-* All other object types are opaque, that is, you cannot access or
-* change their fields directly.
-*
-* Remember that ALL raylib types have REFERENCE SEMANTICS in Lua.
-* There is currently no way to create a copy of an opaque object.
-*
-* NOTE 02:
-* Some raylib functions take a pointer to an array, and the size of that array.
-* The equivalent Lua functions take only an array table of the specified type UNLESS
-* it's a pointer to a large char array (e.g. for images), then it takes (and potentially returns)
-* a Lua string (without the size argument, as Lua strings are sized by default).
-*
-* NOTE 03:
-* Some raylib functions take pointers to objects to modify (e.g. ImageToPOT, etc.)
-* In Lua, these functions take values and return a new changed value, instead.
-* So, in C:
-* ImageToPOT(&img, BLACK);
-* In Lua becomes:
-* img = ImageToPOT(img, BLACK)
-*
-* Remember that functions can return multiple values, so:
-* UpdateCameraPlayer(&cam, &playerPos);
-* Vector3 vec = ResolveCollisionCubicmap(img, mapPos, &playerPos, 5.0);
-* becomes:
-* cam, playerPos = UpdateCameraPlayer(cam, playerPos)
-* vec, playerPos = ResolveCollisionCubicmap(img, mapPos, playerPos, 5)
-*
-* This is to preserve value semantics of raylib objects.
-*
-*
-* This Lua binding for raylib was originally created by Ghassan Al-Mashareqa ([email protected])
-* for raylib 1.3 and later on reviewed and updated to raylib 1.6 by Ramon Santamaria.
-*
-* Copyright (c) 2015-2016 Ghassan Al-Mashareqa and 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.
-*
-**********************************************************************************************/
-
-#pragma once
-
-#include "raylib.h"
-
-#define RLUA_STATIC
-#ifdef RLUA_STATIC
- #define RLUADEF static // Functions just visible to module including this file
-#else
- #ifdef __cplusplus
- #define RLUADEF extern "C" // Functions visible from other files (no name mangling of functions in C++)
- #else
- #define RLUADEF extern // Functions visible from other files
- #endif
-#endif
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-// ...
-
-//----------------------------------------------------------------------------------
-// Module Functions Declaration
-//----------------------------------------------------------------------------------
-RLUADEF void InitLuaDevice(void); // Initialize Lua system
-RLUADEF void ExecuteLuaCode(const char *code); // Execute raylib Lua code
-RLUADEF void ExecuteLuaFile(const char *filename); // Execute raylib Lua script
-RLUADEF void CloseLuaDevice(void); // De-initialize Lua system
-
-/***********************************************************************************
-*
-* RLUA IMPLEMENTATION
-*
-************************************************************************************/
-
-#if defined(RLUA_IMPLEMENTATION)
-
-#include "raylib.h"
-#include "utils.h"
-#include "raymath.h"
-
-#include <string.h>
-#include <stdlib.h>
-
-#include <lua.h>
-#include <lauxlib.h>
-#include <lualib.h>
-
-//----------------------------------------------------------------------------------
-// Defines and Macros
-//----------------------------------------------------------------------------------
-#define LuaPush_Image(L, img) LuaPushOpaqueTypeWithMetatable(L, img, Image)
-#define LuaPush_Texture2D(L, tex) LuaPushOpaqueTypeWithMetatable(L, tex, Texture2D)
-#define LuaPush_RenderTexture2D(L, tex) LuaPushOpaqueTypeWithMetatable(L, tex, RenderTexture2D)
-#define LuaPush_SpriteFont(L, sf) LuaPushOpaqueTypeWithMetatable(L, sf, SpriteFont)
-#define LuaPush_Mesh(L, vd) LuaPushOpaqueType(L, vd)
-#define LuaPush_Shader(L, s) LuaPushOpaqueType(L, s)
-#define LuaPush_Light(L, light) LuaPushOpaqueTypeWithMetatable(L, light, Light)
-#define LuaPush_Sound(L, snd) LuaPushOpaqueType(L, snd)
-#define LuaPush_Wave(L, wav) LuaPushOpaqueType(L, wav)
-#define LuaPush_Music(L, mus) LuaPushOpaqueType(L, mus)
-#define LuaPush_AudioStream(L, aud) LuaPushOpaqueType(L, aud)
-
-#define LuaGetArgument_string luaL_checkstring
-#define LuaGetArgument_int (int)luaL_checkinteger
-#define LuaGetArgument_unsigned (unsigned)luaL_checkinteger
-#define LuaGetArgument_char (char)luaL_checkinteger
-#define LuaGetArgument_float (float)luaL_checknumber
-#define LuaGetArgument_double luaL_checknumber
-
-#define LuaGetArgument_Image(L, img) *(Image*)LuaGetArgumentOpaqueTypeWithMetatable(L, img, "Image")
-#define LuaGetArgument_Texture2D(L, tex) *(Texture2D*)LuaGetArgumentOpaqueTypeWithMetatable(L, tex, "Texture2D")
-#define LuaGetArgument_RenderTexture2D(L, rtex) *(RenderTexture2D*)LuaGetArgumentOpaqueTypeWithMetatable(L, rtex, "RenderTexture2D")
-#define LuaGetArgument_SpriteFont(L, sf) *(SpriteFont*)LuaGetArgumentOpaqueTypeWithMetatable(L, sf, "SpriteFont")
-#define LuaGetArgument_Mesh(L, vd) *(Mesh*)LuaGetArgumentOpaqueType(L, vd)
-#define LuaGetArgument_Shader(L, s) *(Shader*)LuaGetArgumentOpaqueType(L, s)
-#define LuaGetArgument_Light(L, light) *(Light*)LuaGetArgumentOpaqueType(L, light)
-#define LuaGetArgument_Sound(L, snd) *(Sound*)LuaGetArgumentOpaqueType(L, snd)
-#define LuaGetArgument_Wave(L, wav) *(Wave*)LuaGetArgumentOpaqueType(L, wav)
-#define LuaGetArgument_Music(L, mus) *(Music*)LuaGetArgumentOpaqueType(L, mus)
-#define LuaGetArgument_AudioStream(L, aud) *(AudioStream*)LuaGetArgumentOpaqueType(L, aud)
-
-#define LuaPushOpaqueType(L, str) LuaPushOpaque(L, &str, sizeof(str))
-#define LuaPushOpaqueTypeWithMetatable(L, str, meta) LuaPushOpaqueWithMetatable(L, &str, sizeof(str), #meta)
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-static lua_State* mainLuaState = 0;
-static lua_State* L = 0;
-
-//----------------------------------------------------------------------------------
-// Module specific Functions Declaration
-//----------------------------------------------------------------------------------
-static void LuaPush_Color(lua_State* L, Color color);
-static void LuaPush_Vector2(lua_State* L, Vector2 vec);
-static void LuaPush_Vector3(lua_State* L, Vector3 vec);
-static void LuaPush_Quaternion(lua_State* L, Quaternion vec);
-static void LuaPush_Matrix(lua_State* L, Matrix *matrix);
-static void LuaPush_Rectangle(lua_State* L, Rectangle rect);
-static void LuaPush_Model(lua_State* L, Model mdl);
-static void LuaPush_Ray(lua_State* L, Ray ray);
-static void LuaPush_Camera(lua_State* L, Camera cam);
-
-static Vector2 LuaGetArgument_Vector2(lua_State* L, int index);
-static Vector3 LuaGetArgument_Vector3(lua_State* L, int index);
-static Quaternion LuaGetArgument_Quaternion(lua_State* L, int index);
-static Color LuaGetArgument_Color(lua_State* L, int index);
-static Rectangle LuaGetArgument_Rectangle(lua_State* L, int index);
-static Camera LuaGetArgument_Camera(lua_State* L, int index);
-static Camera2D LuaGetArgument_Camera2D(lua_State* L, int index);
-static Ray LuaGetArgument_Ray(lua_State* L, int index);
-static Matrix LuaGetArgument_Matrix(lua_State* L, int index);
-static Model LuaGetArgument_Model(lua_State* L, int index);
-
-//----------------------------------------------------------------------------------
-// rlua Helper Functions
-//----------------------------------------------------------------------------------
-static void LuaStartEnum(void)
-{
- lua_newtable(L);
-}
-
-static void LuaSetEnum(const char *name, int value)
-{
- lua_pushinteger(L, value);
- lua_setfield(L, -2, name);
-}
-
-static void LuaSetEnumColor(const char *name, Color color)
-{
- LuaPush_Color(L, color);
- lua_setfield(L, -2, name);
-}
-
-static void LuaEndEnum(const char *name)
-{
- lua_setglobal(L, name);
-}
-
-static void LuaPushOpaque(lua_State* L, void *ptr, size_t size)
-{
- void *ud = lua_newuserdata(L, size);
- memcpy(ud, ptr, size);
-}
-
-static void LuaPushOpaqueWithMetatable(lua_State* L, void *ptr, size_t size, const char *metatable_name)
-{
- void *ud = lua_newuserdata(L, size);
- memcpy(ud, ptr, size);
- luaL_setmetatable(L, metatable_name);
-}
-
-static void* LuaGetArgumentOpaqueType(lua_State* L, int index)
-{
- return lua_touserdata(L, index);
-}
-
-static void* LuaGetArgumentOpaqueTypeWithMetatable(lua_State* L, int index, const char *metatable_name)
-{
- return luaL_checkudata(L, index, metatable_name);
-}
-
-//----------------------------------------------------------------------------------
-// LuaIndex* functions
-//----------------------------------------------------------------------------------
-static int LuaIndexImage(lua_State* L)
-{
- Image img = LuaGetArgument_Image(L, 1);
- const char *key = luaL_checkstring(L, 2);
- if (!strcmp(key, "width"))
- lua_pushinteger(L, img.width);
- else if (!strcmp(key, "height"))
- lua_pushinteger(L, img.height);
- else if (!strcmp(key, "mipmaps"))
- lua_pushinteger(L, img.mipmaps);
- else if (!strcmp(key, "format"))
- lua_pushinteger(L, img.format);
- else
- return 0;
- return 1;
-}
-
-static int LuaIndexTexture2D(lua_State* L)
-{
- Texture2D img = LuaGetArgument_Texture2D(L, 1);
- const char *key = luaL_checkstring(L, 2);
- if (!strcmp(key, "width"))
- lua_pushinteger(L, img.width);
- else if (!strcmp(key, "height"))
- lua_pushinteger(L, img.height);
- else if (!strcmp(key, "mipmaps"))
- lua_pushinteger(L, img.mipmaps);
- else if (!strcmp(key, "format"))
- lua_pushinteger(L, img.format);
- else if (!strcmp(key, "id"))
- lua_pushinteger(L, img.id);
- else
- return 0;
- return 1;
-}
-
-static int LuaIndexRenderTexture2D(lua_State* L)
-{
- RenderTexture2D img = LuaGetArgument_RenderTexture2D(L, 1);
- const char *key = luaL_checkstring(L, 2);
- if (!strcmp(key, "texture"))
- LuaPush_Texture2D(L, img.texture);
- else if (!strcmp(key, "depth"))
- LuaPush_Texture2D(L, img.depth);
- else
- return 0;
- return 1;
-}
-
-static int LuaIndexSpriteFont(lua_State* L)
-{
- SpriteFont img = LuaGetArgument_SpriteFont(L, 1);
- const char *key = luaL_checkstring(L, 2);
- if (!strcmp(key, "size"))
- lua_pushinteger(L, img.size);
- else if (!strcmp(key, "texture"))
- LuaPush_Texture2D(L, img.texture);
- else if (!strcmp(key, "numChars"))
- lua_pushinteger(L, img.numChars);
- else
- return 0;
- return 1;
-}
-
-static int LuaIndexLight(lua_State* L)
-{
- Light light = LuaGetArgument_Light(L, 1);
- const char *key = luaL_checkstring(L, 2);
- if (!strcmp(key, "id"))
- lua_pushinteger(L, light->id);
- else if (!strcmp(key, "enabled"))
- lua_pushboolean(L, light->enabled);
- else if (!strcmp(key, "type"))
- lua_pushinteger(L, light->type);
- else if (!strcmp(key, "position"))
- LuaPush_Vector3(L, light->position);
- else if (!strcmp(key, "target"))
- LuaPush_Vector3(L, light->target);
- else if (!strcmp(key, "radius"))
- lua_pushnumber(L, light->radius);
- else if (!strcmp(key, "diffuse"))
- LuaPush_Color(L, light->diffuse);
- else if (!strcmp(key, "intensity"))
- lua_pushnumber(L, light->intensity);
- else if (!strcmp(key, "coneAngle"))
- lua_pushnumber(L, light->coneAngle);
- else
- return 0;
- return 1;
-}
-
-static int LuaNewIndexLight(lua_State* L)
-{
- Light light = LuaGetArgument_Light(L, 1);
- const char *key = luaL_checkstring(L, 2);
- if (!strcmp(key, "id"))
- light->id = LuaGetArgument_int(L, 3);
- else if (!strcmp(key, "enabled"))
- light->enabled = lua_toboolean(L, 3);
- else if (!strcmp(key, "type"))
- light->type = LuaGetArgument_int(L, 3);
- else if (!strcmp(key, "position"))
- light->position = LuaGetArgument_Vector3(L, 3);
- else if (!strcmp(key, "target"))
- light->target = LuaGetArgument_Vector3(L, 3);
- else if (!strcmp(key, "radius"))
- light->radius = LuaGetArgument_float(L, 3);
- else if (!strcmp(key, "diffuse"))
- light->diffuse = LuaGetArgument_Color(L, 3);
- else if (!strcmp(key, "intensity"))
- light->intensity = LuaGetArgument_float(L, 3);
- else if (!strcmp(key, "coneAngle"))
- light->coneAngle = LuaGetArgument_float(L, 3);
- return 0;
-}
-
-static void LuaBuildOpaqueMetatables(void)
-{
- luaL_newmetatable(L, "Image");
- lua_pushcfunction(L, &LuaIndexImage);
- lua_setfield(L, -2, "__index");
- lua_pop(L, 1);
-
- luaL_newmetatable(L, "Texture2D");
- lua_pushcfunction(L, &LuaIndexTexture2D);
- lua_setfield(L, -2, "__index");
- lua_pop(L, 1);
-
- luaL_newmetatable(L, "RenderTexture2D");
- lua_pushcfunction(L, &LuaIndexRenderTexture2D);
- lua_setfield(L, -2, "__index");
- lua_pop(L, 1);
-
- luaL_newmetatable(L, "SpriteFont");
- lua_pushcfunction(L, &LuaIndexSpriteFont);
- lua_setfield(L, -2, "__index");
- lua_pop(L, 1);
-
- luaL_newmetatable(L, "Light");
- lua_pushcfunction(L, &LuaIndexLight);
- lua_setfield(L, -2, "__index");
- lua_pushcfunction(L, &LuaNewIndexLight);
- lua_setfield(L, -2, "__newindex");
- lua_pop(L, 1);
-}
-
-//----------------------------------------------------------------------------------
-// LuaGetArgument functions
-//----------------------------------------------------------------------------------
-
-static Vector2 LuaGetArgument_Vector2(lua_State* L, int index)
-{
- index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values
- luaL_argcheck(L, lua_getfield(L, index, "x") == LUA_TNUMBER, index, "Expected Vector2");
- float x = (float)lua_tonumber(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "y") == LUA_TNUMBER, index, "Expected Vector2");
- float y = (float)lua_tonumber(L, -1);
- lua_pop(L, 2);
- return (Vector2) { x, y };
-}
-
-static Vector3 LuaGetArgument_Vector3(lua_State* L, int index)
-{
- index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values
- luaL_argcheck(L, lua_getfield(L, index, "x") == LUA_TNUMBER, index, "Expected Vector3");
- float x = (float)lua_tonumber(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "y") == LUA_TNUMBER, index, "Expected Vector3");
- float y = (float)lua_tonumber(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "z") == LUA_TNUMBER, index, "Expected Vector3");
- float z = (float)lua_tonumber(L, -1);
- lua_pop(L, 3);
- return (Vector3) { x, y, z };
-}
-
-static Quaternion LuaGetArgument_Quaternion(lua_State* L, int index)
-{
- index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values
- luaL_argcheck(L, lua_getfield(L, index, "x") == LUA_TNUMBER, index, "Expected Quaternion");
- float x = (float)lua_tonumber(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "y") == LUA_TNUMBER, index, "Expected Quaternion");
- float y = (float)lua_tonumber(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "z") == LUA_TNUMBER, index, "Expected Quaternion");
- float z = (float)lua_tonumber(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "w") == LUA_TNUMBER, index, "Expected Quaternion");
- float w = (float)lua_tonumber(L, -1);
- lua_pop(L, 4);
- return (Quaternion) { x, y, z, w };
-}
-
-static Color LuaGetArgument_Color(lua_State* L, int index)
-{
- index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values
- luaL_argcheck(L, lua_getfield(L, index, "r") == LUA_TNUMBER, index, "Expected Color");
- unsigned char r = (unsigned char)lua_tointeger(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "g") == LUA_TNUMBER, index, "Expected Color");
- unsigned char g = (unsigned char)lua_tointeger(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "b") == LUA_TNUMBER, index, "Expected Color");
- unsigned char b = (unsigned char)lua_tointeger(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "a") == LUA_TNUMBER, index, "Expected Color");
- unsigned char a = (unsigned char)lua_tointeger(L, -1);
- lua_pop(L, 4);
- return (Color) { r, g, b, a };
-}
-
-static Rectangle LuaGetArgument_Rectangle(lua_State* L, int index)
-{
- index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values
- luaL_argcheck(L, lua_getfield(L, index, "x") == LUA_TNUMBER, index, "Expected Rectangle");
- int x = (int)lua_tointeger(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "y") == LUA_TNUMBER, index, "Expected Rectangle");
- int y = (int)lua_tointeger(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "width") == LUA_TNUMBER, index, "Expected Rectangle");
- int w = (int)lua_tointeger(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "height") == LUA_TNUMBER, index, "Expected Rectangle");
- int h = (int)lua_tointeger(L, -1);
- lua_pop(L, 4);
- return (Rectangle) { x, y, w, h };
-}
-
-static Camera LuaGetArgument_Camera(lua_State* L, int index)
-{
- Camera result;
- index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values
- luaL_argcheck(L, lua_getfield(L, index, "position") == LUA_TTABLE, index, "Expected Camera");
- result.position = LuaGetArgument_Vector3(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "target") == LUA_TTABLE, index, "Expected Camera");
- result.target = LuaGetArgument_Vector3(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "up") == LUA_TTABLE, index, "Expected Camera");
- result.up = LuaGetArgument_Vector3(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "fovy") == LUA_TNUMBER, index, "Expected Camera");
- result.fovy = LuaGetArgument_float(L, -1);
- lua_pop(L, 4);
- return result;
-}
-
-static Camera2D LuaGetArgument_Camera2D(lua_State* L, int index)
-{
- Camera2D result;
- index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values
- luaL_argcheck(L, lua_getfield(L, index, "offset") == LUA_TTABLE, index, "Expected Camera2D");
- result.offset = LuaGetArgument_Vector2(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "target") == LUA_TTABLE, index, "Expected Camera2D");
- result.target = LuaGetArgument_Vector2(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "rotation") == LUA_TNUMBER, index, "Expected Camera2D");
- result.rotation = LuaGetArgument_float(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "zoom") == LUA_TNUMBER, index, "Expected Camera2D");
- result.zoom = LuaGetArgument_float(L, -1);
- lua_pop(L, 4);
- return result;
-}
-
-static BoundingBox LuaGetArgument_BoundingBox(lua_State* L, int index)
-{
- BoundingBox result;
- index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values
- luaL_argcheck(L, lua_getfield(L, index, "min") == LUA_TTABLE, index, "Expected BoundingBox");
- result.min = LuaGetArgument_Vector3(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "max") == LUA_TTABLE, index, "Expected BoundingBox");
- result.max = LuaGetArgument_Vector3(L, -1);
- lua_pop(L, 2);
- return result;
-}
-
-static Ray LuaGetArgument_Ray(lua_State* L, int index)
-{
- Ray result;
- index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values
- luaL_argcheck(L, lua_getfield(L, index, "position") == LUA_TTABLE, index, "Expected Ray");
- result.position = LuaGetArgument_Vector3(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "direction") == LUA_TTABLE, index, "Expected Ray");
- result.direction = LuaGetArgument_Vector3(L, -1);
- lua_pop(L, 2);
- return result;
-}
-
-static Matrix LuaGetArgument_Matrix(lua_State* L, int index)
-{
- Matrix result = { 0 };
- float* ptr = &result.m0;
- index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values
-
- for (int i = 0; i < 16; i++)
- {
- lua_geti(L, index, i+1);
- ptr[i] = luaL_checknumber(L, -1);
- }
- lua_pop(L, 16);
- return result;
-}
-
-static Material LuaGetArgument_Material(lua_State* L, int index)
-{
- Material result;
- index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values
- luaL_argcheck(L, lua_getfield(L, index, "shader") == LUA_TUSERDATA, index, "Expected Material");
- result.shader = LuaGetArgument_Shader(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "texDiffuse") == LUA_TUSERDATA, index, "Expected Material");
- result.texDiffuse = LuaGetArgument_Texture2D(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "texNormal") == LUA_TUSERDATA, index, "Expected Material");
- result.texNormal = LuaGetArgument_Texture2D(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "texSpecular") == LUA_TUSERDATA, index, "Expected Material");
- result.texSpecular = LuaGetArgument_Texture2D(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "colDiffuse") == LUA_TTABLE, index, "Expected Material");
- result.colDiffuse = LuaGetArgument_Color(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "colAmbient") == LUA_TTABLE, index, "Expected Material");
- result.colAmbient = LuaGetArgument_Color(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "colSpecular") == LUA_TTABLE, index, "Expected Material");
- result.colSpecular = LuaGetArgument_Color(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "glossiness") == LUA_TNUMBER, index, "Expected Material");
- result.glossiness = LuaGetArgument_float(L, -1);
- lua_pop(L, 8);
- return result;
-}
-
-static Model LuaGetArgument_Model(lua_State* L, int index)
-{
- Model result;
- index = lua_absindex(L, index); // Makes sure we use absolute indices because we push multiple values
- luaL_argcheck(L, lua_getfield(L, index, "mesh") == LUA_TUSERDATA, index, "Expected Model");
- result.mesh = LuaGetArgument_Mesh(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "transform") == LUA_TTABLE, index, "Expected Model");
- result.transform = LuaGetArgument_Matrix(L, -1);
- luaL_argcheck(L, lua_getfield(L, index, "material") == LUA_TTABLE, index, "Expected Model");
- result.material = LuaGetArgument_Material(L, -1);
- lua_pop(L, 3);
- return result;
-}
-
-//----------------------------------------------------------------------------------
-// LuaPush functions
-//----------------------------------------------------------------------------------
-static void LuaPush_Color(lua_State* L, Color color)
-{
- lua_createtable(L, 0, 4);
- lua_pushinteger(L, color.r);
- lua_setfield(L, -2, "r");
- lua_pushinteger(L, color.g);
- lua_setfield(L, -2, "g");
- lua_pushinteger(L, color.b);
- lua_setfield(L, -2, "b");
- lua_pushinteger(L, color.a);
- lua_setfield(L, -2, "a");
-}
-
-static void LuaPush_Vector2(lua_State* L, Vector2 vec)
-{
- lua_createtable(L, 0, 2);
- lua_pushnumber(L, vec.x);
- lua_setfield(L, -2, "x");
- lua_pushnumber(L, vec.y);
- lua_setfield(L, -2, "y");
-}
-
-static void LuaPush_Vector3(lua_State* L, Vector3 vec)
-{
- lua_createtable(L, 0, 3);
- lua_pushnumber(L, vec.x);
- lua_setfield(L, -2, "x");
- lua_pushnumber(L, vec.y);
- lua_setfield(L, -2, "y");
- lua_pushnumber(L, vec.z);
- lua_setfield(L, -2, "z");
-}
-
-static void LuaPush_Quaternion(lua_State* L, Quaternion vec)
-{
- lua_createtable(L, 0, 4);
- lua_pushnumber(L, vec.x);
- lua_setfield(L, -2, "x");
- lua_pushnumber(L, vec.y);
- lua_setfield(L, -2, "y");
- lua_pushnumber(L, vec.z);
- lua_setfield(L, -2, "z");
- lua_pushnumber(L, vec.w);
- lua_setfield(L, -2, "w");
-}
-
-static void LuaPush_Matrix(lua_State* L, Matrix *matrix)
-{
- int i;
- lua_createtable(L, 16, 0);
- float* num = (&matrix->m0);
- for (i = 0; i < 16; i++)
- {
- lua_pushnumber(L, num[i]);
- lua_rawseti(L, -2, i + 1);
- }
-}
-
-static void LuaPush_Rectangle(lua_State* L, Rectangle rect)
-{
- lua_createtable(L, 0, 4);
- lua_pushinteger(L, rect.x);
- lua_setfield(L, -2, "x");
- lua_pushinteger(L, rect.y);
- lua_setfield(L, -2, "y");
- lua_pushinteger(L, rect.width);
- lua_setfield(L, -2, "width");
- lua_pushinteger(L, rect.height);
- lua_setfield(L, -2, "height");
-}
-
-static void LuaPush_Ray(lua_State* L, Ray ray)
-{
- lua_createtable(L, 0, 2);
- LuaPush_Vector3(L, ray.position);
- lua_setfield(L, -2, "position");
- LuaPush_Vector3(L, ray.direction);
- lua_setfield(L, -2, "direction");
-}
-
-static void LuaPush_BoundingBox(lua_State* L, BoundingBox bb)
-{
- lua_createtable(L, 0, 2);
- LuaPush_Vector3(L, bb.min);
- lua_setfield(L, -2, "min");
- LuaPush_Vector3(L, bb.max);
- lua_setfield(L, -2, "max");
-}
-
-static void LuaPush_Camera(lua_State* L, Camera cam)
-{
- lua_createtable(L, 0, 4);
- LuaPush_Vector3(L, cam.position);
- lua_setfield(L, -2, "position");
- LuaPush_Vector3(L, cam.target);
- lua_setfield(L, -2, "target");
- LuaPush_Vector3(L, cam.up);
- lua_setfield(L, -2, "up");
- lua_pushnumber(L, cam.fovy);
- lua_setfield(L, -2, "fovy");
-}
-
-static void LuaPush_Camera2D(lua_State* L, Camera2D cam)
-{
- lua_createtable(L, 0, 4);
- LuaPush_Vector2(L, cam.offset);
- lua_setfield(L, -2, "offset");
- LuaPush_Vector2(L, cam.target);
- lua_setfield(L, -2, "target");
- lua_pushnumber(L, cam.rotation);
- lua_setfield(L, -2, "rotation");
- lua_pushnumber(L, cam.zoom);
- lua_setfield(L, -2, "zoom");
-}
-
-static void LuaPush_Material(lua_State* L, Material mat)
-{
- lua_createtable(L, 0, 8);
- LuaPush_Shader(L, mat.shader);
- lua_setfield(L, -2, "shader");
- LuaPush_Texture2D(L, mat.texDiffuse);
- lua_setfield(L, -2, "texDiffuse");
- LuaPush_Texture2D(L, mat.texNormal);
- lua_setfield(L, -2, "texNormal");
- LuaPush_Texture2D(L, mat.texSpecular);
- lua_setfield(L, -2, "texSpecular");
- LuaPush_Color(L, mat.colDiffuse);
- lua_setfield(L, -2, "colDiffuse");
- LuaPush_Color(L, mat.colAmbient);
- lua_setfield(L, -2, "colAmbient");
- LuaPush_Color(L, mat.colSpecular);
- lua_setfield(L, -2, "colSpecular");
- lua_pushnumber(L, mat.glossiness);
- lua_setfield(L, -2, "glossiness");
-}
-
-static void LuaPush_Model(lua_State* L, Model mdl)
-{
- lua_createtable(L, 0, 4);
- LuaPush_Mesh(L, mdl.mesh);
- lua_setfield(L, -2, "mesh");
- LuaPush_Matrix(L, &mdl.transform);
- lua_setfield(L, -2, "transform");
- LuaPush_Material(L, mdl.material);
- lua_setfield(L, -2, "material");
-}
-
-//----------------------------------------------------------------------------------
-// raylib Lua Structure constructors
-//----------------------------------------------------------------------------------
-static int lua_Color(lua_State* L)
-{
- LuaPush_Color(L, (Color) { (unsigned char)luaL_checkinteger(L, 1), (unsigned char)luaL_checkinteger(L, 2), (unsigned char)luaL_checkinteger(L, 3), (unsigned char)luaL_checkinteger(L, 4) });
- return 1;
-}
-
-static int lua_Vector2(lua_State* L)
-{
- LuaPush_Vector2(L, (Vector2) { (float)luaL_checknumber(L, 1), (float)luaL_checknumber(L, 2) });
- return 1;
-}
-
-static int lua_Vector3(lua_State* L)
-{
- LuaPush_Vector3(L, (Vector3) { (float)luaL_checknumber(L, 1), (float)luaL_checknumber(L, 2), (float)luaL_checknumber(L, 3) });
- return 1;
-}
-
-static int lua_Quaternion(lua_State* L)
-{
- LuaPush_Quaternion(L, (Quaternion) { (float)luaL_checknumber(L, 1), (float)luaL_checknumber(L, 2), (float)luaL_checknumber(L, 3), (float)luaL_checknumber(L, 4) });
- return 1;
-}
-
-static int lua_Rectangle(lua_State* L)
-{
- LuaPush_Rectangle(L, (Rectangle) { (int)luaL_checkinteger(L, 1), (int)luaL_checkinteger(L, 2), (int)luaL_checkinteger(L, 3), (int)luaL_checkinteger(L, 4) });
- return 1;
-}
-
-static int lua_Ray(lua_State* L)
-{
- Vector2 pos = LuaGetArgument_Vector2(L, 1);
- Vector2 dir = LuaGetArgument_Vector2(L, 2);
- LuaPush_Ray(L, (Ray) { { pos.x, pos.y }, { dir.x, dir.y } });
- return 1;
-}
-
-static int lua_BoundingBox(lua_State* L)
-{
- Vector3 min = LuaGetArgument_Vector3(L, 1);
- Vector3 max = LuaGetArgument_Vector3(L, 2);
- LuaPush_BoundingBox(L, (BoundingBox) { { min.x, min.y, min.z }, { max.x, max.y, max.z } });
- return 1;
-}
-
-static int lua_Camera(lua_State* L)
-{
- Vector3 pos = LuaGetArgument_Vector3(L, 1);
- Vector3 tar = LuaGetArgument_Vector3(L, 2);
- Vector3 up = LuaGetArgument_Vector3(L, 3);
- float fovy = LuaGetArgument_float(L, 4);
- LuaPush_Camera(L, (Camera) { { pos.x, pos.y, pos.z }, { tar.x, tar.y, tar.z }, { up.x, up.y, up.z }, fovy });
- return 1;
-}
-
-static int lua_Camera2D(lua_State* L)
-{
- Vector2 off = LuaGetArgument_Vector2(L, 1);
- Vector2 tar = LuaGetArgument_Vector2(L, 2);
- float rot = LuaGetArgument_float(L, 3);
- float zoom = LuaGetArgument_float(L, 4);
- LuaPush_Camera2D(L, (Camera2D) { { off.x, off.y }, { tar.x, tar.y }, rot, zoom });
- return 1;
-}
-
-/*************************************************************************************
-* raylib Lua Functions Bindings
-**************************************************************************************/
-
-//------------------------------------------------------------------------------------
-// raylib [core] module functions - Window and Graphics Device
-//------------------------------------------------------------------------------------
-int lua_InitWindow(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- const char * arg3 = LuaGetArgument_string(L, 3);
- InitWindow(arg1, arg2, arg3);
- return 0;
-}
-
-int lua_CloseWindow(lua_State* L)
-{
- CloseWindow();
- return 0;
-}
-
-int lua_WindowShouldClose(lua_State* L)
-{
- bool result = WindowShouldClose();
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_IsWindowMinimized(lua_State* L)
-{
- bool result = IsWindowMinimized();
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_ToggleFullscreen(lua_State* L)
-{
- ToggleFullscreen();
- return 0;
-}
-
-int lua_GetScreenWidth(lua_State* L)
-{
- int result = GetScreenWidth();
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_GetScreenHeight(lua_State* L)
-{
- int result = GetScreenHeight();
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_ShowCursor(lua_State* L)
-{
- ShowCursor();
- return 0;
-}
-
-int lua_HideCursor(lua_State* L)
-{
- HideCursor();
- return 0;
-}
-
-int lua_IsCursorHidden(lua_State* L)
-{
- bool result = IsCursorHidden();
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_EnableCursor(lua_State* L)
-{
- EnableCursor();
- return 0;
-}
-
-int lua_DisableCursor(lua_State* L)
-{
- DisableCursor();
- return 0;
-}
-
-int lua_ClearBackground(lua_State* L)
-{
- Color arg1 = LuaGetArgument_Color(L, 1);
- ClearBackground(arg1);
- return 0;
-}
-
-int lua_BeginDrawing(lua_State* L)
-{
- BeginDrawing();
- return 0;
-}
-
-int lua_EndDrawing(lua_State* L)
-{
- EndDrawing();
- return 0;
-}
-
-int lua_Begin2dMode(lua_State* L)
-{
- Camera2D arg1 = LuaGetArgument_Camera2D(L, 1);
- Begin2dMode(arg1);
- return 0;
-}
-
-int lua_End2dMode(lua_State* L)
-{
- End2dMode();
- return 0;
-}
-
-int lua_Begin3dMode(lua_State* L)
-{
- Camera arg1 = LuaGetArgument_Camera(L, 1);
- Begin3dMode(arg1);
- return 0;
-}
-
-int lua_End3dMode(lua_State* L)
-{
- End3dMode();
- return 0;
-}
-
-int lua_BeginTextureMode(lua_State* L)
-{
- RenderTexture2D arg1 = LuaGetArgument_RenderTexture2D(L, 1);
- BeginTextureMode(arg1);
- return 0;
-}
-
-int lua_EndTextureMode(lua_State* L)
-{
- EndTextureMode();
- return 0;
-}
-
-int lua_GetMouseRay(lua_State* L)
-{
- Vector2 arg1 = LuaGetArgument_Vector2(L, 1);
- Camera arg2 = LuaGetArgument_Camera(L, 2);
- Ray result = GetMouseRay(arg1, arg2);
- LuaPush_Ray(L, result);
- return 1;
-}
-
-int lua_GetWorldToScreen(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- Camera arg2 = LuaGetArgument_Camera(L, 2);
- Vector2 result = GetWorldToScreen(arg1, arg2);
- LuaPush_Vector2(L, result);
- return 1;
-}
-
-int lua_GetCameraMatrix(lua_State* L)
-{
- Camera arg1 = LuaGetArgument_Camera(L, 1);
- Matrix result = GetCameraMatrix(arg1);
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-#if defined(PLATFORM_WEB)
-
-static int LuaDrawLoopFunc;
-
-static void LuaDrawLoop()
-{
- lua_rawgeti(L, LUA_REGISTRYINDEX, LuaDrawLoopFunc);
- lua_call(L, 0, 0);
-}
-
-int lua_SetDrawingLoop(lua_State* L)
-{
- luaL_argcheck(L, lua_isfunction(L, 1), 1, "Loop function expected");
- lua_pushvalue(L, 1);
- LuaDrawLoopFunc = luaL_ref(L, LUA_REGISTRYINDEX);
- SetDrawingLoop(&LuaDrawLoop);
- return 0;
-}
-
-#else
-
-int lua_SetTargetFPS(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- SetTargetFPS(arg1);
- return 0;
-}
-#endif
-
-int lua_GetFPS(lua_State* L)
-{
- float result = GetFPS();
- lua_pushnumber(L, result);
- return 1;
-}
-
-int lua_GetFrameTime(lua_State* L)
-{
- float result = GetFrameTime();
- lua_pushnumber(L, result);
- return 1;
-}
-
-int lua_GetColor(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- Color result = GetColor(arg1);
- LuaPush_Color(L, result);
- return 1;
-}
-
-int lua_GetHexValue(lua_State* L)
-{
- Color arg1 = LuaGetArgument_Color(L, 1);
- int result = GetHexValue(arg1);
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_ColorToFloat(lua_State* L)
-{
- Color arg1 = LuaGetArgument_Color(L, 1);
- float * result = ColorToFloat(arg1);
- lua_createtable(L, 4, 0);
- for (int i = 0; i < 4; i++)
- {
- lua_pushnumber(L, result[i]);
- lua_rawseti(L, -2, i + 1);
- }
- free(result);
- return 1;
-}
-
-int lua_VectorToFloat(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- float * result = VectorToFloat(arg1);
- lua_createtable(L, 3, 0);
- for (int i = 0; i < 3; i++)
- {
- lua_pushnumber(L, result[i]);
- lua_rawseti(L, -2, i + 1);
- }
- free(result);
- return 1;
-}
-
-int lua_MatrixToFloat(lua_State* L)
-{
- Matrix arg1 = LuaGetArgument_Matrix(L, 1);
- float * result = MatrixToFloat(arg1);
- lua_createtable(L, 16, 0);
- for (int i = 0; i < 16; i++)
- {
- lua_pushnumber(L, result[i]);
- lua_rawseti(L, -2, i + 1);
- }
- free(result);
- return 1;
-}
-
-int lua_GetRandomValue(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int result = GetRandomValue(arg1, arg2);
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_Fade(lua_State* L)
-{
- Color arg1 = LuaGetArgument_Color(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- Color result = Fade(arg1, arg2);
- LuaPush_Color(L, result);
- return 1;
-}
-
-int lua_SetConfigFlags(lua_State* L)
-{
- char arg1 = LuaGetArgument_char(L, 1);
- SetConfigFlags(arg1);
- return 0;
-}
-
-int lua_ShowLogo(lua_State* L)
-{
- ShowLogo();
- return 0;
-}
-
-int lua_IsFileDropped(lua_State* L)
-{
- bool result = IsFileDropped();
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_GetDroppedFiles(lua_State* L)
-{
- int count = 0;
- char ** result = GetDroppedFiles(&count);
- lua_createtable(L, count, 0);
- for (int i = 0; i < count; i++)
- {
- lua_pushstring(L, result[i]);
- lua_rawseti(L, -2, i + 1);
- }
- return 1;
-}
-
-int lua_ClearDroppedFiles(lua_State* L)
-{
- ClearDroppedFiles();
- return 0;
-}
-
-int lua_StorageSaveValue(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- StorageSaveValue(arg1, arg2);
- return 0;
-}
-
-int lua_StorageLoadValue(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int result = StorageLoadValue(arg1);
- lua_pushinteger(L, result);
- return 1;
-}
-
-//------------------------------------------------------------------------------------
-// raylib [core] module functions - Input Handling
-//------------------------------------------------------------------------------------
-int lua_IsKeyPressed(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- bool result = IsKeyPressed(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_IsKeyDown(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- bool result = IsKeyDown(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_IsKeyReleased(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- bool result = IsKeyReleased(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_IsKeyUp(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- bool result = IsKeyUp(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_GetKeyPressed(lua_State* L)
-{
- int result = GetKeyPressed();
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_SetExitKey(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- SetExitKey(arg1);
- return 0;
-}
-
-int lua_IsGamepadAvailable(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- bool result = IsGamepadAvailable(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_IsGamepadName(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- const char * arg2 = LuaGetArgument_string(L, 2);
- bool result = IsGamepadName(arg1, arg2);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_GetGamepadName(lua_State* L)
-{
- // TODO: Return gamepad name id
-
- int arg1 = LuaGetArgument_int(L, 1);
- char * result = GetGamepadName(arg1);
- //lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_IsGamepadButtonPressed(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- bool result = IsGamepadButtonPressed(arg1, arg2);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_IsGamepadButtonDown(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- bool result = IsGamepadButtonDown(arg1, arg2);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_IsGamepadButtonReleased(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- bool result = IsGamepadButtonReleased(arg1, arg2);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_IsGamepadButtonUp(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- bool result = IsGamepadButtonUp(arg1, arg2);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_GetGamepadButtonPressed(lua_State* L)
-{
- int result = GetGamepadButtonPressed();
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_GetGamepadAxisCount(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int result = GetGamepadAxisCount(arg1);
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_GetGamepadAxisMovement(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- float result = GetGamepadAxisMovement(arg1, arg2);
- lua_pushnumber(L, result);
- return 1;
-}
-
-int lua_IsMouseButtonPressed(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- bool result = IsMouseButtonPressed(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_IsMouseButtonDown(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- bool result = IsMouseButtonDown(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_IsMouseButtonReleased(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- bool result = IsMouseButtonReleased(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_IsMouseButtonUp(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- bool result = IsMouseButtonUp(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_GetMouseX(lua_State* L)
-{
- int result = GetMouseX();
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_GetMouseY(lua_State* L)
-{
- int result = GetMouseY();
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_GetMousePosition(lua_State* L)
-{
- Vector2 result = GetMousePosition();
- LuaPush_Vector2(L, result);
- return 1;
-}
-
-int lua_SetMousePosition(lua_State* L)
-{
- Vector2 arg1 = LuaGetArgument_Vector2(L, 1);
- SetMousePosition(arg1);
- return 0;
-}
-
-int lua_GetMouseWheelMove(lua_State* L)
-{
- int result = GetMouseWheelMove();
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_GetTouchX(lua_State* L)
-{
- int result = GetTouchX();
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_GetTouchY(lua_State* L)
-{
- int result = GetTouchY();
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_GetTouchPosition(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- Vector2 result = GetTouchPosition(arg1);
- LuaPush_Vector2(L, result);
- return 1;
-}
-
-
-#if defined(PLATFORM_ANDROID)
-int lua_IsButtonPressed(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- bool result = IsButtonPressed(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_IsButtonDown(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- bool result = IsButtonDown(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_IsButtonReleased(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- bool result = IsButtonReleased(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-#endif
-
-//------------------------------------------------------------------------------------
-// raylib [gestures] module functions - Gestures and Touch Handling
-//------------------------------------------------------------------------------------
-int lua_SetGesturesEnabled(lua_State* L)
-{
- unsigned arg1 = LuaGetArgument_unsigned(L, 1);
- SetGesturesEnabled(arg1);
- return 0;
-}
-
-int lua_IsGestureDetected(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- bool result = IsGestureDetected(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_GetTouchPointsCount(lua_State* L)
-{
- int result = GetTouchPointsCount();
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_GetGestureDetected(lua_State* L)
-{
- int result = GetGestureDetected();
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_GetGestureHoldDuration(lua_State* L)
-{
- int result = GetGestureHoldDuration();
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_GetGestureDragVector(lua_State* L)
-{
- Vector2 result = GetGestureDragVector();
- LuaPush_Vector2(L, result);
- return 1;
-}
-
-int lua_GetGestureDragAngle(lua_State* L)
-{
- float result = GetGestureDragAngle();
- lua_pushnumber(L, result);
- return 1;
-}
-
-int lua_GetGesturePinchVector(lua_State* L)
-{
- Vector2 result = GetGesturePinchVector();
- LuaPush_Vector2(L, result);
- return 1;
-}
-
-int lua_GetGesturePinchAngle(lua_State* L)
-{
- float result = GetGesturePinchAngle();
- lua_pushnumber(L, result);
- return 1;
-}
-
-//------------------------------------------------------------------------------------
-// raylib [camera] module functions - Camera System
-//------------------------------------------------------------------------------------
-int lua_SetCameraMode(lua_State* L)
-{
- Camera arg1 = LuaGetArgument_Camera(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- SetCameraMode(arg1, arg2);
- return 0;
-}
-
-int lua_UpdateCamera(lua_State* L)
-{
- Camera arg1 = LuaGetArgument_Camera(L, 1);
- UpdateCamera(&arg1);
- LuaPush_Camera(L, arg1);
- return 1;
-}
-
-int lua_SetCameraPanControl(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- SetCameraPanControl(arg1);
- return 0;
-}
-
-int lua_SetCameraAltControl(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- SetCameraAltControl(arg1);
- return 0;
-}
-
-int lua_SetCameraSmoothZoomControl(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- SetCameraSmoothZoomControl(arg1);
- return 0;
-}
-
-int lua_SetCameraMoveControls(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- int arg5 = LuaGetArgument_int(L, 5);
- int arg6 = LuaGetArgument_int(L, 6);
- SetCameraMoveControls(arg1, arg2, arg3, arg4, arg5, arg6);
- return 0;
-}
-
-//------------------------------------------------------------------------------------
-// raylib [shapes] module functions - Basic Shapes Drawing
-//------------------------------------------------------------------------------------
-int lua_DrawPixel(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- Color arg3 = LuaGetArgument_Color(L, 3);
- DrawPixel(arg1, arg2, arg3);
- return 0;
-}
-
-int lua_DrawPixelV(lua_State* L)
-{
- Vector2 arg1 = LuaGetArgument_Vector2(L, 1);
- Color arg2 = LuaGetArgument_Color(L, 2);
- DrawPixelV(arg1, arg2);
- return 0;
-}
-
-int lua_DrawLine(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- DrawLine(arg1, arg2, arg3, arg4, arg5);
- return 0;
-}
-
-int lua_DrawLineV(lua_State* L)
-{
- Vector2 arg1 = LuaGetArgument_Vector2(L, 1);
- Vector2 arg2 = LuaGetArgument_Vector2(L, 2);
- Color arg3 = LuaGetArgument_Color(L, 3);
- DrawLineV(arg1, arg2, arg3);
- return 0;
-}
-
-int lua_DrawCircle(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- Color arg4 = LuaGetArgument_Color(L, 4);
- DrawCircle(arg1, arg2, arg3, arg4);
- return 0;
-}
-
-int lua_DrawCircleGradient(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- Color arg4 = LuaGetArgument_Color(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- DrawCircleGradient(arg1, arg2, arg3, arg4, arg5);
- return 0;
-}
-
-int lua_DrawCircleV(lua_State* L)
-{
- Vector2 arg1 = LuaGetArgument_Vector2(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- Color arg3 = LuaGetArgument_Color(L, 3);
- DrawCircleV(arg1, arg2, arg3);
- return 0;
-}
-
-int lua_DrawCircleLines(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- Color arg4 = LuaGetArgument_Color(L, 4);
- DrawCircleLines(arg1, arg2, arg3, arg4);
- return 0;
-}
-
-int lua_DrawRectangle(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- DrawRectangle(arg1, arg2, arg3, arg4, arg5);
- return 0;
-}
-
-int lua_DrawRectangleRec(lua_State* L)
-{
- Rectangle arg1 = LuaGetArgument_Rectangle(L, 1);
- Color arg2 = LuaGetArgument_Color(L, 2);
- DrawRectangleRec(arg1, arg2);
- return 0;
-}
-
-int lua_DrawRectangleGradient(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- Color arg6 = LuaGetArgument_Color(L, 6);
- DrawRectangleGradient(arg1, arg2, arg3, arg4, arg5, arg6);
- return 0;
-}
-
-int lua_DrawRectangleV(lua_State* L)
-{
- Vector2 arg1 = LuaGetArgument_Vector2(L, 1);
- Vector2 arg2 = LuaGetArgument_Vector2(L, 2);
- Color arg3 = LuaGetArgument_Color(L, 3);
- DrawRectangleV(arg1, arg2, arg3);
- return 0;
-}
-
-int lua_DrawRectangleLines(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- DrawRectangleLines(arg1, arg2, arg3, arg4, arg5);
- return 0;
-}
-
-int lua_DrawTriangle(lua_State* L)
-{
- Vector2 arg1 = LuaGetArgument_Vector2(L, 1);
- Vector2 arg2 = LuaGetArgument_Vector2(L, 2);
- Vector2 arg3 = LuaGetArgument_Vector2(L, 3);
- Color arg4 = LuaGetArgument_Color(L, 4);
- DrawTriangle(arg1, arg2, arg3, arg4);
- return 0;
-}
-
-int lua_DrawTriangleLines(lua_State* L)
-{
- Vector2 arg1 = LuaGetArgument_Vector2(L, 1);
- Vector2 arg2 = LuaGetArgument_Vector2(L, 2);
- Vector2 arg3 = LuaGetArgument_Vector2(L, 3);
- Color arg4 = LuaGetArgument_Color(L, 4);
- DrawTriangleLines(arg1, arg2, arg3, arg4);
- return 0;
-}
-
-int lua_DrawPoly(lua_State* L)
-{
- Vector2 arg1 = LuaGetArgument_Vector2(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- float arg4 = LuaGetArgument_float(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- DrawPoly(arg1, arg2, arg3, arg4, arg5);
- return 0;
-}
-
-#define GET_TABLE(type, name, index) \
- type* name = 0; \
- size_t name##_size = 0; \
- { \
- size_t sz = 0; \
- luaL_checktype(L, index, LUA_TTABLE); \
- lua_pushnil(L); \
- while (lua_next(L, index)) { \
- LuaGetArgument_##type(L, -1); \
- sz++; \
- lua_pop(L, 1); \
- } \
- name = calloc(sz, sizeof(type)); \
- sz = 0; \
- lua_pushnil(L); \
- while (lua_next(L, index)) { \
- name[sz] = LuaGetArgument_##type(L, -1); \
- sz++; \
- lua_pop(L, 1); \
- } \
- lua_pop(L, 1); \
- name##_size = sz; \
- }
-
-
-int lua_DrawPolyEx(lua_State* L)
-{
- GET_TABLE(Vector2, arg1, 1);
- Color arg2 = LuaGetArgument_Color(L, 2);
- DrawPolyEx(arg1, arg1_size, arg2);
- free(arg1);
- return 0;
-}
-
-int lua_DrawPolyExLines(lua_State* L)
-{
- GET_TABLE(Vector2, arg1, 1);
- Color arg2 = LuaGetArgument_Color(L, 2);
- DrawPolyExLines(arg1, arg1_size, arg2);
- free(arg1);
- return 0;
-}
-
-int lua_CheckCollisionRecs(lua_State* L)
-{
- Rectangle arg1 = LuaGetArgument_Rectangle(L, 1);
- Rectangle arg2 = LuaGetArgument_Rectangle(L, 2);
- bool result = CheckCollisionRecs(arg1, arg2);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_CheckCollisionCircles(lua_State* L)
-{
- Vector2 arg1 = LuaGetArgument_Vector2(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- Vector2 arg3 = LuaGetArgument_Vector2(L, 3);
- float arg4 = LuaGetArgument_float(L, 4);
- bool result = CheckCollisionCircles(arg1, arg2, arg3, arg4);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_CheckCollisionCircleRec(lua_State* L)
-{
- Vector2 arg1 = LuaGetArgument_Vector2(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- Rectangle arg3 = LuaGetArgument_Rectangle(L, 3);
- bool result = CheckCollisionCircleRec(arg1, arg2, arg3);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_GetCollisionRec(lua_State* L)
-{
- Rectangle arg1 = LuaGetArgument_Rectangle(L, 1);
- Rectangle arg2 = LuaGetArgument_Rectangle(L, 2);
- Rectangle result = GetCollisionRec(arg1, arg2);
- LuaPush_Rectangle(L, result);
- return 1;
-}
-
-int lua_CheckCollisionPointRec(lua_State* L)
-{
- Vector2 arg1 = LuaGetArgument_Vector2(L, 1);
- Rectangle arg2 = LuaGetArgument_Rectangle(L, 2);
- bool result = CheckCollisionPointRec(arg1, arg2);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_CheckCollisionPointCircle(lua_State* L)
-{
- Vector2 arg1 = LuaGetArgument_Vector2(L, 1);
- Vector2 arg2 = LuaGetArgument_Vector2(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- bool result = CheckCollisionPointCircle(arg1, arg2, arg3);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_CheckCollisionPointTriangle(lua_State* L)
-{
- Vector2 arg1 = LuaGetArgument_Vector2(L, 1);
- Vector2 arg2 = LuaGetArgument_Vector2(L, 2);
- Vector2 arg3 = LuaGetArgument_Vector2(L, 3);
- Vector2 arg4 = LuaGetArgument_Vector2(L, 4);
- bool result = CheckCollisionPointTriangle(arg1, arg2, arg3, arg4);
- lua_pushboolean(L, result);
- return 1;
-}
-
-//------------------------------------------------------------------------------------
-// raylib [textures] module functions - Texture Loading and Drawing
-//------------------------------------------------------------------------------------
-int lua_LoadImage(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- Image result = LoadImage(arg1);
- LuaPush_Image(L, result);
- return 1;
-}
-
-int lua_LoadImageEx(lua_State* L)
-{
- // TODO: Image LoadImageEx(Color *pixels, int width, int height);
-
- GET_TABLE(Color, arg1, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- Image result = LoadImageEx(arg1, arg2, arg3); // ISSUE: #3 number expected, got no value
- LuaPush_Image(L, result);
- free(arg1);
- return 1;
-}
-
-int lua_LoadImageRaw(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- int arg5 = LuaGetArgument_int(L, 5);
- Image result = LoadImageRaw(arg1, arg2, arg3, arg4, arg5);
- LuaPush_Image(L, result);
- return 1;
-}
-
-int lua_LoadImageFromRES(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- Image result = LoadImageFromRES(arg1, arg2);
- LuaPush_Image(L, result);
- return 1;
-}
-
-int lua_LoadTexture(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- Texture2D result = LoadTexture(arg1);
- LuaPush_Texture2D(L, result);
- return 1;
-}
-
-int lua_LoadTextureEx(lua_State* L)
-{
- void * arg1 = (char *)LuaGetArgument_string(L, 1); // NOTE: getting argument as string?
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- Texture2D result = LoadTextureEx(arg1, arg2, arg3, arg4);
- LuaPush_Texture2D(L, result);
- return 1;
-}
-
-int lua_LoadTextureFromRES(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- Texture2D result = LoadTextureFromRES(arg1, arg2);
- LuaPush_Texture2D(L, result);
- return 1;
-}
-
-int lua_LoadTextureFromImage(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- Texture2D result = LoadTextureFromImage(arg1);
- LuaPush_Texture2D(L, result);
- return 1;
-}
-
-int lua_LoadRenderTexture(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- RenderTexture2D result = LoadRenderTexture(arg1, arg2);
- LuaPush_RenderTexture2D(L, result);
- return 1;
-}
-
-int lua_UnloadImage(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- UnloadImage(arg1);
- return 0;
-}
-
-int lua_UnloadTexture(lua_State* L)
-{
- Texture2D arg1 = LuaGetArgument_Texture2D(L, 1);
- UnloadTexture(arg1);
- return 0;
-}
-
-int lua_UnloadRenderTexture(lua_State* L)
-{
- RenderTexture2D arg1 = LuaGetArgument_RenderTexture2D(L, 1);
- UnloadRenderTexture(arg1);
- return 0;
-}
-
-int lua_GetImageData(lua_State* L)
-{
- // TODO: Color *GetImageData(Image image);
-
- Image arg1 = LuaGetArgument_Image(L, 1);
- Color * result = GetImageData(arg1);
- lua_createtable(L, arg1.width*arg1.height, 0);
- for (int i = 0; i < arg1.width*arg1.height; i++)
- {
- LuaPush_Color(L, result[i]);
- lua_rawseti(L, -2, i + 1);
- }
- free(result);
- return 1;
-}
-
-int lua_GetTextureData(lua_State* L)
-{
- Texture2D arg1 = LuaGetArgument_Texture2D(L, 1);
- Image result = GetTextureData(arg1);
- LuaPush_Image(L, result);
- return 1;
-}
-
-int lua_UpdateTexture(lua_State* L)
-{
- // TODO: void UpdateTexture(Texture2D texture, void *pixels);
-
- Texture2D arg1 = LuaGetArgument_Texture2D(L, 1);
- void * arg2 = (char *)LuaGetArgument_string(L, 2); // NOTE: Getting (void *) as string?
- UpdateTexture(arg1, arg2); // ISSUE: #2 string expected, got table -> GetImageData() returns a table!
- return 0;
-}
-
-int lua_ImageToPOT(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- Color arg2 = LuaGetArgument_Color(L, 2);
- ImageToPOT(&arg1, arg2);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_ImageFormat(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- ImageFormat(&arg1, arg2);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_ImageDither(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- int arg5 = LuaGetArgument_int(L, 5);
- ImageDither(&arg1, arg2, arg3, arg4, arg5);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_ImageCopy(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- Image result = ImageCopy(arg1);
- LuaPush_Image(L, result);
- return 1;
-}
-
-int lua_ImageCrop(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- Rectangle arg2 = LuaGetArgument_Rectangle(L, 2);
- ImageCrop(&arg1, arg2);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_ImageResize(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- ImageResize(&arg1, arg2, arg3);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_ImageResizeNN(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- ImageResizeNN(&arg1, arg2, arg3);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_ImageText(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- Color arg3 = LuaGetArgument_Color(L, 3);
- Image result = ImageText(arg1, arg2, arg3);
- LuaPush_Image(L, result);
- return 1;
-}
-
-int lua_ImageTextEx(lua_State* L)
-{
- SpriteFont arg1 = LuaGetArgument_SpriteFont(L, 1);
- const char * arg2 = LuaGetArgument_string(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- Image result = ImageTextEx(arg1, arg2, arg3, arg4, arg5);
- LuaPush_Image(L, result);
- return 1;
-}
-
-int lua_ImageDraw(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- Image arg2 = LuaGetArgument_Image(L, 2);
- Rectangle arg3 = LuaGetArgument_Rectangle(L, 3);
- Rectangle arg4 = LuaGetArgument_Rectangle(L, 4);
- ImageDraw(&arg1, arg2, arg3, arg4);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_ImageDrawText(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- Vector2 arg2 = LuaGetArgument_Vector2(L, 2);
- const char * arg3 = LuaGetArgument_string(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- ImageDrawText(&arg1, arg2, arg3, arg4, arg5);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_ImageDrawTextEx(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- Vector2 arg2 = LuaGetArgument_Vector2(L, 2);
- SpriteFont arg3 = LuaGetArgument_SpriteFont(L, 3);
- const char * arg4 = LuaGetArgument_string(L, 4);
- float arg5 = LuaGetArgument_float(L, 5);
- int arg6 = LuaGetArgument_int(L, 6);
- Color arg7 = LuaGetArgument_Color(L, 7);
- ImageDrawTextEx(&arg1, arg2, arg3, arg4, arg5, arg6, arg7);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_ImageFlipVertical(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- ImageFlipVertical(&arg1);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_ImageFlipHorizontal(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- ImageFlipHorizontal(&arg1);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_ImageColorTint(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- Color arg2 = LuaGetArgument_Color(L, 2);
- ImageColorTint(&arg1, arg2);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_ImageColorInvert(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- ImageColorInvert(&arg1);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_ImageColorGrayscale(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- ImageColorGrayscale(&arg1);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_ImageColorContrast(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- ImageColorContrast(&arg1, arg2);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_ImageColorBrightness(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- ImageColorBrightness(&arg1, arg2);
- LuaPush_Image(L, arg1);
- return 1;
-}
-
-int lua_GenTextureMipmaps(lua_State* L)
-{
- Texture2D arg1 = LuaGetArgument_Texture2D(L, 1);
- GenTextureMipmaps(arg1);
- return 0;
-}
-
-int lua_SetTextureFilter(lua_State* L)
-{
- Texture2D arg1 = LuaGetArgument_Texture2D(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- SetTextureFilter(arg1, arg2);
- return 0;
-}
-
-int lua_SetTextureWrap(lua_State* L)
-{
- Texture2D arg1 = LuaGetArgument_Texture2D(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- SetTextureWrap(arg1, arg2);
- return 0;
-}
-
-int lua_DrawTexture(lua_State* L)
-{
- Texture2D arg1 = LuaGetArgument_Texture2D(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- Color arg4 = LuaGetArgument_Color(L, 4);
- DrawTexture(arg1, arg2, arg3, arg4);
- return 0;
-}
-
-int lua_DrawTextureV(lua_State* L)
-{
- Texture2D arg1 = LuaGetArgument_Texture2D(L, 1);
- Vector2 arg2 = LuaGetArgument_Vector2(L, 2);
- Color arg3 = LuaGetArgument_Color(L, 3);
- DrawTextureV(arg1, arg2, arg3);
- return 0;
-}
-
-int lua_DrawTextureEx(lua_State* L)
-{
- Texture2D arg1 = LuaGetArgument_Texture2D(L, 1);
- Vector2 arg2 = LuaGetArgument_Vector2(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- float arg4 = LuaGetArgument_float(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- DrawTextureEx(arg1, arg2, arg3, arg4, arg5);
- return 0;
-}
-
-int lua_DrawTextureRec(lua_State* L)
-{
- Texture2D arg1 = LuaGetArgument_Texture2D(L, 1);
- Rectangle arg2 = LuaGetArgument_Rectangle(L, 2);
- Vector2 arg3 = LuaGetArgument_Vector2(L, 3);
- Color arg4 = LuaGetArgument_Color(L, 4);
- DrawTextureRec(arg1, arg2, arg3, arg4);
- return 0;
-}
-
-int lua_DrawTexturePro(lua_State* L)
-{
- Texture2D arg1 = LuaGetArgument_Texture2D(L, 1);
- Rectangle arg2 = LuaGetArgument_Rectangle(L, 2);
- Rectangle arg3 = LuaGetArgument_Rectangle(L, 3);
- Vector2 arg4 = LuaGetArgument_Vector2(L, 4);
- float arg5 = LuaGetArgument_float(L, 5);
- Color arg6 = LuaGetArgument_Color(L, 6);
- DrawTexturePro(arg1, arg2, arg3, arg4, arg5, arg6);
- return 0;
-}
-
-//------------------------------------------------------------------------------------
-// raylib [text] module functions - Font Loading and Text Drawing
-//------------------------------------------------------------------------------------
-int lua_GetDefaultFont(lua_State* L)
-{
- SpriteFont result = GetDefaultFont();
- LuaPush_SpriteFont(L, result);
- return 1;
-}
-
-int lua_LoadSpriteFont(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- SpriteFont result = LoadSpriteFont(arg1);
- LuaPush_SpriteFont(L, result);
- return 1;
-}
-
-int lua_LoadSpriteFontTTF(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- //LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, int *fontChars);
- SpriteFont result = LoadSpriteFontTTF(arg1, arg2, arg3, &arg4);
- LuaPush_SpriteFont(L, result);
- return 1;
-}
-
-int lua_UnloadSpriteFont(lua_State* L)
-{
- SpriteFont arg1 = LuaGetArgument_SpriteFont(L, 1);
- UnloadSpriteFont(arg1);
- return 0;
-}
-
-int lua_DrawText(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- DrawText(arg1, arg2, arg3, arg4, arg5);
- return 0;
-}
-
-int lua_DrawTextEx(lua_State* L)
-{
- SpriteFont arg1 = LuaGetArgument_SpriteFont(L, 1);
- const char * arg2 = LuaGetArgument_string(L, 2);
- Vector2 arg3 = LuaGetArgument_Vector2(L, 3);
- float arg4 = LuaGetArgument_float(L, 4);
- int arg5 = LuaGetArgument_int(L, 5);
- Color arg6 = LuaGetArgument_Color(L, 6);
- DrawTextEx(arg1, arg2, arg3, arg4, arg5, arg6);
- return 0;
-}
-
-int lua_MeasureText(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int result = MeasureText(arg1, arg2);
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_MeasureTextEx(lua_State* L)
-{
- SpriteFont arg1 = LuaGetArgument_SpriteFont(L, 1);
- const char * arg2 = LuaGetArgument_string(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- Vector2 result = MeasureTextEx(arg1, arg2, arg3, arg4);
- LuaPush_Vector2(L, result);
- return 1;
-}
-
-int lua_DrawFPS(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- DrawFPS(arg1, arg2);
- return 0;
-}
-
-// NOTE: FormatText() can be replaced by Lua function: string.format()
-// NOTE: SubText() can be replaced by Lua function: string.sub()
-
-//------------------------------------------------------------------------------------
-// raylib [models] module functions - Basic 3d Shapes Drawing Functions
-//------------------------------------------------------------------------------------
-int lua_DrawLine3D(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- Color arg3 = LuaGetArgument_Color(L, 3);
- DrawLine3D(arg1, arg2, arg3);
- return 0;
-}
-
-int lua_DrawCircle3D(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- Vector3 arg3 = LuaGetArgument_Vector3(L, 3);
- float arg4 = LuaGetArgument_float(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- DrawCircle3D(arg1, arg2, arg3, arg4, arg5);
- return 0;
-}
-
-int lua_DrawCube(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- float arg4 = LuaGetArgument_float(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- DrawCube(arg1, arg2, arg3, arg4, arg5);
- return 0;
-}
-
-int lua_DrawCubeV(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- Color arg3 = LuaGetArgument_Color(L, 3);
- DrawCubeV(arg1, arg2, arg3);
- return 0;
-}
-
-int lua_DrawCubeWires(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- float arg4 = LuaGetArgument_float(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- DrawCubeWires(arg1, arg2, arg3, arg4, arg5);
- return 0;
-}
-
-int lua_DrawCubeTexture(lua_State* L)
-{
- Texture2D arg1 = LuaGetArgument_Texture2D(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- float arg4 = LuaGetArgument_float(L, 4);
- float arg5 = LuaGetArgument_float(L, 5);
- Color arg6 = LuaGetArgument_Color(L, 6);
- DrawCubeTexture(arg1, arg2, arg3, arg4, arg5, arg6);
- return 0;
-}
-
-int lua_DrawSphere(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- Color arg3 = LuaGetArgument_Color(L, 3);
- DrawSphere(arg1, arg2, arg3);
- return 0;
-}
-
-int lua_DrawSphereEx(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- DrawSphereEx(arg1, arg2, arg3, arg4, arg5);
- return 0;
-}
-
-int lua_DrawSphereWires(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- DrawSphereWires(arg1, arg2, arg3, arg4, arg5);
- return 0;
-}
-
-int lua_DrawCylinder(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- float arg4 = LuaGetArgument_float(L, 4);
- int arg5 = LuaGetArgument_int(L, 5);
- Color arg6 = LuaGetArgument_Color(L, 6);
- DrawCylinder(arg1, arg2, arg3, arg4, arg5, arg6);
- return 0;
-}
-
-int lua_DrawCylinderWires(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- float arg4 = LuaGetArgument_float(L, 4);
- int arg5 = LuaGetArgument_int(L, 5);
- Color arg6 = LuaGetArgument_Color(L, 6);
- DrawCylinderWires(arg1, arg2, arg3, arg4, arg5, arg6);
- return 0;
-}
-
-int lua_DrawPlane(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- Vector2 arg2 = LuaGetArgument_Vector2(L, 2);
- Color arg3 = LuaGetArgument_Color(L, 3);
- DrawPlane(arg1, arg2, arg3);
- return 0;
-}
-
-int lua_DrawRay(lua_State* L)
-{
- Ray arg1 = LuaGetArgument_Ray(L, 1);
- Color arg2 = LuaGetArgument_Color(L, 2);
- DrawRay(arg1, arg2);
- return 0;
-}
-
-int lua_DrawGrid(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- DrawGrid(arg1, arg2);
- return 0;
-}
-
-int lua_DrawGizmo(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- DrawGizmo(arg1);
- return 0;
-}
-
-int lua_DrawLight(lua_State* L)
-{
- Light arg1 = LuaGetArgument_Light(L, 1);
- DrawLight(arg1);
- return 0;
-}
-
-//------------------------------------------------------------------------------------
-// raylib [models] module functions
-//------------------------------------------------------------------------------------
-int lua_LoadModel(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- Model result = LoadModel(arg1);
- LuaPush_Model(L, result);
- return 1;
-}
-
-int lua_LoadModelEx(lua_State* L)
-{
- Mesh arg1 = LuaGetArgument_Mesh(L, 1);
- bool arg2 = LuaGetArgument_int(L, 2);
- Model result = LoadModelEx(arg1, arg2);
- LuaPush_Model(L, result);
- return 1;
-}
-
-int lua_LoadModelFromRES(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- Model result = LoadModelFromRES(arg1, arg2);
- LuaPush_Model(L, result);
- return 1;
-}
-
-int lua_LoadHeightmap(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- Model result = LoadHeightmap(arg1, arg2);
- LuaPush_Model(L, result);
- return 1;
-}
-
-int lua_LoadCubicmap(lua_State* L)
-{
- Image arg1 = LuaGetArgument_Image(L, 1);
- Model result = LoadCubicmap(arg1);
- LuaPush_Model(L, result);
- return 1;
-}
-
-int lua_UnloadModel(lua_State* L)
-{
- Model arg1 = LuaGetArgument_Model(L, 1);
- UnloadModel(arg1);
- return 0;
-}
-
-// TODO: GenMesh*() functionality (not ready yet on raylib 1.6)
-
-int lua_LoadMaterial(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- Material result = LoadMaterial(arg1);
- LuaPush_Material(L, result);
- return 1;
-}
-
-int lua_LoadDefaultMaterial(lua_State* L)
-{
- Material result = LoadDefaultMaterial();
- LuaPush_Material(L, result);
- return 1;
-}
-
-int lua_LoadStandardMaterial(lua_State* L)
-{
- Material result = LoadStandardMaterial();
- LuaPush_Material(L, result);
- return 1;
-}
-
-int lua_UnloadMaterial(lua_State* L)
-{
- Material arg1 = LuaGetArgument_Material(L, 1);
- UnloadMaterial(arg1);
- return 0;
-}
-
-int lua_DrawModel(lua_State* L)
-{
- Model arg1 = LuaGetArgument_Model(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- Color arg4 = LuaGetArgument_Color(L, 4);
- DrawModel(arg1, arg2, arg3, arg4);
- return 0;
-}
-
-int lua_DrawModelEx(lua_State* L)
-{
- Model arg1 = LuaGetArgument_Model(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- Vector3 arg3 = LuaGetArgument_Vector3(L, 3);
- float arg4 = LuaGetArgument_float(L, 4);
- Vector3 arg5 = LuaGetArgument_Vector3(L, 5);
- Color arg6 = LuaGetArgument_Color(L, 6);
- DrawModelEx(arg1, arg2, arg3, arg4, arg5, arg6);
- return 0;
-}
-
-int lua_DrawModelWires(lua_State* L)
-{
- Model arg1 = LuaGetArgument_Model(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- Color arg4 = LuaGetArgument_Color(L, 4);
- DrawModelWires(arg1, arg2, arg3, arg4);
- return 0;
-}
-
-int lua_DrawModelWiresEx(lua_State* L)
-{
- Model arg1 = LuaGetArgument_Model(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- Vector3 arg3 = LuaGetArgument_Vector3(L, 3);
- float arg4 = LuaGetArgument_float(L, 4);
- Vector3 arg5 = LuaGetArgument_Vector3(L, 5);
- Color arg6 = LuaGetArgument_Color(L, 6);
- DrawModelWiresEx(arg1, arg2, arg3, arg4, arg5, arg6);
- return 0;
-}
-
-int lua_DrawBillboard(lua_State* L)
-{
- Camera arg1 = LuaGetArgument_Camera(L, 1);
- Texture2D arg2 = LuaGetArgument_Texture2D(L, 2);
- Vector3 arg3 = LuaGetArgument_Vector3(L, 3);
- float arg4 = LuaGetArgument_float(L, 4);
- Color arg5 = LuaGetArgument_Color(L, 5);
- DrawBillboard(arg1, arg2, arg3, arg4, arg5);
- return 0;
-}
-
-int lua_DrawBillboardRec(lua_State* L)
-{
- Camera arg1 = LuaGetArgument_Camera(L, 1);
- Texture2D arg2 = LuaGetArgument_Texture2D(L, 2);
- Rectangle arg3 = LuaGetArgument_Rectangle(L, 3);
- Vector3 arg4 = LuaGetArgument_Vector3(L, 4);
- float arg5 = LuaGetArgument_float(L, 5);
- Color arg6 = LuaGetArgument_Color(L, 6);
- DrawBillboardRec(arg1, arg2, arg3, arg4, arg5, arg6);
- return 0;
-}
-
-int lua_CalculateBoundingBox(lua_State* L)
-{
- Mesh arg1 = LuaGetArgument_Mesh(L, 1);
- BoundingBox result = CalculateBoundingBox(arg1);
- LuaPush_BoundingBox(L, result);
- return 1;
-}
-
-int lua_CheckCollisionSpheres(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- Vector3 arg3 = LuaGetArgument_Vector3(L, 3);
- float arg4 = LuaGetArgument_float(L, 4);
- bool result = CheckCollisionSpheres(arg1, arg2, arg3, arg4);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_CheckCollisionBoxes(lua_State* L)
-{
- BoundingBox arg1 = LuaGetArgument_BoundingBox(L, 1);
- BoundingBox arg2 = LuaGetArgument_BoundingBox(L, 2);
- bool result = CheckCollisionBoxes(arg1, arg2);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_CheckCollisionBoxSphere(lua_State* L)
-{
- BoundingBox arg1 = LuaGetArgument_BoundingBox(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- bool result = CheckCollisionBoxSphere(arg1, arg2, arg3);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_CheckCollisionRaySphere(lua_State* L)
-{
- Ray arg1 = LuaGetArgument_Ray(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- bool result = CheckCollisionRaySphere(arg1, arg2, arg3);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_CheckCollisionRaySphereEx(lua_State* L)
-{
- Ray arg1 = LuaGetArgument_Ray(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- Vector3 arg4 = LuaGetArgument_Vector3(L, 4);
- bool result = CheckCollisionRaySphereEx(arg1, arg2, arg3, &arg4);
- lua_pushboolean(L, result);
- LuaPush_Vector3(L, arg4);
- return 2;
-}
-
-int lua_CheckCollisionRayBox(lua_State* L)
-{
- Ray arg1 = LuaGetArgument_Ray(L, 1);
- BoundingBox arg2 = LuaGetArgument_BoundingBox(L, 2);
- bool result = CheckCollisionRayBox(arg1, arg2);
- lua_pushboolean(L, result);
- return 1;
-}
-
-//------------------------------------------------------------------------------------
-// raylib [raymath] module functions - Shaders
-//------------------------------------------------------------------------------------
-int lua_LoadShader(lua_State* L)
-{
- char * arg1 = (char *)LuaGetArgument_string(L, 1);
- char * arg2 = (char *)LuaGetArgument_string(L, 2);
- Shader result = LoadShader(arg1, arg2);
- LuaPush_Shader(L, result);
- return 1;
-}
-
-int lua_UnloadShader(lua_State* L)
-{
- Shader arg1 = LuaGetArgument_Shader(L, 1);
- UnloadShader(arg1);
- return 0;
-}
-
-int lua_GetDefaultShader(lua_State* L)
-{
- Shader result = GetDefaultShader();
- LuaPush_Shader(L, result);
- return 1;
-}
-
-int lua_GetStandardShader(lua_State* L)
-{
- Shader result = GetStandardShader();
- LuaPush_Shader(L, result);
- return 1;
-}
-
-int lua_GetDefaultTexture(lua_State* L)
-{
- Texture2D result = GetDefaultTexture();
- LuaPush_Texture2D(L, result);
- return 1;
-}
-
-int lua_GetShaderLocation(lua_State* L)
-{
- Shader arg1 = LuaGetArgument_Shader(L, 1);
- const char * arg2 = LuaGetArgument_string(L, 2);
- int result = GetShaderLocation(arg1, arg2);
- lua_pushinteger(L, result);
- return 1;
-}
-
-int lua_SetShaderValue(lua_State* L)
-{
- Shader arg1 = LuaGetArgument_Shader(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- GET_TABLE(float, arg3, 3);
- SetShaderValue(arg1, arg2, arg3, arg3_size);
- free(arg3);
- return 0;
-}
-
-int lua_SetShaderValuei(lua_State* L)
-{
- Shader arg1 = LuaGetArgument_Shader(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- GET_TABLE(int, arg3, 3);
- SetShaderValuei(arg1, arg2, arg3, arg3_size);
- free(arg3);
- return 0;
-}
-
-int lua_SetShaderValueMatrix(lua_State* L)
-{
- Shader arg1 = LuaGetArgument_Shader(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- Matrix arg3 = LuaGetArgument_Matrix(L, 3);
- SetShaderValueMatrix(arg1, arg2, arg3);
- return 0;
-}
-
-int lua_SetMatrixProjection(lua_State* L)
-{
- Matrix arg1 = LuaGetArgument_Matrix(L, 1);
- SetMatrixProjection(arg1);
- return 0;
-}
-
-int lua_SetMatrixModelview(lua_State* L)
-{
- Matrix arg1 = LuaGetArgument_Matrix(L, 1);
- SetMatrixModelview(arg1);
- return 0;
-}
-
-int lua_BeginShaderMode(lua_State* L)
-{
- Shader arg1 = LuaGetArgument_Shader(L, 1);
- BeginShaderMode(arg1);
- return 0;
-}
-
-int lua_EndShaderMode(lua_State* L)
-{
- EndShaderMode();
- return 0;
-}
-
-int lua_BeginBlendMode(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- BeginBlendMode(arg1);
- return 0;
-}
-
-int lua_EndBlendMode(lua_State* L)
-{
- EndBlendMode();
- return 0;
-}
-
-int lua_CreateLight(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- Color arg3 = LuaGetArgument_Color(L, 3);
- Light result = CreateLight(arg1, arg2, arg3);
- LuaPush_Light(L, result);
- return 1;
-}
-
-int lua_DestroyLight(lua_State* L)
-{
- Light arg1 = LuaGetArgument_Light(L, 1);
- DestroyLight(arg1);
- return 0;
-}
-
-
-//------------------------------------------------------------------------------------
-// raylib [rlgl] module functions - VR experience
-//------------------------------------------------------------------------------------
-int lua_InitVrDevice(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- InitVrDevice(arg1);
- return 0;
-}
-
-int lua_CloseVrDevice(lua_State* L)
-{
- CloseVrDevice();
- return 0;
-}
-
-int lua_IsVrDeviceReady(lua_State* L)
-{
- bool result = IsVrDeviceReady();
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_IsVrSimulator(lua_State* L)
-{
- bool result = IsVrSimulator();
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_UpdateVrTracking(lua_State* L)
-{
- Camera arg1 = LuaGetArgument_Camera(L, 1);
- UpdateVrTracking(&arg1);
- LuaPush_Camera(L, arg1);
- return 1;
-}
-
-int lua_ToggleVrMode(lua_State* L)
-{
- ToggleVrMode();
- return 0;
-}
-
-//------------------------------------------------------------------------------------
-// raylib [audio] module functions - Audio Loading and Playing
-//------------------------------------------------------------------------------------
-int lua_InitAudioDevice(lua_State* L)
-{
- InitAudioDevice();
- return 0;
-}
-
-int lua_CloseAudioDevice(lua_State* L)
-{
- CloseAudioDevice();
- return 0;
-}
-
-int lua_IsAudioDeviceReady(lua_State* L)
-{
- bool result = IsAudioDeviceReady();
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_LoadWave(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- Wave result = LoadWave((char *)arg1);
- LuaPush_Wave(L, result);
- return 1;
-}
-
-int lua_LoadWaveEx(lua_State* L)
-{
- // TODO: Wave LoadWaveEx(float *data, int sampleCount, int sampleRate, int sampleSize, int channels);
-
- int arg1 = 0;
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- int arg5 = LuaGetArgument_int(L, 5);
- Wave result = LoadWaveEx(arg1, arg2, arg3, arg4, arg5);
- LuaPush_Wave(L, result);
- return 1;
-}
-
-int lua_LoadSound(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- Sound result = LoadSound((char*)arg1);
- LuaPush_Sound(L, result);
- return 1;
-}
-
-int lua_LoadSoundFromWave(lua_State* L)
-{
- Wave arg1 = LuaGetArgument_Wave(L, 1);
- Sound result = LoadSoundFromWave(arg1);
- LuaPush_Sound(L, result);
- return 1;
-}
-
-int lua_LoadSoundFromRES(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- Sound result = LoadSoundFromRES(arg1, arg2);
- LuaPush_Sound(L, result);
- return 1;
-}
-
-int lua_UpdateSound(lua_State* L)
-{
- // TODO: void UpdateSound(Sound sound, void *data, int numSamples);
-
- Sound arg1 = LuaGetArgument_Sound(L, 1);
- const char * arg2 = LuaGetArgument_string(L, 2);
- int * arg3 = LuaGetArgument_int(L, 3);
- UpdateSound(arg1, arg2, arg3);
- return 0;
-}
-
-int lua_UnloadWave(lua_State* L)
-{
- Wave arg1 = LuaGetArgument_Wave(L, 1);
- UnloadWave(arg1);
- return 0;
-}
-
-int lua_UnloadSound(lua_State* L)
-{
- Sound arg1 = LuaGetArgument_Sound(L, 1);
- UnloadSound(arg1);
- return 0;
-}
-
-int lua_PlaySound(lua_State* L)
-{
- Sound arg1 = LuaGetArgument_Sound(L, 1);
- PlaySound(arg1);
- return 0;
-}
-
-int lua_PauseSound(lua_State* L)
-{
- Sound arg1 = LuaGetArgument_Sound(L, 1);
- PauseSound(arg1);
- return 0;
-}
-
-int lua_ResumeSound(lua_State* L)
-{
- Sound arg1 = LuaGetArgument_Sound(L, 1);
- ResumeSound(arg1);
- return 0;
-}
-
-int lua_StopSound(lua_State* L)
-{
- Sound arg1 = LuaGetArgument_Sound(L, 1);
- StopSound(arg1);
- return 0;
-}
-
-int lua_IsSoundPlaying(lua_State* L)
-{
- Sound arg1 = LuaGetArgument_Sound(L, 1);
- bool result = IsSoundPlaying(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_SetSoundVolume(lua_State* L)
-{
- Sound arg1 = LuaGetArgument_Sound(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- SetSoundVolume(arg1, arg2);
- return 0;
-}
-
-int lua_SetSoundPitch(lua_State* L)
-{
- Sound arg1 = LuaGetArgument_Sound(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- SetSoundPitch(arg1, arg2);
- return 0;
-}
-
-int lua_WaveFormat(lua_State* L)
-{
- Wave arg1 = LuaGetArgument_Wave(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- WaveFormat(&arg1, arg2, arg3, arg4);
- return 0;
-}
-
-int lua_WaveCopy(lua_State* L)
-{
- Wave arg1 = LuaGetArgument_Wave(L, 1);
- Wave result = WaveCopy(arg1);
- LuaPush_Wave(L, result);
- return 1;
-}
-
-int lua_WaveCrop(lua_State* L)
-{
- Wave arg1 = LuaGetArgument_Wave(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- WaveCrop(&arg1, arg2, arg3);
- return 0;
-}
-
-int lua_GetWaveData(lua_State* L)
-{
- // TODO: float *GetWaveData(Wave wave);
-
- Wave arg1 = LuaGetArgument_Wave(L, 1);
- float * result = GetWaveData(arg1);
- //LuaPush_float(L, result);
- //lua_pushnumber(L, result);
- return 0;
-}
-
-int lua_LoadMusicStream(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- Music result = LoadMusicStream((char *)arg1);
- LuaPush_Music(L, result);
- return 1;
-}
-
-int lua_UnloadMusicStream(lua_State* L)
-{
- Music arg1 = LuaGetArgument_Music(L, 1);
- UnloadMusicStream(arg1);
- return 0;
-}
-
-int lua_UpdateMusicStream(lua_State* L)
-{
- Music arg1 = LuaGetArgument_Music(L, 1);
- UpdateMusicStream(arg1);
- return 0;
-}
-
-int lua_PlayMusicStream(lua_State* L)
-{
- Music arg1 = LuaGetArgument_Music(L, 1);
- PlayMusicStream(arg1);
- return 0;
-}
-
-int lua_StopMusicStream(lua_State* L)
-{
- Music arg1 = LuaGetArgument_Music(L, 1);
- StopMusicStream(arg1);
- return 0;
-}
-
-int lua_PauseMusicStream(lua_State* L)
-{
- Music arg1 = LuaGetArgument_Music(L, 1);
- PauseMusicStream(arg1);
- return 0;
-}
-
-int lua_ResumeMusicStream(lua_State* L)
-{
- Music arg1 = LuaGetArgument_Music(L, 1);
- ResumeMusicStream(arg1);
- return 0;
-}
-
-int lua_IsMusicPlaying(lua_State* L)
-{
- Music arg1 = LuaGetArgument_Music(L, 1);
- bool result = IsMusicPlaying(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_SetMusicVolume(lua_State* L)
-{
- Music arg1 = LuaGetArgument_Music(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- SetMusicVolume(arg1, arg2);
- return 0;
-}
-
-int lua_SetMusicPitch(lua_State* L)
-{
- Music arg1 = LuaGetArgument_Music(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- SetMusicPitch(arg1, arg2);
- return 0;
-}
-
-int lua_GetMusicTimeLength(lua_State* L)
-{
- Music arg1 = LuaGetArgument_Music(L, 1);
- float result = GetMusicTimeLength(arg1);
- lua_pushnumber(L, result);
- return 1;
-}
-
-int lua_GetMusicTimePlayed(lua_State* L)
-{
- Music arg1 = LuaGetArgument_Music(L, 1);
- float result = GetMusicTimePlayed(arg1);
- lua_pushnumber(L, result);
- return 1;
-}
-
-int lua_InitAudioStream(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int arg2 = LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- AudioStream result = InitAudioStream(arg1, arg2, arg3);
- LuaPush_AudioStream(L, result);
- return 1;
-}
-
-int lua_CloseAudioStream(lua_State* L)
-{
- AudioStream arg1 = LuaGetArgument_AudioStream(L, 1);
- CloseAudioStream(arg1);
- return 0;
-}
-
-int lua_UpdateAudioStream(lua_State* L)
-{
- // TODO: void UpdateAudioStream(AudioStream stream, void *data, int numSamples);
-
- AudioStream arg1 = LuaGetArgument_AudioStream(L, 1);
- void * arg2 = (char *)LuaGetArgument_string(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- UpdateAudioStream(arg1, arg2, arg3);
- return 0;
-}
-
-int lua_IsAudioBufferProcessed(lua_State* L)
-{
- AudioStream arg1 = LuaGetArgument_AudioStream(L, 1);
- bool result = IsAudioBufferProcessed(arg1);
- lua_pushboolean(L, result);
- return 1;
-}
-
-int lua_PlayAudioStream(lua_State* L)
-{
- AudioStream arg1 = LuaGetArgument_AudioStream(L, 1);
- PlayAudioStream(arg1);
- return 0;
-}
-
-
-int lua_StopAudioStream(lua_State* L)
-{
- AudioStream arg1 = LuaGetArgument_AudioStream(L, 1);
- StopAudioStream(arg1);
- return 0;
-}
-
-int lua_PauseAudioStream(lua_State* L)
-{
- AudioStream arg1 = LuaGetArgument_AudioStream(L, 1);
- PauseAudioStream(arg1);
- return 0;
-}
-
-int lua_ResumeAudioStream(lua_State* L)
-{
- AudioStream arg1 = LuaGetArgument_AudioStream(L, 1);
- ResumeAudioStream(arg1);
- return 0;
-}
-
-//----------------------------------------------------------------------------------
-// raylib [utils] module functions
-//----------------------------------------------------------------------------------
-int lua_DecompressData(lua_State* L)
-{
- unsigned char *arg1 = (unsigned char *)LuaGetArgument_string(L, 1);
- unsigned arg2 = (unsigned)LuaGetArgument_int(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- unsigned char *result = DecompressData(arg1, arg2, arg3);
- lua_pushlstring(L, (const char *)result, arg3);
- return 1;
-}
-
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
-int lua_WriteBitmap(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- unsigned char* arg2 = (unsigned char*)LuaGetArgument_string(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- WriteBitmap(arg1, arg2, arg3, arg4);
- return 0;
-}
-
-int lua_WritePNG(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- unsigned char* arg2 = (unsigned char*)LuaGetArgument_string(L, 2);
- int arg3 = LuaGetArgument_int(L, 3);
- int arg4 = LuaGetArgument_int(L, 4);
- int arg5 = LuaGetArgument_int(L, 5);
- WritePNG(arg1, arg2, arg3, arg4, arg5);
- return 0;
-}
-#endif
-
-int lua_TraceLog(lua_State* L)
-{
- int num_args = lua_gettop(L) - 1;
- int arg1 = LuaGetArgument_int(L, 1);
-
- /// type, fmt, args...
-
- lua_rotate(L, 1, -1); /// fmt, args..., type
- lua_pop(L, 1); /// fmt, args...
-
- lua_getglobal(L, "string"); /// fmt, args..., [string]
- lua_getfield(L, 1, "format"); /// fmt, args..., [string], format()
- lua_rotate(L, 1, 2); /// [string], format(), fmt, args...
- lua_call(L, num_args, 1); /// [string], formatted_string
-
- TraceLog(arg1, "%s", luaL_checkstring(L,-1));
- return 0;
-}
-
-int lua_GetExtension(lua_State* L)
-{
- const char * arg1 = LuaGetArgument_string(L, 1);
- const char* result = GetExtension(arg1);
- lua_pushstring(L, result);
- return 1;
-}
-
-int lua_GetNextPOT(lua_State* L)
-{
- int arg1 = LuaGetArgument_int(L, 1);
- int result = GetNextPOT(arg1);
- lua_pushinteger(L, result);
- return 1;
-}
-
-//----------------------------------------------------------------------------------
-// raylib [raymath] module functions - Vector3 math
-//----------------------------------------------------------------------------------
-int lua_VectorAdd(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- Vector3 result = VectorAdd(arg1, arg2);
- LuaPush_Vector3(L, result);
- return 1;
-}
-
-int lua_VectorSubtract(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- Vector3 result = VectorSubtract(arg1, arg2);
- LuaPush_Vector3(L, result);
- return 1;
-}
-
-int lua_VectorCrossProduct(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- Vector3 result = VectorCrossProduct(arg1, arg2);
- LuaPush_Vector3(L, result);
- return 1;
-}
-
-int lua_VectorPerpendicular(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- Vector3 result = VectorPerpendicular(arg1);
- LuaPush_Vector3(L, result);
- return 1;
-}
-
-int lua_VectorDotProduct(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- float result = VectorDotProduct(arg1, arg2);
- lua_pushnumber(L, result);
- return 1;
-}
-
-int lua_VectorLength(lua_State* L)
-{
- const Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- float result = VectorLength(arg1);
- lua_pushnumber(L, result);
- return 1;
-}
-
-int lua_VectorScale(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- VectorScale(&arg1, arg2);
- LuaPush_Vector3(L, arg1);
- return 1;
-}
-
-int lua_VectorNegate(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- VectorNegate(&arg1);
- LuaPush_Vector3(L, arg1);
- return 1;
-}
-
-int lua_VectorNormalize(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- VectorNormalize(&arg1);
- LuaPush_Vector3(L, arg1);
- return 1;
-}
-
-int lua_VectorDistance(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- float result = VectorDistance(arg1, arg2);
- lua_pushnumber(L, result);
- return 1;
-}
-
-int lua_VectorLerp(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- Vector3 result = VectorLerp(arg1, arg2, arg3);
- LuaPush_Vector3(L, result);
- return 1;
-}
-
-int lua_VectorReflect(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- Vector3 result = VectorReflect(arg1, arg2);
- LuaPush_Vector3(L, result);
- return 1;
-}
-
-int lua_VectorTransform(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- Matrix arg2 = LuaGetArgument_Matrix(L, 2);
- VectorTransform(&arg1, arg2);
- LuaPush_Vector3(L, arg1);
- return 1;
-}
-
-int lua_VectorZero(lua_State* L)
-{
- Vector3 result = VectorZero();
- LuaPush_Vector3(L, result);
- return 1;
-}
-
-//----------------------------------------------------------------------------------
-// raylib [raymath] module functions - Matrix math
-//----------------------------------------------------------------------------------
-int lua_MatrixDeterminant(lua_State* L)
-{
- Matrix arg1 = LuaGetArgument_Matrix(L, 1);
- float result = MatrixDeterminant(arg1);
- lua_pushnumber(L, result);
- return 1;
-}
-
-int lua_MatrixTrace(lua_State* L)
-{
- Matrix arg1 = LuaGetArgument_Matrix(L, 1);
- float result = MatrixTrace(arg1);
- lua_pushnumber(L, result);
- return 1;
-}
-
-int lua_MatrixTranspose(lua_State* L)
-{
- Matrix arg1 = LuaGetArgument_Matrix(L, 1);
- MatrixTranspose(&arg1);
- LuaPush_Matrix(L, &arg1);
- return 1;
-}
-
-int lua_MatrixInvert(lua_State* L)
-{
- Matrix arg1 = LuaGetArgument_Matrix(L, 1);
- MatrixInvert(&arg1);
- LuaPush_Matrix(L, &arg1);
- return 1;
-}
-
-int lua_MatrixNormalize(lua_State* L)
-{
- Matrix arg1 = LuaGetArgument_Matrix(L, 1);
- MatrixNormalize(&arg1);
- LuaPush_Matrix(L, &arg1);
- return 1;
-}
-
-int lua_MatrixIdentity(lua_State* L)
-{
- Matrix result = MatrixIdentity();
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-int lua_MatrixAdd(lua_State* L)
-{
- Matrix arg1 = LuaGetArgument_Matrix(L, 1);
- Matrix arg2 = LuaGetArgument_Matrix(L, 2);
- Matrix result = MatrixAdd(arg1, arg2);
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-int lua_MatrixSubstract(lua_State* L)
-{
- Matrix arg1 = LuaGetArgument_Matrix(L, 1);
- Matrix arg2 = LuaGetArgument_Matrix(L, 2);
- Matrix result = MatrixSubstract(arg1, arg2);
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-int lua_MatrixTranslate(lua_State* L)
-{
- float arg1 = LuaGetArgument_float(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- Matrix result = MatrixTranslate(arg1, arg2, arg3);
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-int lua_MatrixRotate(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- Matrix result = MatrixRotate(arg1, arg2);
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-int lua_MatrixRotateX(lua_State* L)
-{
- float arg1 = LuaGetArgument_float(L, 1);
- Matrix result = MatrixRotateX(arg1);
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-int lua_MatrixRotateY(lua_State* L)
-{
- float arg1 = LuaGetArgument_float(L, 1);
- Matrix result = MatrixRotateY(arg1);
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-int lua_MatrixRotateZ(lua_State* L)
-{
- float arg1 = LuaGetArgument_float(L, 1);
- Matrix result = MatrixRotateZ(arg1);
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-int lua_MatrixScale(lua_State* L)
-{
- float arg1 = LuaGetArgument_float(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- Matrix result = MatrixScale(arg1, arg2, arg3);
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-int lua_MatrixMultiply(lua_State* L)
-{
- Matrix arg1 = LuaGetArgument_Matrix(L, 1);
- Matrix arg2 = LuaGetArgument_Matrix(L, 2);
- Matrix result = MatrixMultiply(arg1, arg2);
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-int lua_MatrixFrustum(lua_State* L)
-{
- double arg1 = LuaGetArgument_double(L, 1);
- double arg2 = LuaGetArgument_double(L, 2);
- double arg3 = LuaGetArgument_double(L, 3);
- double arg4 = LuaGetArgument_double(L, 4);
- double arg5 = LuaGetArgument_double(L, 5);
- double arg6 = LuaGetArgument_double(L, 6);
- Matrix result = MatrixFrustum(arg1, arg2, arg3, arg4, arg5, arg6);
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-int lua_MatrixPerspective(lua_State* L)
-{
- double arg1 = LuaGetArgument_double(L, 1);
- double arg2 = LuaGetArgument_double(L, 2);
- double arg3 = LuaGetArgument_double(L, 3);
- double arg4 = LuaGetArgument_double(L, 4);
- Matrix result = MatrixPerspective(arg1, arg2, arg3, arg4);
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-int lua_MatrixOrtho(lua_State* L)
-{
- double arg1 = LuaGetArgument_double(L, 1);
- double arg2 = LuaGetArgument_double(L, 2);
- double arg3 = LuaGetArgument_double(L, 3);
- double arg4 = LuaGetArgument_double(L, 4);
- double arg5 = LuaGetArgument_double(L, 5);
- double arg6 = LuaGetArgument_double(L, 6);
- Matrix result = MatrixOrtho(arg1, arg2, arg3, arg4, arg5, arg6);
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-int lua_MatrixLookAt(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- Vector3 arg2 = LuaGetArgument_Vector3(L, 2);
- Vector3 arg3 = LuaGetArgument_Vector3(L, 3);
- Matrix result = MatrixLookAt(arg1, arg2, arg3);
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-//----------------------------------------------------------------------------------
-// raylib [raymath] module functions - Quaternion math
-//----------------------------------------------------------------------------------
-int lua_QuaternionLength(lua_State* L)
-{
- Quaternion arg1 = LuaGetArgument_Quaternion(L, 1);
- float result = QuaternionLength(arg1);
- lua_pushnumber(L, result);
- return 1;
-}
-
-int lua_QuaternionNormalize(lua_State* L)
-{
- Quaternion arg1 = LuaGetArgument_Quaternion(L, 1);
- QuaternionNormalize(&arg1);
- LuaPush_Quaternion(L, arg1);
- return 1;
-}
-
-int lua_QuaternionMultiply(lua_State* L)
-{
- Quaternion arg1 = LuaGetArgument_Quaternion(L, 1);
- Quaternion arg2 = LuaGetArgument_Quaternion(L, 2);
- Quaternion result = QuaternionMultiply(arg1, arg2);
- LuaPush_Quaternion(L, result);
- return 1;
-}
-
-int lua_QuaternionSlerp(lua_State* L)
-{
- Quaternion arg1 = LuaGetArgument_Quaternion(L, 1);
- Quaternion arg2 = LuaGetArgument_Quaternion(L, 2);
- float arg3 = LuaGetArgument_float(L, 3);
- Quaternion result = QuaternionSlerp(arg1, arg2, arg3);
- LuaPush_Quaternion(L, result);
- return 1;
-}
-
-int lua_QuaternionFromMatrix(lua_State* L)
-{
- Matrix arg1 = LuaGetArgument_Matrix(L, 1);
- Quaternion result = QuaternionFromMatrix(arg1);
- LuaPush_Quaternion(L, result);
- return 1;
-}
-
-int lua_QuaternionToMatrix(lua_State* L)
-{
- Quaternion arg1 = LuaGetArgument_Quaternion(L, 1);
- Matrix result = QuaternionToMatrix(arg1);
- LuaPush_Matrix(L, &result);
- return 1;
-}
-
-int lua_QuaternionFromAxisAngle(lua_State* L)
-{
- Vector3 arg1 = LuaGetArgument_Vector3(L, 1);
- float arg2 = LuaGetArgument_float(L, 2);
- Quaternion result = QuaternionFromAxisAngle(arg1, arg2);
- LuaPush_Quaternion(L, result);
- return 1;
-}
-
-int lua_QuaternionToAxisAngle(lua_State* L)
-{
- Quaternion arg1 = LuaGetArgument_Quaternion(L, 1);
- Vector3 arg2;
- float arg3 = 0;
- QuaternionToAxisAngle(arg1, &arg2, &arg3);
- LuaPush_Vector3(L, arg2);
- lua_pushnumber(L, arg3);
- return 2;
-}
-
-int lua_QuaternionTransform(lua_State* L)
-{
- Quaternion arg1 = LuaGetArgument_Quaternion(L, 1);
- Matrix arg2 = LuaGetArgument_Matrix(L, 2);
- QuaternionTransform(&arg1, arg2);
- LuaPush_Quaternion(L, arg1);
- return 1;
-}
-
-
-//----------------------------------------------------------------------------------
-// Functions Registering
-//----------------------------------------------------------------------------------
-#define REG(name) { #name, lua_##name },
-
-// raylib Functions (and data types) list
-static luaL_Reg raylib_functions[] = {
-
- // Register non-opaque data types
- REG(Color)
- REG(Vector2)
- REG(Vector3)
- //REG(Matrix)
- REG(Quaternion)
- REG(Rectangle)
- REG(Ray)
- REG(Camera)
- REG(Camera2D)
- REG(BoundingBox)
- //REG(Material)
-
- // Register functions
- REG(InitWindow)
- REG(CloseWindow)
- REG(WindowShouldClose)
- REG(IsWindowMinimized)
- REG(ToggleFullscreen)
- REG(GetScreenWidth)
- REG(GetScreenHeight)
-
- REG(ShowCursor)
- REG(HideCursor)
- REG(IsCursorHidden)
- REG(EnableCursor)
- REG(DisableCursor)
-
- REG(ClearBackground)
- REG(BeginDrawing)
- REG(EndDrawing)
- REG(Begin2dMode)
- REG(End2dMode)
- REG(Begin3dMode)
- REG(End3dMode)
- REG(BeginTextureMode)
- REG(EndTextureMode)
-
- REG(GetMouseRay)
- REG(GetWorldToScreen)
- REG(GetCameraMatrix)
-
-#if defined(PLATFORM_WEB)
- REG(SetDrawingLoop)
-#else
- REG(SetTargetFPS)
-#endif
- REG(GetFPS)
- REG(GetFrameTime)
-
- REG(GetColor)
- REG(GetHexValue)
- REG(ColorToFloat)
- REG(VectorToFloat)
- REG(MatrixToFloat)
- REG(GetRandomValue)
- REG(Fade)
- REG(SetConfigFlags)
- REG(ShowLogo)
-
- REG(IsFileDropped)
- REG(GetDroppedFiles)
- REG(ClearDroppedFiles)
- REG(StorageSaveValue)
- REG(StorageLoadValue)
-
- REG(IsKeyPressed)
- REG(IsKeyDown)
- REG(IsKeyReleased)
- REG(IsKeyUp)
- REG(GetKeyPressed)
- REG(SetExitKey)
-
- REG(IsGamepadAvailable)
- REG(IsGamepadName)
- REG(GetGamepadName)
- REG(IsGamepadButtonPressed)
- REG(IsGamepadButtonDown)
- REG(IsGamepadButtonReleased)
- REG(IsGamepadButtonUp)
- REG(GetGamepadButtonPressed)
- REG(GetGamepadAxisCount)
- REG(GetGamepadAxisMovement)
-
- REG(IsMouseButtonPressed)
- REG(IsMouseButtonDown)
- REG(IsMouseButtonReleased)
- REG(IsMouseButtonUp)
- REG(GetMouseX)
- REG(GetMouseY)
- REG(GetMousePosition)
- REG(SetMousePosition)
- REG(GetMouseWheelMove)
- REG(GetTouchX)
- REG(GetTouchY)
- REG(GetTouchPosition)
-
-#if defined(PLATFORM_ANDROID)
- REG(IsButtonPressed)
- REG(IsButtonDown)
- REG(IsButtonReleased)
-#endif
-
- REG(SetGesturesEnabled)
- REG(IsGestureDetected)
- REG(GetGestureDetected)
- REG(GetTouchPointsCount)
- REG(GetGestureHoldDuration)
- REG(GetGestureDragVector)
- REG(GetGestureDragAngle)
- REG(GetGesturePinchVector)
- REG(GetGesturePinchAngle)
-
- REG(SetCameraMode)
- REG(UpdateCamera)
- REG(SetCameraPanControl)
- REG(SetCameraAltControl)
- REG(SetCameraSmoothZoomControl)
- REG(SetCameraMoveControls)
-
- REG(DrawPixel)
- REG(DrawPixelV)
- REG(DrawLine)
- REG(DrawLineV)
- REG(DrawCircle)
- REG(DrawCircleGradient)
- REG(DrawCircleV)
- REG(DrawCircleLines)
- REG(DrawRectangle)
- REG(DrawRectangleRec)
- REG(DrawRectangleGradient)
- REG(DrawRectangleV)
- REG(DrawRectangleLines)
- REG(DrawTriangle)
- REG(DrawTriangleLines)
- REG(DrawPoly)
- REG(DrawPolyEx)
- REG(DrawPolyExLines)
-
- REG(CheckCollisionRecs)
- REG(CheckCollisionCircles)
- REG(CheckCollisionCircleRec)
- REG(GetCollisionRec)
- REG(CheckCollisionPointRec)
- REG(CheckCollisionPointCircle)
- REG(CheckCollisionPointTriangle)
-
- REG(LoadImage)
- REG(LoadImageEx)
- REG(LoadImageRaw)
- REG(LoadImageFromRES)
- REG(LoadTexture)
- REG(LoadTextureEx)
- REG(LoadTextureFromRES)
- REG(LoadTextureFromImage)
- REG(LoadRenderTexture)
- REG(UnloadImage)
- REG(UnloadTexture)
- REG(UnloadRenderTexture)
- REG(GetImageData)
- REG(GetTextureData)
- REG(UpdateTexture)
- REG(ImageToPOT)
- REG(ImageFormat)
- REG(ImageDither)
- REG(ImageCopy)
- REG(ImageCrop)
- REG(ImageResize)
- REG(ImageResizeNN)
- REG(ImageText)
- REG(ImageTextEx)
- REG(ImageDraw)
- REG(ImageDrawText)
- REG(ImageDrawTextEx)
- REG(ImageFlipVertical)
- REG(ImageFlipHorizontal)
- REG(ImageColorTint)
- REG(ImageColorInvert)
- REG(ImageColorGrayscale)
- REG(ImageColorContrast)
- REG(ImageColorBrightness)
- REG(GenTextureMipmaps)
- REG(SetTextureFilter)
- REG(SetTextureWrap)
-
- REG(DrawTexture)
- REG(DrawTextureV)
- REG(DrawTextureEx)
- REG(DrawTextureRec)
- REG(DrawTexturePro)
-
- REG(GetDefaultFont)
- REG(LoadSpriteFont)
- REG(LoadSpriteFontTTF)
- REG(UnloadSpriteFont)
- REG(DrawText)
- REG(DrawTextEx)
- REG(MeasureText)
- REG(MeasureTextEx)
- REG(DrawFPS)
-
- REG(DrawLine3D)
- REG(DrawCircle3D)
- REG(DrawCube)
- REG(DrawCubeV)
- REG(DrawCubeWires)
- REG(DrawCubeTexture)
- REG(DrawSphere)
- REG(DrawSphereEx)
- REG(DrawSphereWires)
- REG(DrawCylinder)
- REG(DrawCylinderWires)
- REG(DrawPlane)
- REG(DrawRay)
- REG(DrawGrid)
- REG(DrawGizmo)
- REG(DrawLight)
-
- REG(LoadModel)
- REG(LoadModelEx)
- REG(LoadModelFromRES)
- REG(LoadHeightmap)
- REG(LoadCubicmap)
- REG(UnloadModel)
- REG(LoadMaterial)
- REG(LoadDefaultMaterial)
- REG(LoadStandardMaterial)
- REG(UnloadMaterial)
- //REG(GenMesh*) // Not ready yet...
-
- REG(DrawModel)
- REG(DrawModelEx)
- REG(DrawModelWires)
- REG(DrawModelWiresEx)
- REG(DrawBillboard)
- REG(DrawBillboardRec)
- REG(CalculateBoundingBox)
- REG(CheckCollisionSpheres)
- REG(CheckCollisionBoxes)
- REG(CheckCollisionBoxSphere)
- REG(CheckCollisionRaySphere)
- REG(CheckCollisionRaySphereEx)
- REG(CheckCollisionRayBox)
-
- REG(LoadShader)
- REG(UnloadShader)
- REG(GetDefaultShader)
- REG(GetStandardShader)
- REG(GetDefaultTexture)
- REG(GetShaderLocation)
- REG(SetShaderValue)
- REG(SetShaderValuei)
- REG(SetShaderValueMatrix)
- REG(SetMatrixProjection)
- REG(SetMatrixModelview)
- REG(BeginShaderMode)
- REG(EndShaderMode)
- REG(BeginBlendMode)
- REG(EndBlendMode)
- REG(CreateLight)
- REG(DestroyLight)
-
- REG(InitVrDevice)
- REG(CloseVrDevice)
- REG(IsVrDeviceReady)
- REG(IsVrSimulator)
- REG(UpdateVrTracking)
- REG(ToggleVrMode)
-
- REG(InitAudioDevice)
- REG(CloseAudioDevice)
- REG(IsAudioDeviceReady)
- REG(LoadWave)
- REG(LoadWaveEx)
- REG(LoadSound)
- REG(LoadSoundFromWave)
- REG(LoadSoundFromRES)
- REG(UpdateSound)
- REG(UnloadWave)
- REG(UnloadSound)
- REG(PlaySound)
- REG(PauseSound)
- REG(ResumeSound)
- REG(StopSound)
- REG(IsSoundPlaying)
- REG(SetSoundVolume)
- REG(SetSoundPitch)
- REG(WaveFormat)
- REG(WaveCopy)
- REG(WaveCrop)
- REG(GetWaveData)
-
- REG(LoadMusicStream)
- REG(UnloadMusicStream)
- REG(UpdateMusicStream)
- REG(PlayMusicStream)
- REG(StopMusicStream)
- REG(PauseMusicStream)
- REG(ResumeMusicStream)
- REG(IsMusicPlaying)
- REG(SetMusicVolume)
- REG(SetMusicPitch)
- REG(GetMusicTimeLength)
- REG(GetMusicTimePlayed)
-
- REG(InitAudioStream)
- REG(UpdateAudioStream)
- REG(CloseAudioStream)
- REG(IsAudioBufferProcessed)
- REG(PlayAudioStream)
- REG(PauseAudioStream)
- REG(ResumeAudioStream)
- REG(StopAudioStream)
-
- /// Math and util
- REG(DecompressData)
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
- REG(WriteBitmap)
- REG(WritePNG)
-#endif
- REG(TraceLog)
- REG(GetExtension)
- REG(GetNextPOT)
- REG(VectorAdd)
- REG(VectorSubtract)
- REG(VectorCrossProduct)
- REG(VectorPerpendicular)
- REG(VectorDotProduct)
- REG(VectorLength)
- REG(VectorScale)
- REG(VectorNegate)
- REG(VectorNormalize)
- REG(VectorDistance)
- REG(VectorLerp)
- REG(VectorReflect)
- REG(VectorTransform)
- REG(VectorZero)
- REG(MatrixDeterminant)
- REG(MatrixTrace)
- REG(MatrixTranspose)
- REG(MatrixInvert)
- REG(MatrixNormalize)
- REG(MatrixIdentity)
- REG(MatrixAdd)
- REG(MatrixSubstract)
- REG(MatrixTranslate)
- REG(MatrixRotate)
- REG(MatrixRotateX)
- REG(MatrixRotateY)
- REG(MatrixRotateZ)
- REG(MatrixScale)
- REG(MatrixMultiply)
- REG(MatrixFrustum)
- REG(MatrixPerspective)
- REG(MatrixOrtho)
- REG(MatrixLookAt)
- REG(QuaternionLength)
- REG(QuaternionNormalize)
- REG(QuaternionMultiply)
- REG(QuaternionSlerp)
- REG(QuaternionFromMatrix)
- REG(QuaternionToMatrix)
- REG(QuaternionFromAxisAngle)
- REG(QuaternionToAxisAngle)
- REG(QuaternionTransform)
-
- {NULL, NULL} // sentinel: end signal
-};
-
-// Register raylib functionality
-static void LuaRegisterRayLib(const char *opt_table)
-{
- if (opt_table) lua_createtable(L, 0, sizeof(raylib_functions)/sizeof(raylib_functions[0]));
- else lua_pushglobaltable(L);
-
- luaL_setfuncs(L, raylib_functions, 0);
-}
-
-//----------------------------------------------------------------------------------
-// raylib Lua API
-//----------------------------------------------------------------------------------
-
-// Initialize Lua system
-RLUADEF void InitLuaDevice(void)
-{
- mainLuaState = luaL_newstate();
- L = mainLuaState;
-
- LuaStartEnum();
- LuaSetEnum("FULLSCREEN_MODE", 1);
- LuaSetEnum("SHOW_LOGO", 2);
- LuaSetEnum("SHOW_MOUSE_CURSOR", 4);
- LuaSetEnum("CENTERED_MODE", 8);
- LuaSetEnum("MSAA_4X_HINT", 16);
- LuaSetEnum("VSYNC_HINT", 32);
- LuaEndEnum("FLAG");
-
- LuaStartEnum();
- LuaSetEnum("SPACE", 32);
- LuaSetEnum("ESCAPE", 256);
- LuaSetEnum("ENTER", 257);
- LuaSetEnum("BACKSPACE", 259);
- LuaSetEnum("RIGHT", 262);
- LuaSetEnum("LEFT", 263);
- LuaSetEnum("DOWN", 264);
- LuaSetEnum("UP", 265);
- LuaSetEnum("F1", 290);
- LuaSetEnum("F2", 291);
- LuaSetEnum("F3", 292);
- LuaSetEnum("F4", 293);
- LuaSetEnum("F5", 294);
- LuaSetEnum("F6", 295);
- LuaSetEnum("F7", 296);
- LuaSetEnum("F8", 297);
- LuaSetEnum("F9", 298);
- LuaSetEnum("F10", 299);
- LuaSetEnum("LEFT_SHIFT", 340);
- LuaSetEnum("LEFT_CONTROL", 341);
- LuaSetEnum("LEFT_ALT", 342);
- LuaSetEnum("RIGHT_SHIFT", 344);
- LuaSetEnum("RIGHT_CONTROL", 345);
- LuaSetEnum("RIGHT_ALT", 346);
- LuaSetEnum("ZERO", 48);
- LuaSetEnum("ONE", 49);
- LuaSetEnum("TWO", 50);
- LuaSetEnum("THREE", 51);
- LuaSetEnum("FOUR", 52);
- LuaSetEnum("FIVE", 53);
- LuaSetEnum("SIX", 54);
- LuaSetEnum("SEVEN", 55);
- LuaSetEnum("EIGHT", 56);
- LuaSetEnum("NINE", 57);
- LuaSetEnum("A", 65);
- LuaSetEnum("B", 66);
- LuaSetEnum("C", 67);
- LuaSetEnum("D", 68);
- LuaSetEnum("E", 69);
- LuaSetEnum("F", 70);
- LuaSetEnum("G", 71);
- LuaSetEnum("H", 72);
- LuaSetEnum("I", 73);
- LuaSetEnum("J", 74);
- LuaSetEnum("K", 75);
- LuaSetEnum("L", 76);
- LuaSetEnum("M", 77);
- LuaSetEnum("N", 78);
- LuaSetEnum("O", 79);
- LuaSetEnum("P", 80);
- LuaSetEnum("Q", 81);
- LuaSetEnum("R", 82);
- LuaSetEnum("S", 83);
- LuaSetEnum("T", 84);
- LuaSetEnum("U", 85);
- LuaSetEnum("V", 86);
- LuaSetEnum("W", 87);
- LuaSetEnum("X", 88);
- LuaSetEnum("Y", 89);
- LuaSetEnum("Z", 90);
- LuaEndEnum("KEY");
-
- LuaStartEnum();
- LuaSetEnum("LEFT_BUTTON", 0);
- LuaSetEnum("RIGHT_BUTTON", 1);
- LuaSetEnum("MIDDLE_BUTTON", 2);
- LuaEndEnum("MOUSE");
-
- LuaStartEnum();
- LuaSetEnum("PLAYER1", 0);
- LuaSetEnum("PLAYER2", 1);
- LuaSetEnum("PLAYER3", 2);
- LuaSetEnum("PLAYER4", 3);
-
- LuaSetEnum("PS3_BUTTON_A", 2);
- LuaSetEnum("PS3_BUTTON_B", 1);
- LuaSetEnum("PS3_BUTTON_X", 3);
- LuaSetEnum("PS3_BUTTON_Y", 4);
- LuaSetEnum("PS3_BUTTON_R1", 7);
- LuaSetEnum("PS3_BUTTON_R2", 5);
- LuaSetEnum("PS3_BUTTON_L1", 6);
- LuaSetEnum("PS3_BUTTON_L2", 8);
- LuaSetEnum("PS3_BUTTON_SELECT", 9);
- LuaSetEnum("PS3_BUTTON_START", 10);
-
- LuaSetEnum("XBOX_BUTTON_A", 0);
- LuaSetEnum("XBOX_BUTTON_B", 1);
- LuaSetEnum("XBOX_BUTTON_X", 2);
- LuaSetEnum("XBOX_BUTTON_Y", 3);
- LuaSetEnum("XBOX_BUTTON_LB", 4);
- LuaSetEnum("XBOX_BUTTON_RB", 5);
- LuaSetEnum("XBOX_BUTTON_SELECT", 6);
- LuaSetEnum("XBOX_BUTTON_START", 7);
-
-#if defined(PLATFORM_RPI)
- LuaSetEnum("XBOX_AXIS_DPAD_X", 7);
- LuaSetEnum("XBOX_AXIS_DPAD_Y", 6);
- LuaSetEnum("XBOX_AXIS_RIGHT_X", 3);
- LuaSetEnum("XBOX_AXIS_RIGHT_Y", 4);
- LuaSetEnum("XBOX_AXIS_LT", 2);
- LuaSetEnum("XBOX_AXIS_RT", 5);
-#else
- LuaSetEnum("XBOX_BUTTON_UP", 10);
- LuaSetEnum("XBOX_BUTTON_DOWN", 12);
- LuaSetEnum("XBOX_BUTTON_LEFT", 13);
- LuaSetEnum("XBOX_BUTTON_RIGHT", 11);
- LuaSetEnum("XBOX_AXIS_RIGHT_X", 4);
- LuaSetEnum("XBOX_AXIS_RIGHT_Y", 3);
- LuaSetEnum("XBOX_AXIS_LT_RT", 2);
-#endif
- LuaSetEnum("XBOX_AXIS_LEFT_X", 0);
- LuaSetEnum("XBOX_AXIS_LEFT_Y", 1);
- LuaEndEnum("GAMEPAD");
-
- lua_pushglobaltable(L);
- LuaSetEnumColor("LIGHTGRAY", LIGHTGRAY);
- LuaSetEnumColor("GRAY", GRAY);
- LuaSetEnumColor("DARKGRAY", DARKGRAY);
- LuaSetEnumColor("YELLOW", YELLOW);
- LuaSetEnumColor("GOLD", GOLD);
- LuaSetEnumColor("ORANGE", ORANGE);
- LuaSetEnumColor("PINK", PINK);
- LuaSetEnumColor("RED", RED);
- LuaSetEnumColor("MAROON", MAROON);
- LuaSetEnumColor("GREEN", GREEN);
- LuaSetEnumColor("LIME", LIME);
- LuaSetEnumColor("DARKGREEN", DARKGREEN);
- LuaSetEnumColor("SKYBLUE", SKYBLUE);
- LuaSetEnumColor("BLUE", BLUE);
- LuaSetEnumColor("DARKBLUE", DARKBLUE);
- LuaSetEnumColor("PURPLE", PURPLE);
- LuaSetEnumColor("VIOLET", VIOLET);
- LuaSetEnumColor("DARKPURPLE", DARKPURPLE);
- LuaSetEnumColor("BEIGE", BEIGE);
- LuaSetEnumColor("BROWN", BROWN);
- LuaSetEnumColor("DARKBROWN", DARKBROWN);
- LuaSetEnumColor("WHITE", WHITE);
- LuaSetEnumColor("BLACK", BLACK);
- LuaSetEnumColor("BLANK", BLANK);
- LuaSetEnumColor("MAGENTA", MAGENTA);
- LuaSetEnumColor("RAYWHITE", RAYWHITE);
- lua_pop(L, 1);
-
- LuaStartEnum();
- LuaSetEnum("UNCOMPRESSED_GRAYSCALE", UNCOMPRESSED_GRAYSCALE);
- LuaSetEnum("UNCOMPRESSED_GRAY_ALPHA", UNCOMPRESSED_GRAY_ALPHA);
- LuaSetEnum("UNCOMPRESSED_R5G6B5", UNCOMPRESSED_R5G6B5);
- LuaSetEnum("UNCOMPRESSED_R8G8B8", UNCOMPRESSED_R8G8B8);
- LuaSetEnum("UNCOMPRESSED_R5G5B5A1", UNCOMPRESSED_R5G5B5A1);
- LuaSetEnum("UNCOMPRESSED_R4G4B4A4", UNCOMPRESSED_R4G4B4A4);
- LuaSetEnum("UNCOMPRESSED_R8G8B8A8", UNCOMPRESSED_R8G8B8A8);
- LuaSetEnum("COMPRESSED_DXT1_RGB", COMPRESSED_DXT1_RGB);
- LuaSetEnum("COMPRESSED_DXT1_RGBA", COMPRESSED_DXT1_RGBA);
- LuaSetEnum("COMPRESSED_DXT3_RGBA", COMPRESSED_DXT3_RGBA);
- LuaSetEnum("COMPRESSED_DXT5_RGBA", COMPRESSED_DXT5_RGBA);
- LuaSetEnum("COMPRESSED_ETC1_RGB", COMPRESSED_ETC1_RGB);
- LuaSetEnum("COMPRESSED_ETC2_RGB", COMPRESSED_ETC2_RGB);
- LuaSetEnum("COMPRESSED_ETC2_EAC_RGBA", COMPRESSED_ETC2_EAC_RGBA);
- LuaSetEnum("COMPRESSED_PVRT_RGB", COMPRESSED_PVRT_RGB);
- LuaSetEnum("COMPRESSED_PVRT_RGBA", COMPRESSED_PVRT_RGBA);
- LuaSetEnum("COMPRESSED_ASTC_4x4_RGBA", COMPRESSED_ASTC_4x4_RGBA);
- LuaSetEnum("COMPRESSED_ASTC_8x8_RGBA", COMPRESSED_ASTC_8x8_RGBA);
- LuaEndEnum("TextureFormat");
-
- LuaStartEnum();
- LuaSetEnum("ALPHA", BLEND_ALPHA);
- LuaSetEnum("ADDITIVE", BLEND_ADDITIVE);
- LuaSetEnum("MULTIPLIED", BLEND_MULTIPLIED);
- LuaEndEnum("BlendMode");
-
- LuaStartEnum();
- LuaSetEnum("POINT", LIGHT_POINT);
- LuaSetEnum("DIRECTIONAL", LIGHT_DIRECTIONAL);
- LuaSetEnum("SPOT", LIGHT_SPOT);
- LuaEndEnum("LightType");
-
- LuaStartEnum();
- LuaSetEnum("NONE", GESTURE_NONE);
- LuaSetEnum("TAP", GESTURE_TAP);
- LuaSetEnum("DOUBLETAP", GESTURE_DOUBLETAP);
- LuaSetEnum("HOLD", GESTURE_HOLD);
- LuaSetEnum("DRAG", GESTURE_DRAG);
- LuaSetEnum("SWIPE_RIGHT", GESTURE_SWIPE_RIGHT);
- LuaSetEnum("SWIPE_LEFT", GESTURE_SWIPE_LEFT);
- LuaSetEnum("SWIPE_UP", GESTURE_SWIPE_UP);
- LuaSetEnum("SWIPE_DOWN", GESTURE_SWIPE_DOWN);
- LuaSetEnum("PINCH_IN", GESTURE_PINCH_IN);
- LuaSetEnum("PINCH_OUT", GESTURE_PINCH_OUT);
- LuaEndEnum("Gestures");
-
- LuaStartEnum();
- LuaSetEnum("CUSTOM", CAMERA_CUSTOM);
- LuaSetEnum("FREE", CAMERA_FREE);
- LuaSetEnum("ORBITAL", CAMERA_ORBITAL);
- LuaSetEnum("FIRST_PERSON", CAMERA_FIRST_PERSON);
- LuaSetEnum("THIRD_PERSON", CAMERA_THIRD_PERSON);
- LuaEndEnum("CameraMode");
-
- LuaStartEnum();
- LuaSetEnum("DEFAULT_DEVICE", HMD_DEFAULT_DEVICE);
- LuaSetEnum("OCULUS_RIFT_DK2", HMD_OCULUS_RIFT_DK2);
- LuaSetEnum("OCULUS_RIFT_CV1", HMD_OCULUS_RIFT_CV1);
- LuaSetEnum("VALVE_HTC_VIVE", HMD_VALVE_HTC_VIVE);
- LuaSetEnum("SAMSUNG_GEAR_VR", HMD_SAMSUNG_GEAR_VR);
- LuaSetEnum("GOOGLE_CARDBOARD", HMD_GOOGLE_CARDBOARD);
- LuaSetEnum("SONY_PLAYSTATION_VR", HMD_SONY_PLAYSTATION_VR);
- LuaSetEnum("RAZER_OSVR", HMD_RAZER_OSVR);
- LuaSetEnum("FOVE_VR", HMD_FOVE_VR);
- LuaEndEnum("VrDevice");
-
- lua_pushglobaltable(L);
- LuaSetEnum("INFO", INFO);
- LuaSetEnum("ERROR", ERROR);
- LuaSetEnum("WARNING", WARNING);
- LuaSetEnum("DEBUG", DEBUG);
- LuaSetEnum("OTHER", OTHER);
- lua_pop(L, 1);
-
- lua_pushboolean(L, true);
-#if defined(PLATFORM_DESKTOP)
- lua_setglobal(L, "PLATFORM_DESKTOP");
-#elif defined(PLATFORM_ANDROID)
- lua_setglobal(L, "PLATFORM_ANDROID");
-#elif defined(PLATFORM_RPI)
- lua_setglobal(L, "PLATFORM_RPI");
-#elif defined(PLATFORM_WEB)
- lua_setglobal(L, "PLATFORM_WEB");
-#endif
-
- luaL_openlibs(L);
- LuaBuildOpaqueMetatables();
-
- LuaRegisterRayLib(0);
-}
-
-// De-initialize Lua system
-RLUADEF void CloseLuaDevice(void)
-{
- if (mainLuaState)
- {
- lua_close(mainLuaState);
- mainLuaState = 0;
- L = 0;
- }
-}
-
-// Execute raylib Lua code
-RLUADEF void ExecuteLuaCode(const char *code)
-{
- if (!mainLuaState)
- {
- TraceLog(WARNING, "Lua device not initialized");
- return;
- }
-
- int result = luaL_dostring(L, code);
-
- switch (result)
- {
- case LUA_OK: break;
- case LUA_ERRRUN: TraceLog(ERROR, "Lua Runtime Error: %s", lua_tostring(L, -1)); break;
- case LUA_ERRMEM: TraceLog(ERROR, "Lua Memory Error: %s", lua_tostring(L, -1)); break;
- default: TraceLog(ERROR, "Lua Error: %s", lua_tostring(L, -1)); break;
- }
-}
-
-// Execute raylib Lua script
-RLUADEF void ExecuteLuaFile(const char *filename)
-{
- if (!mainLuaState)
- {
- TraceLog(WARNING, "Lua device not initialized");
- return;
- }
-
- int result = luaL_dofile(L, filename);
-
- switch (result)
- {
- case LUA_OK: break;
- case LUA_ERRRUN: TraceLog(ERROR, "Lua Runtime Error: %s", lua_tostring(L, -1));
- case LUA_ERRMEM: TraceLog(ERROR, "Lua Memory Error: %s", lua_tostring(L, -1));
- default: TraceLog(ERROR, "Lua Error: %s", lua_tostring(L, -1));
- }
-}
-
-#endif // RLUA_IMPLEMENTATION
diff --git a/src/rres.h b/src/rres.h
new file mode 100644
index 00000000..362da10d
--- /dev/null
+++ b/src/rres.h
@@ -0,0 +1,439 @@
+/**********************************************************************************************
+*
+* rres - raylib Resource custom format management functions
+*
+* Basic functions to load/save rRES resource files
+*
+* CONFIGURATION:
+*
+* #define RREM_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.
+*
+* DEPENDENCIES:
+* tinfl - DEFLATE decompression functions
+*
+*
+* LICENSE: zlib/libpng
+*
+* 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 RRESData {
+ 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;
+
+ // RRESData type
+ 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_CHARDATA, // Character { int value, recX, recY, recWidth, recHeight, offsetX, offsetY, xAdvance }
+ RRES_TYPE_DIRECTORY
+ } RRESDataType;
+
+ // RRES type (pointer to RRESData array)
+ typedef struct RRESData *RRES;
+#endif
+
+//----------------------------------------------------------------------------------
+// Global variables
+//----------------------------------------------------------------------------------
+//...
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+//RRESDEF RRESData LoadResourceData(const char *rresFileName, int rresId, int part);
+RRESDEF RRES LoadResource(const char *fileName, int rresId);
+RRESDEF void UnloadResource(RRES 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 by id (could be multiple parts)
+// NOTE: Returns uncompressed data with parameters, search resource by id
+RRESDEF RRES LoadResource(const char *fileName, int rresId)
+{
+ RRES 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);
+
+ rres = (RRES)malloc(sizeof(RRESData)*infoHeader.partsCount);
+
+ if (infoHeader.id == rresId)
+ {
+ // Load all required resources parts
+ for (int k = 0; k < infoHeader.partsCount; k++)
+ {
+ // TODO: Verify again that rresId is the same in every part
+
+ // Register data type and parameters
+ rres[k].type = infoHeader.dataType;
+ rres[k].param1 = infoHeader.param1;
+ rres[k].param2 = infoHeader.param2;
+ rres[k].param3 = infoHeader.param3;
+ rres[k].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[k].data = uncompData;
+
+ RRES_FREE(data);
+ }
+ else rres[k].data = data;
+
+ if (rres[k].data != NULL) TraceLog(INFO, "[%s][ID %i] Resource data loaded successfully", fileName, (int)infoHeader.id);
+
+ // Read next part
+ fread(&infoHeader, sizeof(RRESInfoHeader), 1, rresFile);
+ }
+ }
+ else
+ {
+ // Skip required data to read next resource infoHeader
+ fseek(rresFile, infoHeader.dataSize, SEEK_CUR);
+ }
+ }
+
+ if (rres[0].data == NULL) TraceLog(WARNING, "[%s][ID %i] Requested resource could not be found", fileName, (int)rresId);
+ }
+
+ fclose(rresFile);
+ }
+
+ return rres;
+}
+
+RRESDEF void UnloadResource(RRES rres)
+{
+ if (rres[0].data != NULL) free(rres[0].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
+
+// RRES_TYPE_IMAGE params: imgWidth, imgHeight, format, mipmaps;
+// RRES_TYPE_WAVE params: sampleCount, sampleRate, sampleSize, channels;
+// RRES_TYPE_FONT_IMAGE params: imgWidth, imgHeight, format, mipmaps;
+// RRES_TYPE_FONT_DATA params: charsCount, baseSize
+// RRES_TYPE_VERTEX params: vertexCount, vertexType, vertexFormat // Use masks instead?
+// RRES_TYPE_TEXT params: charsCount, cultureCode
+// RRES_TYPE_DIRECTORY params: fileCount, directoryCount
+
+// SpriteFont = RRES_TYPE_FONT_IMAGE chunk + RRES_TYPE_FONT_DATA chunk
+// Mesh = multiple RRES_TYPE_VERTEX chunks
+
+Ref: RIFF file-format: http://www.johnloomis.org/cpe102/asgn/asgn1/riff.html
+
+*/ \ No newline at end of file
diff --git a/src/shader_standard.h b/src/shader_standard.h
deleted file mode 100644
index 995c62ea..00000000
--- a/src/shader_standard.h
+++ /dev/null
@@ -1,173 +0,0 @@
-
-// Vertex shader definition to embed, no external file required
-static const char vStandardShaderStr[] =
-#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 vec3 vertexNormal; \n"
-"attribute vec2 vertexTexCoord; \n"
-"attribute vec4 vertexColor; \n"
-"varying vec3 fragPosition; \n"
-"varying vec3 fragNormal; \n"
-"varying vec2 fragTexCoord; \n"
-"varying vec4 fragColor; \n"
-#elif defined(GRAPHICS_API_OPENGL_33)
-"#version 330 \n"
-"in vec3 vertexPosition; \n"
-"in vec3 vertexNormal; \n"
-"in vec2 vertexTexCoord; \n"
-"in vec4 vertexColor; \n"
-"out vec3 fragPosition; \n"
-"out vec3 fragNormal; \n"
-"out vec2 fragTexCoord; \n"
-"out vec4 fragColor; \n"
-#endif
-"uniform mat4 mvpMatrix; \n"
-"void main() \n"
-"{ \n"
-" fragPosition = vertexPosition; \n"
-" fragNormal = vertexNormal; \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 fStandardShaderStr[] =
-#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 vec3 fragPosition; \n"
-"varying vec3 fragNormal; \n"
-"varying vec2 fragTexCoord; \n"
-"varying vec4 fragColor; \n"
-#elif defined(GRAPHICS_API_OPENGL_33)
-"#version 330 \n"
-"in vec3 fragPosition; \n"
-"in vec3 fragNormal; \n"
-"in vec2 fragTexCoord; \n"
-"in vec4 fragColor; \n"
-"out vec4 finalColor; \n"
-#endif
-"uniform sampler2D texture0; \n"
-"uniform sampler2D texture1; \n"
-"uniform sampler2D texture2; \n"
-"uniform vec4 colAmbient; \n"
-"uniform vec4 colDiffuse; \n"
-"uniform vec4 colSpecular; \n"
-"uniform float glossiness; \n"
-"uniform int useNormal; \n"
-"uniform int useSpecular; \n"
-"uniform mat4 modelMatrix; \n"
-"uniform vec3 viewDir; \n"
-"struct Light { \n"
-" int enabled; \n"
-" int type; \n"
-" vec3 position; \n"
-" vec3 direction; \n"
-" vec4 diffuse; \n"
-" float intensity; \n"
-" float radius; \n"
-" float coneAngle; }; \n"
-"const int maxLights = 8; \n"
-"uniform Light lights[maxLights]; \n"
-"\n"
-"vec3 CalcPointLight(Light l, vec3 n, vec3 v, float s) \n"
-"{\n"
-" vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1));\n"
-" vec3 surfaceToLight = l.position - surfacePos;\n"
-" float brightness = clamp(float(dot(n, surfaceToLight)/(length(surfaceToLight)*length(n))), 0.0, 1.0);\n"
-" float diff = 1.0/dot(surfaceToLight/l.radius, surfaceToLight/l.radius)*brightness*l.intensity;\n"
-" float spec = 0.0;\n"
-" if (diff > 0.0)\n"
-" {\n"
-" vec3 h = normalize(-l.direction + v);\n"
-" spec = pow(abs(dot(n, h)), 3.0 + glossiness)*s;\n"
-" }\n"
-" return (diff*l.diffuse.rgb + spec*colSpecular.rgb);\n"
-"}\n"
-"\n"
-"vec3 CalcDirectionalLight(Light l, vec3 n, vec3 v, float s)\n"
-"{\n"
-" vec3 lightDir = normalize(-l.direction);\n"
-" float diff = clamp(float(dot(n, lightDir)), 0.0, 1.0)*l.intensity;\n"
-" float spec = 0.0;\n"
-" if (diff > 0.0)\n"
-" {\n"
-" vec3 h = normalize(lightDir + v);\n"
-" spec = pow(abs(dot(n, h)), 3.0 + glossiness)*s;\n"
-" }\n"
-" return (diff*l.intensity*l.diffuse.rgb + spec*colSpecular.rgb);\n"
-"}\n"
-"\n"
-"vec3 CalcSpotLight(Light l, vec3 n, vec3 v, float s)\n"
-"{\n"
-" vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1.0));\n"
-" vec3 lightToSurface = normalize(surfacePos - l.position);\n"
-" vec3 lightDir = normalize(-l.direction);\n"
-" float diff = clamp(float(dot(n, lightDir)), 0.0, 1.0)*l.intensity;\n"
-" float attenuation = clamp(float(dot(n, lightToSurface)), 0.0, 1.0);\n"
-" attenuation = dot(lightToSurface, -lightDir);\n"
-" float lightToSurfaceAngle = degrees(acos(attenuation));\n"
-" if (lightToSurfaceAngle > l.coneAngle) attenuation = 0.0;\n"
-" float falloff = (l.coneAngle - lightToSurfaceAngle)/l.coneAngle;\n"
-" float diffAttenuation = diff*attenuation;\n"
-" float spec = 0.0;\n"
-" if (diffAttenuation > 0.0)\n"
-" {\n"
-" vec3 h = normalize(lightDir + v);\n"
-" spec = pow(abs(dot(n, h)), 3.0 + glossiness)*s;\n"
-" }\n"
-" return (falloff*(diffAttenuation*l.diffuse.rgb + spec*colSpecular.rgb));\n"
-"}\n"
-"\n"
-"void main()\n"
-"{\n"
-" mat3 normalMatrix = mat3(modelMatrix);\n"
-" vec3 normal = normalize(normalMatrix*fragNormal);\n"
-" vec3 n = normalize(normal);\n"
-" vec3 v = normalize(viewDir);\n"
-#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
-" vec4 texelColor = texture2D(texture0, fragTexCoord);\n"
-#elif defined(GRAPHICS_API_OPENGL_33)
-" vec4 texelColor = texture(texture0, fragTexCoord);\n"
-#endif
-" vec3 lighting = colAmbient.rgb;\n"
-" if (useNormal == 1)\n"
-" {\n"
-#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
-" n *= texture2D(texture1, fragTexCoord).rgb;\n"
-#elif defined(GRAPHICS_API_OPENGL_33)
-" n *= texture(texture1, fragTexCoord).rgb;\n"
-#endif
-" n = normalize(n);\n"
-" }\n"
-" float spec = 1.0;\n"
-#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
-" if (useSpecular == 1) spec = texture2D(texture2, fragTexCoord).r;\n"
-#elif defined(GRAPHICS_API_OPENGL_33)
-" if (useSpecular == 1) spec = texture(texture2, fragTexCoord).r;\n"
-#endif
-" for (int i = 0; i < maxLights; i++)\n"
-" {\n"
-" if (lights[i].enabled == 1)\n"
-" {\n"
-" if(lights[i].type == 0) lighting += CalcPointLight(lights[i], n, v, spec);\n"
-" else if(lights[i].type == 1) lighting += CalcDirectionalLight(lights[i], n, v, spec);\n"
-" else if(lights[i].type == 2) lighting += CalcSpotLight(lights[i], n, v, spec);\n"
-" }\n"
-" }\n"
-#if defined(GRAPHICS_API_OPENGL_ES2) || defined(GRAPHICS_API_OPENGL_21)
-" gl_FragColor = vec4(texelColor.rgb*lighting*colDiffuse.rgb, texelColor.a*colDiffuse.a); \n"
-#elif defined(GRAPHICS_API_OPENGL_33)
-" finalColor = vec4(texelColor.rgb*lighting*colDiffuse.rgb, texelColor.a*colDiffuse.a); \n"
-#endif
-"}\n";
diff --git a/src/shapes.c b/src/shapes.c
index 70aad59a..9cbe1da4 100644
--- a/src/shapes.c
+++ b/src/shapes.c
@@ -1,14 +1,17 @@
/**********************************************************************************************
*
-* raylib.shapes
+* raylib.shapes - Basic functions to draw 2d Shapes and check collisions
*
-* Basic functions to draw 2d Shapes and check collisions
+* CONFIGURATION:
*
-* External libs:
-* rlgl - raylib OpenGL abstraction layer
+* #define SUPPORT_QUADS_ONLY
+* Draw shapes using only QUADS, vertex are accumulated in QUADS arrays (like textures)
*
-* Module Configuration Flags:
-* ...
+* #define SUPPORT_TRIANGLES_ONLY
+* Draw shapes using only TRIANGLES, vertex are accumulated in TRIANGLES arrays
+*
+*
+* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
@@ -100,6 +103,36 @@ void DrawLineV(Vector2 startPos, Vector2 endPos, Color color)
rlEnd();
}
+// Draw a line defining thickness
+void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
+{
+ float dx = endPos.x - startPos.x;
+ float dy = endPos.y - startPos.y;
+
+ float d = sqrtf(dx*dx + dy*dy);
+ float angle = asinf(dy/d);
+
+ rlEnableTexture(GetDefaultTexture().id);
+
+ rlPushMatrix();
+ rlTranslatef((float)startPos.x, (float)startPos.y, 0);
+ rlRotatef(-RAD2DEG*angle, 0, 0, 1);
+ rlTranslatef(0, -thick/2.0f, 0);
+
+ rlBegin(RL_QUADS);
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlNormal3f(0.0f, 0.0f, 1.0f);
+
+ rlVertex2f(0.0f, 0.0f);
+ rlVertex2f(0.0f, thick);
+ rlVertex2f(d, thick);
+ rlVertex2f(d, 0.0f);
+ rlEnd();
+ rlPopMatrix();
+
+ rlDisableTexture();
+}
+
// Draw a color-filled circle
void DrawCircle(int centerX, int centerY, float radius, Color color)
{
@@ -190,6 +223,29 @@ void DrawRectangleRec(Rectangle rec, Color color)
DrawRectangle(rec.x, rec.y, rec.width, rec.height, color);
}
+void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color)
+{
+ rlEnableTexture(GetDefaultTexture().id);
+
+ rlPushMatrix();
+ rlTranslatef((float)rec.x, (float)rec.y, 0);
+ rlRotatef(rotation, 0, 0, 1);
+ rlTranslatef(-origin.x, -origin.y, 0);
+
+ rlBegin(RL_QUADS);
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer
+
+ rlVertex2f(0.0f, 0.0f);
+ rlVertex2f(0.0f, (float)rec.height);
+ rlVertex2f((float)rec.width, (float)rec.height);
+ rlVertex2f((float)rec.width, 0.0f);
+ rlEnd();
+ rlPopMatrix();
+
+ rlDisableTexture();
+}
+
// 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)
@@ -453,16 +509,17 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
int recCenterX = rec.x + rec.width/2;
int recCenterY = rec.y + rec.height/2;
- float dx = fabs(center.x - recCenterX);
- float dy = fabs(center.y - recCenterY);
+ float dx = fabsf(center.x - recCenterX);
+ float dy = fabsf(center.y - recCenterY);
- if (dx > (rec.width/2 + radius)) { return false; }
- if (dy > (rec.height/2 + radius)) { return false; }
+ if (dx > ((float)rec.width/2.0f + radius)) { return false; }
+ if (dy > ((float)rec.height/2.0f + radius)) { return false; }
- if (dx <= (rec.width/2)) { return true; }
- if (dy <= (rec.height/2)) { return true; }
+ if (dx <= ((float)rec.width/2.0f)) { return true; }
+ if (dy <= ((float)rec.height/2.0f)) { return true; }
- float cornerDistanceSq = (dx - rec.width/2)*(dx - rec.width/2) + (dy - rec.height/2)*(dy - rec.height/2);
+ 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));
}
@@ -532,4 +589,4 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
}
return retRec;
-} \ No newline at end of file
+}
diff --git a/src/text.c b/src/text.c
index c394889e..18ebf482 100644
--- a/src/text.c
+++ b/src/text.c
@@ -1,14 +1,22 @@
/**********************************************************************************************
*
-* raylib.text
+* raylib.text - Basic functions to load SpriteFonts and draw Text
*
-* Basic functions to load SpriteFonts and draw Text
+* CONFIGURATION:
*
-* External libs:
+* #define SUPPORT_FILEFORMAT_FNT
+* #define SUPPORT_FILEFORMAT_TTF / INCLUDE_STB_TRUETYPE
+* #define SUPPORT_FILEFORMAT_IMAGE_FONT
+* Selected desired fileformats to be supported for loading. Some of those formats are
+* supported by default, to remove support, just comment unrequired #define in this module
+*
+* #define INCLUDE_DEFAULT_FONT / SUPPORT_DEFAULT_FONT
+*
+* DEPENDENCIES:
* stb_truetype - Load TTF file and rasterize characters data
*
-* Module Configuration Flags:
-* ...
+*
+* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
@@ -36,7 +44,7 @@
#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(), GetNextPOT()
+#include "utils.h" // Required for: GetExtension()
// Following libs are used on LoadTTF()
#define STBTT_STATIC // Define stb_truetype functions static to this module
@@ -53,7 +61,7 @@
#define MAX_FORMATTEXT_LENGTH 64
#define MAX_SUBTEXT_LENGTH 64
-#define BIT_CHECK(a,b) ((a) & (1<<(b)))
+#define BIT_CHECK(a,b) ((a) & (1 << (b)))
//----------------------------------------------------------------------------------
// Types and Structures Definition
@@ -79,7 +87,7 @@ 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
+static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data
extern void LoadDefaultFont(void);
extern void UnloadDefaultFont(void);
@@ -92,7 +100,7 @@ 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
+ defaultFont.charsCount = 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
@@ -189,29 +197,27 @@ extern void LoadDefaultFont(void)
defaultFont.texture = LoadTextureFromImage(image);
UnloadImage(image);
- // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, numChars
+ // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, charsCount
//------------------------------------------------------------------------------
- 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));
+
+ // Allocate space for our characters info data
+ // NOTE: This memory should be freed at end! --> CloseWindow()
+ defaultFont.chars = (CharInfo *)malloc(defaultFont.charsCount*sizeof(CharInfo));
int currentLine = 0;
int currentPosX = charsDivisor;
int testPosX = charsDivisor;
- for (int i = 0; i < defaultFont.numChars; i++)
+ for (int i = 0; i < defaultFont.charsCount; i++)
{
- defaultFont.charValues[i] = 32 + i; // First char is 32
+ defaultFont.chars[i].value = 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;
+ defaultFont.chars[i].rec.x = currentPosX;
+ defaultFont.chars[i].rec.y = charsDivisor + currentLine*(charsHeight + charsDivisor);
+ defaultFont.chars[i].rec.width = charsWidth[i];
+ defaultFont.chars[i].rec.height = charsHeight;
- testPosX += (defaultFont.charRecs[i].width + charsDivisor);
+ testPosX += (defaultFont.chars[i].rec.width + charsDivisor);
if (testPosX >= defaultFont.texture.width)
{
@@ -219,17 +225,18 @@ extern void LoadDefaultFont(void)
currentPosX = 2*charsDivisor + charsWidth[i];
testPosX = currentPosX;
- defaultFont.charRecs[i].x = charsDivisor;
- defaultFont.charRecs[i].y = charsDivisor + currentLine*(charsHeight + charsDivisor);
+ defaultFont.chars[i].rec.x = charsDivisor;
+ defaultFont.chars[i].rec.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.chars[i].offsetX = 0;
+ defaultFont.chars[i].offsetY = 0;
+ defaultFont.chars[i].advanceX = 0;
}
- defaultFont.size = defaultFont.charRecs[0].height;
+ defaultFont.baseSize = defaultFont.chars[0].rec.height;
TraceLog(INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id);
}
@@ -237,10 +244,7 @@ extern void LoadDefaultFont(void)
extern void UnloadDefaultFont(void)
{
UnloadTexture(defaultFont.texture);
- free(defaultFont.charValues);
- free(defaultFont.charRecs);
- free(defaultFont.charOffsets);
- free(defaultFont.charAdvanceX);
+ free(defaultFont.chars);
}
// Get the default font, useful to be used with extended parameters
@@ -249,7 +253,7 @@ SpriteFont GetDefaultFont()
return defaultFont;
}
-// Load a SpriteFont image into GPU memory
+// Load SpriteFont from file into GPU memory (VRAM)
SpriteFont LoadSpriteFont(const char *fileName)
{
// Default hardcoded values for ttf file loading
@@ -260,9 +264,35 @@ SpriteFont LoadSpriteFont(const char *fileName)
SpriteFont spriteFont = { 0 };
// Check file extension
- if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName);
+ if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName); // TODO: DELETE... SOON...
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 if (strcmp(GetExtension(fileName),"rres") == 0)
+ {
+ // TODO: Read multiple resource blocks from file (RRES_FONT_IMAGE, RRES_FONT_CHARDATA)
+ RRES rres = LoadResource(fileName, 0);
+
+ // Load sprite font texture
+ if (rres[0].type == RRES_TYPE_FONT_IMAGE)
+ {
+ // NOTE: Parameters for RRES_FONT_IMAGE type are: width, height, format, mipmaps
+ Image image = LoadImagePro(rres[0].data, rres[0].param1, rres[0].param2, rres[0].param3);
+ spriteFont.texture = LoadTextureFromImage(image);
+ UnloadImage(image);
+ }
+
+ // Load sprite characters data
+ if (rres[1].type == RRES_TYPE_FONT_CHARDATA)
+ {
+ // NOTE: Parameters for RRES_FONT_CHARDATA type are: fontSize, charsCount
+ spriteFont.baseSize = rres[1].param1;
+ spriteFont.charsCount = rres[1].param2;
+ spriteFont.chars = rres[1].data;
+ }
+
+ // TODO: Do not free rres.data memory (chars info data!)
+ //UnloadResource(rres[0]);
+ }
else
{
Image image = LoadImage(fileName);
@@ -280,26 +310,26 @@ SpriteFont LoadSpriteFont(const char *fileName)
return spriteFont;
}
-// Load SpriteFont from TTF file with custom parameters
+// 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 LoadSpriteFontTTF(const char *fileName, int fontSize, int charsCount, int *fontChars)
{
SpriteFont spriteFont = { 0 };
-
- if (strcmp(GetExtension(fileName),"ttf") == 0)
+
+ if (strcmp(GetExtension(fileName),"ttf") == 0)
{
- if ((fontChars == NULL) || (numChars == 0))
+ if ((fontChars == NULL) || (charsCount == 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);
+ else spriteFont = LoadTTF(fileName, fontSize, charsCount, fontChars);
}
if (spriteFont.texture.id == 0)
@@ -311,17 +341,14 @@ SpriteFont LoadSpriteFontTTF(const char *fileName, int fontSize, int numChars, i
return spriteFont;
}
-// Unload SpriteFont from GPU memory
+// 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);
+ free(spriteFont.chars);
TraceLog(DEBUG, "Unloaded sprite font data");
}
@@ -353,11 +380,11 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float
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;
+
+ scaleFactor = fontSize/spriteFont.baseSize;
// NOTE: Some ugly hacks are made to support Latin-1 Extended characters directly
// written in C code files (codified by default as UTF-8)
@@ -367,7 +394,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float
if ((unsigned char)text[i] == '\n')
{
// NOTE: Fixed line spacing of 1.5 lines
- textOffsetY += ((spriteFont.size + spriteFont.size/2)*scaleFactor);
+ textOffsetY += (int)((spriteFont.baseSize + spriteFont.baseSize/2)*scaleFactor);
textOffsetX = 0;
}
else
@@ -388,14 +415,14 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float
}
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);
+ DrawTexturePro(spriteFont.texture, spriteFont.chars[index].rec,
+ (Rectangle){ position.x + textOffsetX + spriteFont.chars[index].offsetX*scaleFactor,
+ position.y + textOffsetY + spriteFont.chars[index].offsetY*scaleFactor,
+ spriteFont.chars[index].rec.width*scaleFactor,
+ spriteFont.chars[index].rec.height*scaleFactor }, (Vector2){ 0, 0 }, 0.0f, tint);
- if (spriteFont.charAdvanceX[index] == 0) textOffsetX += (spriteFont.charRecs[index].width*scaleFactor + spacing);
- else textOffsetX += (spriteFont.charAdvanceX[index]*scaleFactor + spacing);
+ if (spriteFont.chars[index].advanceX == 0) textOffsetX += (int)(spriteFont.chars[index].rec.width*scaleFactor + spacing);
+ else textOffsetX += (int)(spriteFont.chars[index].advanceX*scaleFactor + spacing);
}
}
}
@@ -460,14 +487,14 @@ int MeasureText(const char *text, int fontSize)
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 tempLen = 0; // Used to count longer text line num chars
int lenCounter = 0;
- int textWidth = 0;
- int tempTextWidth = 0; // Used to count longer text line width
+ float textWidth = 0;
+ float tempTextWidth = 0; // Used to count longer text line width
- int textHeight = spriteFont.size;
- float scaleFactor = fontSize/spriteFont.size;
+ float textHeight = (float)spriteFont.baseSize;
+ float scaleFactor = fontSize/(float)spriteFont.baseSize;
for (int i = 0; i < len; i++)
{
@@ -476,16 +503,16 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i
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);
+
+ if (spriteFont.chars[index].advanceX != 0) textWidth += spriteFont.chars[index].advanceX;
+ else textWidth += (spriteFont.chars[index].rec.width + spriteFont.chars[index].offsetX);
}
else
{
if (tempTextWidth < textWidth) tempTextWidth = textWidth;
lenCounter = 0;
textWidth = 0;
- textHeight += (spriteFont.size + spriteFont.size/2); // NOTE: Fixed line spacing of 1.5 lines
+ textHeight += ((float)spriteFont.baseSize*1.5f); // NOTE: Fixed line spacing of 1.5 lines
}
if (tempLen < lenCounter) tempLen = lenCounter;
@@ -494,8 +521,8 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i
if (tempTextWidth < textWidth) tempTextWidth = textWidth;
Vector2 vec;
- vec.x = (float)tempTextWidth*scaleFactor + (tempLen - 1)*spacing; // Adds chars spacing to measure
- vec.y = (float)textHeight*scaleFactor;
+ vec.x = tempTextWidth*scaleFactor + (float)((tempLen - 1)*spacing); // Adds chars spacing to measure
+ vec.y = textHeight*scaleFactor;
return vec;
}
@@ -504,28 +531,22 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, i
// NOTE: Uses default font
void DrawFPS(int posX, int posY)
{
- char buffer[20];
-
// NOTE: We are rendering fps every second for better viewing on high framerates
- // TODO: Not working properly on ANDROID and RPI
- static float fps = 0.0f;
+ static int fps = 0;
static int counter = 0;
static int refreshRate = 20;
- if (counter < refreshRate)
- {
- counter++;
- }
+ if (counter < refreshRate) counter++;
else
{
fps = GetFPS();
refreshRate = fps;
counter = 0;
}
-
- sprintf(buffer, "%2.0f FPS", fps);
- DrawText(buffer, posX, posY, 20, LIME);
+
+ // NOTE: We have rounding errors every frame, so it oscillates a lot
+ DrawText(FormatText("%2i FPS", fps), posX, posY, 20, LIME);
}
//----------------------------------------------------------------------------------
@@ -537,16 +558,16 @@ 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++)
+
+ for (int i = 0; i < font.charsCount; i++)
{
- if (font.charValues[i] == letter)
+ if (font.chars[i].value == letter)
{
index = i;
break;
}
}
-
+
return index;
#else
return (letter - 32);
@@ -627,43 +648,41 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar)
}
TraceLog(DEBUG, "SpriteFont data parsed correctly from image");
-
- // NOTE: We need to remove key color borders from image to avoid weird
+
+ // 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;
-
+ spriteFont.charsCount = 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));
+ spriteFont.chars = (CharInfo *)malloc(spriteFont.charsCount*sizeof(CharInfo));
- for (int i = 0; i < spriteFont.numChars; i++)
+ for (int i = 0; i < spriteFont.charsCount; i++)
{
- spriteFont.charValues[i] = tempCharValues[i];
- spriteFont.charRecs[i] = tempCharRecs[i];
+ spriteFont.chars[i].value = tempCharValues[i];
+ spriteFont.chars[i].rec = 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.chars[i].offsetX = 0;
+ spriteFont.chars[i].offsetY = 0;
+ spriteFont.chars[i].advanceX = 0;
}
- spriteFont.size = spriteFont.charRecs[0].height;
-
+ spriteFont.baseSize = spriteFont.chars[0].rec.height;
+
TraceLog(INFO, "Image file loaded correctly as SpriteFont");
return spriteFont;
@@ -692,6 +711,8 @@ static SpriteFont LoadRBMF(const char *fileName)
SpriteFont spriteFont = { 0 };
+ // REMOVE SOON!!!
+/*
rbmfInfoHeader rbmfHeader;
unsigned int *rbmfFileData = NULL;
unsigned char *rbmfCharWidthData = NULL;
@@ -757,29 +778,27 @@ static SpriteFont LoadRBMF(const char *fileName)
//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));
+ spriteFont.chars = (CharInfo *)malloc(spriteFont.charsCount*sizeof(CharInfo));
int currentLine = 0;
int currentPosX = charsDivisor;
int testPosX = charsDivisor;
- for (int i = 0; i < spriteFont.numChars; i++)
+ for (int i = 0; i < spriteFont.charsCount; i++)
{
- spriteFont.charValues[i] = (int)rbmfHeader.firstChar + i;
+ spriteFont.chars[i].value = (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;
+ spriteFont.chars[i].rec.x = currentPosX;
+ spriteFont.chars[i].rec.y = charsDivisor + currentLine*((int)rbmfHeader.charHeight + charsDivisor);
+ spriteFont.chars[i].rec.width = (int)rbmfCharWidthData[i];
+ spriteFont.chars[i].rec.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;
+ spriteFont.chars[i].offsetX = 0;
+ spriteFont.chars[i].offsetY = 0;
+ spriteFont.chars[i].advanceX = 0;
- testPosX += (spriteFont.charRecs[i].width + charsDivisor);
+ testPosX += (spriteFont.chars[i].rec.width + charsDivisor);
if (testPosX > spriteFont.texture.width)
{
@@ -787,13 +806,13 @@ static SpriteFont LoadRBMF(const char *fileName)
currentPosX = 2*charsDivisor + (int)rbmfCharWidthData[i];
testPosX = currentPosX;
- spriteFont.charRecs[i].x = charsDivisor;
- spriteFont.charRecs[i].y = charsDivisor + currentLine*(rbmfHeader.charHeight + charsDivisor);
+ spriteFont.chars[i].rec.x = charsDivisor;
+ spriteFont.chars[i].rec.y = charsDivisor + currentLine*(rbmfHeader.charHeight + charsDivisor);
}
else currentPosX = testPosX;
}
- spriteFont.size = spriteFont.charRecs[0].height;
+ spriteFont.baseSize = spriteFont.charRecs[0].height;
TraceLog(INFO, "[%s] rBMF file loaded correctly as SpriteFont", fileName);
}
@@ -802,6 +821,7 @@ static SpriteFont LoadRBMF(const char *fileName)
free(rbmfFileData); // Now we can free loaded data from RAM memory
free(rbmfCharWidthData);
+*/
return spriteFont;
}
@@ -820,7 +840,7 @@ static SpriteFont LoadBMFont(const char *fileName)
int fontSize = 0;
int texWidth, texHeight;
char texFileName[128];
- int numChars = 0;
+ int charsCount = 0;
int base; // Useless data
@@ -854,9 +874,9 @@ static SpriteFont LoadBMFont(const char *fileName)
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
searchPoint = strstr(buffer, "count");
- sscanf(searchPoint, "count=%i", &numChars);
+ sscanf(searchPoint, "count=%i", &charsCount);
- TraceLog(DEBUG, "[%s] Font num chars: %i", fileName, numChars);
+ TraceLog(DEBUG, "[%s] Font num chars: %i", fileName, charsCount);
// Compose correct path using route of .fnt file (fileName) and texFileName
char *texPath = NULL;
@@ -873,13 +893,13 @@ static SpriteFont LoadBMFont(const char *fileName)
strncat(texPath, texFileName, strlen(texFileName));
TraceLog(DEBUG, "[%s] Font texture loading path: %s", fileName, texPath);
-
+
Image imFont = LoadImage(texPath);
-
- if (imFont.format == UNCOMPRESSED_GRAYSCALE)
+
+ 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);
@@ -887,31 +907,29 @@ static SpriteFont LoadBMFont(const char *fileName)
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));
+
+ font.baseSize = fontSize;
+ font.charsCount = charsCount;
+ font.chars = (CharInfo *)malloc(charsCount*sizeof(CharInfo));
UnloadImage(imFont);
-
+
free(texPath);
int charId, charX, charY, charWidth, charHeight, charOffsetX, charOffsetY, charAdvanceX;
- for (int i = 0; i < numChars; i++)
+ for (int i = 0; i < charsCount; 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;
+ font.chars[i].value = charId;
+ font.chars[i].rec = (Rectangle){ charX, charY, charWidth, charHeight };
+ font.chars[i].offsetX = charOffsetX;
+ font.chars[i].offsetY = charOffsetY;
+ font.chars[i].advanceX = charAdvanceX;
}
fclose(fntFile);
@@ -928,18 +946,23 @@ static SpriteFont LoadBMFont(const char *fileName)
// 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)
+static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars)
{
+ #define MAX_TTF_SIZE 16 // Maximum ttf file size in MB
+
// 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...
- int textureSize = GetNextPOT(ceil((float)fontSize*3/4)*ceil(sqrtf((float)numChars)));
-
+
+ // Calculate next power-of-two value
+ float guessSize = ceilf((float)fontSize*3/4)*ceilf(sqrtf((float)charsCount));
+ 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 *ttfBuffer = (unsigned char *)malloc(MAX_TTF_SIZE*1024*1024);
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);
+ stbtt_bakedchar *charData = (stbtt_bakedchar *)malloc(sizeof(stbtt_bakedchar)*charsCount);
SpriteFont font = { 0 };
@@ -951,18 +974,19 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int
return font;
}
- fread(ttfBuffer, 1, 1<<25, ttfFile);
-
+ // NOTE: We try reading up to 16 MB of elements of 1 byte
+ fread(ttfBuffer, 1, MAX_TTF_SIZE*1024*1024, 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);
+ int result = stbtt_BakeFontBitmap(ttfBuffer, 0, fontSize, dataBitmap, textureSize, textureSize, fontChars[0], charsCount, 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
@@ -983,31 +1007,29 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int numChars, int
image.mipmaps = 1;
image.format = UNCOMPRESSED_GRAY_ALPHA;
image.data = dataGrayAlpha;
-
+
font.texture = LoadTextureFromImage(image);
-
- //WritePNG("generated_ttf_image.png", (unsigned char *)image.data, image.width, image.height, 2);
-
+
+ //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));
+ font.baseSize = fontSize;
+ font.charsCount = charsCount;
+ font.chars = (CharInfo *)malloc(font.charsCount*sizeof(CharInfo));
- for (int i = 0; i < font.numChars; i++)
+ for (int i = 0; i < font.charsCount; i++)
{
- font.charValues[i] = fontChars[i];
+ font.chars[i].value = 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.chars[i].rec.x = (int)charData[i].x0;
+ font.chars[i].rec.y = (int)charData[i].y0;
+ font.chars[i].rec.width = (int)charData[i].x1 - (int)charData[i].x0;
+ font.chars[i].rec.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;
+ font.chars[i].offsetX = charData[i].xoff;
+ font.chars[i].offsetY = charData[i].yoff;
+ font.chars[i].advanceX = (int)charData[i].xadvance;
}
free(charData);
diff --git a/src/textures.c b/src/textures.c
index af59d035..7db3bf56 100644
--- a/src/textures.c
+++ b/src/textures.c
@@ -1,16 +1,35 @@
/**********************************************************************************************
*
-* raylib.textures
+* raylib.textures - Basic functions to load and draw Textures (2d)
*
-* Basic functions to load and draw Textures (2d)
+* CONFIGURATION:
*
-* External libs:
+* #define SUPPORT_STB_IMAGE / INCLUDE_STB_IMAGE
+*
+* #define SUPPORT_FILEFORMAT_BMP / SUPPORT_LOAD_BMP
+* #define SUPPORT_FILEFORMAT_PNG / SUPPORT_LOAD_PNG
+* #define SUPPORT_FILEFORMAT_TGA
+* #define SUPPORT_FILEFORMAT_JPG / ENABLE_LOAD_JPG
+* #define SUPPORT_FILEFORMAT_GIF
+* #define SUPPORT_FILEFORMAT_HDR
+* #define SUPPORT_FILEFORMAT_DDS / ENABLE_LOAD_DDS
+* #define SUPPORT_FILEFORMAT_PKM
+* #define SUPPORT_FILEFORMAT_KTX
+* #define SUPPORT_FILEFORMAT_PVR
+* #define SUPPORT_FILEFORMAT_ASTC
+* Selected desired fileformats to be supported for loading. Some of those formats are
+* supported by default, to remove support, just comment unrequired #define in this module
+*
+* #define SUPPORT_IMAGE_RESIZE / INCLUDE_STB_IMAGE_RESIZE
+* #define SUPPORT_IMAGE_MANIPULATION
+*
+* DEPENDENCIES:
* stb_image - Multiple image formats loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC)
* NOTE: stb_image has been slightly modified to support Android platform.
* stb_image_resize - Multiple image resize algorythms
*
-* Module Configuration Flags:
-* ...
+*
+* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
@@ -37,11 +56,10 @@
#include <string.h> // Required for: strcmp(), strrchr(), strncmp()
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3 or ES2
- // Required: rlglLoadTexture() rlDeleteTextures(),
- // rlglGenerateMipmaps(), some funcs for DrawTexturePro()
+ // Required for: rlglLoadTexture() rlDeleteTextures(),
+ // rlglGenerateMipmaps(), some funcs for DrawTexturePro()
-#include "utils.h" // rRES data decompression utility function
- // NOTE: Includes Android fopen function map
+#include "utils.h" // Required for: fopen() Android mapping, TraceLog()
// Support only desired texture formats, by default: JPEG, PNG, BMP, TGA
//#define STBI_NO_JPEG // Image format .jpg and .jpeg
@@ -94,7 +112,7 @@ static Image LoadASTC(const char *fileName); // Load ASTC file
// Module Functions Definition
//----------------------------------------------------------------------------------
-// Load an image into CPU memory (RAM)
+// Load image from file into CPU memory (RAM)
Image LoadImage(const char *fileName)
{
Image image;
@@ -142,17 +160,25 @@ Image LoadImage(const char *fileName)
else if (strcmp(GetExtension(fileName),"ktx") == 0) image = LoadKTX(fileName);
else if (strcmp(GetExtension(fileName),"pvr") == 0) image = LoadPVR(fileName);
else if (strcmp(GetExtension(fileName),"astc") == 0) image = LoadASTC(fileName);
-
- if (image.data != NULL)
+ else if (strcmp(GetExtension(fileName),"rres") == 0)
{
- TraceLog(INFO, "[%s] Image loaded successfully (%ix%i)", fileName, image.width, image.height);
+ RRES rres = LoadResource(fileName, 0);
+
+ // NOTE: Parameters for RRES_TYPE_IMAGE are: width, height, format, mipmaps
+
+ if (rres[0].type == RRES_TYPE_IMAGE) image = LoadImagePro(rres[0].data, rres[0].param1, rres[0].param2, rres[0].param3);
+ else TraceLog(WARNING, "[%s] Resource file does not contain image data", fileName);
+
+ UnloadResource(rres);
}
- else TraceLog(WARNING, "[%s] Image could not be loaded, file not recognized", fileName);
+
+ if (image.data != NULL) TraceLog(INFO, "[%s] Image loaded successfully (%ix%i)", fileName, image.width, image.height);
+ else TraceLog(WARNING, "[%s] Image could not be loaded", fileName);
return image;
}
-// Load image data from Color array data (RGBA - 32bit)
+// Load image from Color array data (RGBA - 32bit)
// NOTE: Creates a copy of pixels data array
Image LoadImageEx(Color *pixels, int width, int height)
{
@@ -179,7 +205,24 @@ Image LoadImageEx(Color *pixels, int width, int height)
return image;
}
-// Load an image from RAW file
+// Load image from raw data with parameters
+// NOTE: This functions makes a copy of provided data
+Image LoadImagePro(void *data, int width, int height, int format)
+{
+ Image srcImage = { 0 };
+
+ srcImage.data = data;
+ srcImage.width = width;
+ srcImage.height = height;
+ srcImage.mipmaps = 1;
+ srcImage.format = format;
+
+ Image dstImage = ImageCopy(srcImage);
+
+ return dstImage;
+}
+
+// Load an image from RAW file data
Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize)
{
Image image;
@@ -214,134 +257,32 @@ Image LoadImageRaw(const char *fileName, int width, int height, int format, int
default: TraceLog(WARNING, "Image format not suported"); break;
}
- fread(image.data, size, 1, rawFile);
-
- // TODO: Check if data have been read
+ // NOTE: fread() returns num read elements instead of bytes,
+ // to get bytes we need to read (1 byte size, elements) instead of (x byte size, 1 element)
+ int bytes = fread(image.data, 1, size, rawFile);
- image.width = width;
- image.height = height;
- image.mipmaps = 0;
- image.format = format;
-
- fclose(rawFile);
- }
-
- return image;
-}
-
-// Load an image from rRES file (raylib Resource)
-// TODO: Review function to support multiple color modes
-Image LoadImageFromRES(const char *rresName, int resId)
-{
- Image image = { 0 };
- bool found = false;
-
- char id[4]; // rRES file identifier
- unsigned char version; // rRES file version and subversion
- char useless; // rRES header reserved data
- short numRes;
-
- ResInfoHeader infoHeader;
-
- FILE *rresFile = fopen(rresName, "rb");
-
- if (rresFile == NULL)
- {
- TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", rresName);
- }
- else
- {
- // Read rres file (basic file check - id)
- fread(&id[0], sizeof(char), 1, rresFile);
- fread(&id[1], sizeof(char), 1, rresFile);
- fread(&id[2], sizeof(char), 1, rresFile);
- fread(&id[3], sizeof(char), 1, rresFile);
- fread(&version, sizeof(char), 1, rresFile);
- fread(&useless, sizeof(char), 1, rresFile);
-
- if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S'))
+ // Check if data has been read successfully
+ if (bytes < size)
{
- TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName);
+ TraceLog(WARNING, "[%s] RAW image data can not be read, wrong requested format or size", fileName);
+
+ if (image.data != NULL) free(image.data);
}
else
{
- // Read number of resources embedded
- fread(&numRes, sizeof(short), 1, rresFile);
-
- for (int i = 0; i < numRes; i++)
- {
- fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile);
-
- if (infoHeader.id == resId)
- {
- found = true;
-
- // Check data is of valid IMAGE type
- if (infoHeader.type == 0) // IMAGE data type
- {
- // TODO: Check data compression type
- // NOTE: We suppose compression type 2 (DEFLATE - default)
-
- short imgWidth, imgHeight;
- char colorFormat, mipmaps;
-
- fread(&imgWidth, sizeof(short), 1, rresFile); // Image width
- fread(&imgHeight, sizeof(short), 1, rresFile); // Image height
- fread(&colorFormat, 1, 1, rresFile); // Image data color format (default: RGBA 32 bit)
- fread(&mipmaps, 1, 1, rresFile); // Mipmap images included (default: 0)
-
- image.width = (int)imgWidth;
- image.height = (int)imgHeight;
-
- unsigned char *compData = malloc(infoHeader.size);
-
- fread(compData, infoHeader.size, 1, rresFile);
-
- unsigned char *imgData = DecompressData(compData, infoHeader.size, infoHeader.srcSize);
-
- // TODO: Review color mode
- //image.data = (unsigned char *)malloc(sizeof(unsigned char)*imgWidth*imgHeight*4);
- image.data = imgData;
-
- //free(imgData);
-
- free(compData);
-
- TraceLog(INFO, "[%s] Image loaded successfully from resource, size: %ix%i", rresName, image.width, image.height);
- }
- else
- {
- TraceLog(WARNING, "[%s] Required resource do not seem to be a valid IMAGE resource", rresName);
- }
- }
- else
- {
- // Depending on type, skip the right amount of parameters
- switch (infoHeader.type)
- {
- case 0: fseek(rresFile, 6, SEEK_CUR); break; // IMAGE: Jump 6 bytes of parameters
- case 1: fseek(rresFile, 6, SEEK_CUR); break; // SOUND: Jump 6 bytes of parameters
- case 2: fseek(rresFile, 5, SEEK_CUR); break; // MODEL: Jump 5 bytes of parameters (TODO: Review)
- case 3: break; // TEXT: No parameters
- case 4: break; // RAW: No parameters
- default: break;
- }
-
- // Jump DATA to read next infoHeader
- fseek(rresFile, infoHeader.size, SEEK_CUR);
- }
- }
+ image.width = width;
+ image.height = height;
+ image.mipmaps = 0;
+ image.format = format;
}
- fclose(rresFile);
+ fclose(rawFile);
}
- if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId);
-
return image;
}
-// Load an image as texture into GPU memory
+// Load texture from file into GPU memory (VRAM)
Texture2D LoadTexture(const char *fileName)
{
Texture2D texture;
@@ -362,33 +303,6 @@ Texture2D LoadTexture(const char *fileName)
return texture;
}
-// Load a texture from raw data into GPU memory
-Texture2D LoadTextureEx(void *data, int width, int height, int textureFormat)
-{
- Texture2D texture;
-
- texture.width = width;
- texture.height = height;
- texture.mipmaps = 1;
- texture.format = textureFormat;
-
- texture.id = rlglLoadTexture(data, width, height, textureFormat, 1);
-
- return texture;
-}
-
-// Load an image as texture from rRES file (raylib Resource)
-Texture2D LoadTextureFromRES(const char *rresName, int resId)
-{
- Texture2D texture;
-
- Image image = LoadImageFromRES(rresName, resId);
- texture = LoadTextureFromImage(image);
- UnloadImage(image);
-
- return texture;
-}
-
// Load a texture from image data
// NOTE: image is not unloaded, it must be done manually
Texture2D LoadTextureFromImage(Image image)
@@ -412,7 +326,7 @@ Texture2D LoadTextureFromImage(Image image)
return texture;
}
-// Load a texture to be used for rendering
+// Load texture for rendering (framebuffer)
RenderTexture2D LoadRenderTexture(int width, int height)
{
RenderTexture2D target = rlglLoadRenderTexture(width, height);
@@ -429,7 +343,7 @@ void UnloadImage(Image image)
//TraceLog(INFO, "Unloaded image data");
}
-// Unload texture from GPU memory
+// Unload texture from GPU memory (VRAM)
void UnloadTexture(Texture2D texture)
{
if (texture.id != 0)
@@ -440,102 +354,12 @@ void UnloadTexture(Texture2D texture)
}
}
-// Unload render texture from GPU memory
+// Unload render texture from GPU memory (VRAM)
void UnloadRenderTexture(RenderTexture2D target)
{
if (target.id != 0) rlDeleteRenderTextures(target);
}
-// Set texture scaling filter mode
-void SetTextureFilter(Texture2D texture, int filterMode)
-{
- switch (filterMode)
- {
- case FILTER_POINT:
- {
- if (texture.mipmaps > 1)
- {
- // RL_FILTER_MIP_NEAREST - tex filter: POINT, mipmaps filter: POINT (sharp switching between mipmaps)
- rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_NEAREST);
-
- // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
- rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST);
- }
- else
- {
- // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
- rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_NEAREST);
- rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST);
- }
- } break;
- case FILTER_BILINEAR:
- {
- if (texture.mipmaps > 1)
- {
- // RL_FILTER_LINEAR_MIP_NEAREST - tex filter: BILINEAR, mipmaps filter: POINT (sharp switching between mipmaps)
- // Alternative: RL_FILTER_NEAREST_MIP_LINEAR - tex filter: POINT, mipmaps filter: BILINEAR (smooth transition between mipmaps)
- rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR_MIP_NEAREST);
-
- // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
- rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
- }
- else
- {
- // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
- rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR);
- rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
- }
- } break;
- case FILTER_TRILINEAR:
- {
- if (texture.mipmaps > 1)
- {
- // RL_FILTER_MIP_LINEAR - tex filter: BILINEAR, mipmaps filter: BILINEAR (smooth transition between mipmaps)
- rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_LINEAR);
-
- // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
- rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
- }
- else
- {
- TraceLog(WARNING, "[TEX ID %i] No mipmaps available for TRILINEAR texture filtering", texture.id);
-
- // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
- rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR);
- rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
- }
- } break;
- case FILTER_ANISOTROPIC_4X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 4); break;
- case FILTER_ANISOTROPIC_8X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 8); break;
- case FILTER_ANISOTROPIC_16X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 16); break;
- default: break;
- }
-}
-
-// Set texture wrapping mode
-void SetTextureWrap(Texture2D texture, int wrapMode)
-{
- switch (wrapMode)
- {
- case WRAP_REPEAT:
- {
- rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_REPEAT);
- rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_REPEAT);
- } break;
- case WRAP_CLAMP:
- {
- rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP);
- rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP);
- } break;
- case WRAP_MIRROR:
- {
- rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP_MIRROR);
- rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP_MIRROR);
- } break;
- default: break;
- }
-}
-
// Get pixel data from image in the form of Color struct array
Color *GetImageData(Image image)
{
@@ -654,6 +478,13 @@ Image GetTextureData(Texture2D texture)
return image;
}
+// Update GPU texture with new data
+// NOTE: pixels data must match texture.format
+void UpdateTexture(Texture2D texture, const void *pixels)
+{
+ rlglUpdateTexture(texture.id, texture.width, texture.height, texture.format, pixels);
+}
+
// Convert image data to desired format
void ImageFormat(Image *image, int newFormat)
{
@@ -805,12 +636,12 @@ void ImageAlphaMask(Image *image, Image alphaMask)
// Force mask to be Grayscale
Image mask = ImageCopy(alphaMask);
if (mask.format != UNCOMPRESSED_GRAYSCALE) ImageFormat(&mask, UNCOMPRESSED_GRAYSCALE);
-
+
// In case image is only grayscale, we just add alpha channel
if (image->format == UNCOMPRESSED_GRAYSCALE)
{
ImageFormat(image, UNCOMPRESSED_GRAY_ALPHA);
-
+
// Apply alpha mask to alpha channel
for (int i = 0, k = 1; (i < mask.width*mask.height) || (i < image->width*image->height); i++, k += 2)
{
@@ -872,11 +703,11 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
// NOTE: We will store the dithered data as unsigned short (16bpp)
image->data = (unsigned short *)malloc(image->width*image->height*sizeof(unsigned short));
- Color oldpixel = WHITE;
- Color newpixel = WHITE;
+ Color oldPixel = WHITE;
+ Color newPixel = WHITE;
- int error_r, error_g, error_b;
- unsigned short pixel_r, pixel_g, pixel_b, pixel_a; // Used for 16bit pixel composition
+ int rError, gError, bError;
+ unsigned short rPixel, gPixel, bPixel, aPixel; // Used for 16bit pixel composition
#define MIN(a,b) (((a)<(b))?(a):(b))
@@ -884,57 +715,57 @@ void ImageDither(Image *image, int rBpp, int gBpp, int bBpp, int aBpp)
{
for (int x = 0; x < image->width; x++)
{
- oldpixel = pixels[y*image->width + x];
+ oldPixel = pixels[y*image->width + x];
// NOTE: New pixel obtained by bits truncate, it would be better to round values (check ImageFormat())
- newpixel.r = oldpixel.r>>(8 - rBpp); // R bits
- newpixel.g = oldpixel.g>>(8 - gBpp); // G bits
- newpixel.b = oldpixel.b>>(8 - bBpp); // B bits
- newpixel.a = oldpixel.a>>(8 - aBpp); // A bits (not used on dithering)
+ newPixel.r = oldPixel.r >> (8 - rBpp); // R bits
+ newPixel.g = oldPixel.g >> (8 - gBpp); // G bits
+ newPixel.b = oldPixel.b >> (8 - bBpp); // B bits
+ newPixel.a = oldPixel.a >> (8 - aBpp); // A bits (not used on dithering)
// NOTE: Error must be computed between new and old pixel but using same number of bits!
// We want to know how much color precision we have lost...
- error_r = (int)oldpixel.r - (int)(newpixel.r<<(8 - rBpp));
- error_g = (int)oldpixel.g - (int)(newpixel.g<<(8 - gBpp));
- error_b = (int)oldpixel.b - (int)(newpixel.b<<(8 - bBpp));
+ rError = (int)oldPixel.r - (int)(newPixel.r << (8 - rBpp));
+ gError = (int)oldPixel.g - (int)(newPixel.g << (8 - gBpp));
+ bError = (int)oldPixel.b - (int)(newPixel.b << (8 - bBpp));
- pixels[y*image->width + x] = newpixel;
+ pixels[y*image->width + x] = newPixel;
// NOTE: Some cases are out of the array and should be ignored
if (x < (image->width - 1))
{
- pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)error_r*7.0f/16), 0xff);
- pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)error_g*7.0f/16), 0xff);
- pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)error_b*7.0f/16), 0xff);
+ pixels[y*image->width + x+1].r = MIN((int)pixels[y*image->width + x+1].r + (int)((float)rError*7.0f/16), 0xff);
+ pixels[y*image->width + x+1].g = MIN((int)pixels[y*image->width + x+1].g + (int)((float)gError*7.0f/16), 0xff);
+ pixels[y*image->width + x+1].b = MIN((int)pixels[y*image->width + x+1].b + (int)((float)bError*7.0f/16), 0xff);
}
if ((x > 0) && (y < (image->height - 1)))
{
- pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)error_r*3.0f/16), 0xff);
- pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)error_g*3.0f/16), 0xff);
- pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)error_b*3.0f/16), 0xff);
+ pixels[(y+1)*image->width + x-1].r = MIN((int)pixels[(y+1)*image->width + x-1].r + (int)((float)rError*3.0f/16), 0xff);
+ pixels[(y+1)*image->width + x-1].g = MIN((int)pixels[(y+1)*image->width + x-1].g + (int)((float)gError*3.0f/16), 0xff);
+ pixels[(y+1)*image->width + x-1].b = MIN((int)pixels[(y+1)*image->width + x-1].b + (int)((float)bError*3.0f/16), 0xff);
}
if (y < (image->height - 1))
{
- pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)error_r*5.0f/16), 0xff);
- pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)error_g*5.0f/16), 0xff);
- pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)error_b*5.0f/16), 0xff);
+ pixels[(y+1)*image->width + x].r = MIN((int)pixels[(y+1)*image->width + x].r + (int)((float)rError*5.0f/16), 0xff);
+ pixels[(y+1)*image->width + x].g = MIN((int)pixels[(y+1)*image->width + x].g + (int)((float)gError*5.0f/16), 0xff);
+ pixels[(y+1)*image->width + x].b = MIN((int)pixels[(y+1)*image->width + x].b + (int)((float)bError*5.0f/16), 0xff);
}
if ((x < (image->width - 1)) && (y < (image->height - 1)))
{
- pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)error_r*1.0f/16), 0xff);
- pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)error_g*1.0f/16), 0xff);
- pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)error_b*1.0f/16), 0xff);
+ pixels[(y+1)*image->width + x+1].r = MIN((int)pixels[(y+1)*image->width + x+1].r + (int)((float)rError*1.0f/16), 0xff);
+ pixels[(y+1)*image->width + x+1].g = MIN((int)pixels[(y+1)*image->width + x+1].g + (int)((float)gError*1.0f/16), 0xff);
+ pixels[(y+1)*image->width + x+1].b = MIN((int)pixels[(y+1)*image->width + x+1].b + (int)((float)bError*1.0f/16), 0xff);
}
- pixel_r = (unsigned short)newpixel.r;
- pixel_g = (unsigned short)newpixel.g;
- pixel_b = (unsigned short)newpixel.b;
- pixel_a = (unsigned short)newpixel.a;
+ rPixel = (unsigned short)newPixel.r;
+ gPixel = (unsigned short)newPixel.g;
+ bPixel = (unsigned short)newPixel.b;
+ aPixel = (unsigned short)newPixel.a;
- ((unsigned short *)image->data)[y*image->width + x] = (pixel_r<<(gBpp + bBpp + aBpp)) | (pixel_g<<(bBpp + aBpp)) | (pixel_b<<aBpp) | pixel_a;
+ ((unsigned short *)image->data)[y*image->width + x] = (rPixel << (gBpp + bBpp + aBpp)) | (gPixel << (bBpp + aBpp)) | (bPixel << aBpp) | aPixel;
}
}
@@ -948,9 +779,10 @@ void ImageToPOT(Image *image, Color fillColor)
{
Color *pixels = GetImageData(*image); // Get pixels data
- // Just add the required amount of pixels at the right and bottom sides of image...
- int potWidth = GetNextPOT(image->width);
- int potHeight = GetNextPOT(image->height);
+ // Calculate next power-of-two values
+ // NOTE: Just add the required amount of pixels at the right and bottom sides of image...
+ int potWidth = (int)powf(2, ceilf(logf((float)image->width)/logf(2)));
+ int potHeight = (int)powf(2, ceilf(logf((float)image->height)/logf(2)));
// Check if POT texture generation is required (if texture is not already POT)
if ((potWidth != image->width) || (potHeight != image->height))
@@ -991,24 +823,37 @@ Image ImageCopy(Image image)
{
Image newImage;
- int size = image.width*image.height;
+ int byteSize = image.width*image.height;
switch (image.format)
{
- case UNCOMPRESSED_GRAYSCALE: newImage.data = (unsigned char *)malloc(size); break; // 8 bit per pixel (no alpha)
- case UNCOMPRESSED_GRAY_ALPHA: newImage.data = (unsigned char *)malloc(size*2); size *= 2; break; // 16 bpp (2 channels)
- case UNCOMPRESSED_R5G6B5: newImage.data = (unsigned short *)malloc(size); size *= 2; break; // 16 bpp
- case UNCOMPRESSED_R8G8B8: newImage.data = (unsigned char *)malloc(size*3); size *= 3; break; // 24 bpp
- case UNCOMPRESSED_R5G5B5A1: newImage.data = (unsigned short *)malloc(size); size *= 2; break; // 16 bpp (1 bit alpha)
- case UNCOMPRESSED_R4G4B4A4: newImage.data = (unsigned short *)malloc(size); size *= 2; break; // 16 bpp (4 bit alpha)
- case UNCOMPRESSED_R8G8B8A8: newImage.data = (unsigned char *)malloc(size*4); size *= 4; break; // 32 bpp
- default: TraceLog(WARNING, "Image format not suported for copy"); break;
+ case UNCOMPRESSED_GRAYSCALE: break; // 8 bpp (1 byte)
+ case UNCOMPRESSED_GRAY_ALPHA: // 16 bpp
+ case UNCOMPRESSED_R5G6B5: // 16 bpp
+ case UNCOMPRESSED_R5G5B5A1: // 16 bpp
+ case UNCOMPRESSED_R4G4B4A4: byteSize *= 2; break; // 16 bpp (2 bytes)
+ case UNCOMPRESSED_R8G8B8: byteSize *= 3; break; // 24 bpp (3 bytes)
+ case UNCOMPRESSED_R8G8B8A8: byteSize *= 4; break; // 32 bpp (4 bytes)
+ case COMPRESSED_DXT3_RGBA:
+ case COMPRESSED_DXT5_RGBA:
+ case COMPRESSED_ETC2_EAC_RGBA:
+ case COMPRESSED_ASTC_4x4_RGBA: break; // 8 bpp (1 byte)
+ case COMPRESSED_DXT1_RGB:
+ case COMPRESSED_DXT1_RGBA:
+ case COMPRESSED_ETC1_RGB:
+ case COMPRESSED_ETC2_RGB:
+ case COMPRESSED_PVRT_RGB:
+ case COMPRESSED_PVRT_RGBA: byteSize /= 2; break; // 4 bpp
+ case COMPRESSED_ASTC_8x8_RGBA: byteSize /= 4; break;// 2 bpp
+ default: TraceLog(WARNING, "Image format not recognized"); break;
}
+ newImage.data = malloc(byteSize);
+
if (newImage.data != NULL)
{
// NOTE: Size must be provided in bytes
- memcpy(newImage.data, image.data, size);
+ memcpy(newImage.data, image.data, byteSize);
newImage.width = image.width;
newImage.height = image.height;
@@ -1100,18 +945,18 @@ void ImageResizeNN(Image *image,int newWidth,int newHeight)
Color *output = (Color *)malloc(newWidth*newHeight*sizeof(Color));
// EDIT: added +1 to account for an early rounding problem
- int x_ratio = (int)((image->width<<16)/newWidth) + 1;
- int y_ratio = (int)((image->height<<16)/newHeight) + 1;
+ int xRatio = (int)((image->width << 16)/newWidth) + 1;
+ int yRatio = (int)((image->height << 16)/newHeight) + 1;
int x2, y2;
- for (int i = 0; i < newHeight; i++)
+ for (int y = 0; y < newHeight; y++)
{
- for (int j = 0; j < newWidth; j++)
+ for (int x = 0; x < newWidth; x++)
{
- x2 = ((j*x_ratio) >> 16);
- y2 = ((i*y_ratio) >> 16);
+ x2 = ((x*xRatio) >> 16);
+ y2 = ((y*yRatio) >> 16);
- output[(i*newWidth) + j] = pixels[(y2*image->width) + x2] ;
+ output[(y*newWidth) + x] = pixels[(y2*image->width) + x2] ;
}
}
@@ -1131,7 +976,7 @@ void ImageResizeNN(Image *image,int newWidth,int newHeight)
void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
{
bool cropRequired = false;
-
+
// Security checks to avoid size and rectangle issues (out of bounds)
// Check that srcRec is inside src image
if (srcRec.x < 0) srcRec.x = 0;
@@ -1149,15 +994,15 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
TraceLog(WARNING, "Source rectangle height out of bounds, rescaled height: %i", srcRec.height);
cropRequired = true;
}
-
+
Image srcCopy = ImageCopy(src); // Make a copy of source image to work with it
ImageCrop(&srcCopy, srcRec); // Crop source image to desired source rectangle
-
+
// Check that dstRec is inside dst image
// TODO: Allow negative position within destination with cropping
if (dstRec.x < 0) dstRec.x = 0;
if (dstRec.y < 0) dstRec.y = 0;
-
+
// Scale source image in case destination rec size is different than source rec size
if ((dstRec.width != srcRec.width) || (dstRec.height != srcRec.height))
{
@@ -1177,24 +1022,24 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
TraceLog(WARNING, "Destination rectangle height out of bounds, rescaled height: %i", dstRec.height);
cropRequired = true;
}
-
+
if (cropRequired)
{
// Crop destination rectangle if out of bounds
Rectangle crop = { 0, 0, dstRec.width, dstRec.height };
ImageCrop(&srcCopy, crop);
}
-
+
// Get image data as Color pixels array to work with it
Color *dstPixels = GetImageData(*dst);
Color *srcPixels = GetImageData(srcCopy);
UnloadImage(srcCopy); // Source copy not required any more...
-
+
Color srcCol, dstCol;
// Blit pixels, copy source image into destination
- // TODO: Probably out-of-bounds blitting could be considering here instead of so much cropping...
+ // TODO: Probably out-of-bounds blitting could be considered here instead of so much cropping...
for (int j = dstRec.y; j < (dstRec.y + dstRec.height); j++)
{
for (int i = dstRec.x; i < (dstRec.x + dstRec.width); i++)
@@ -1202,13 +1047,13 @@ void ImageDraw(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec)
// Alpha blending implementation
dstCol = dstPixels[j*dst->width + i];
srcCol = srcPixels[(j - dstRec.y)*dstRec.width + (i - dstRec.x)];
-
+
dstCol.r = ((srcCol.a*(srcCol.r - dstCol.r)) >> 8) + dstCol.r;
dstCol.g = ((srcCol.a*(srcCol.g - dstCol.g)) >> 8) + dstCol.g;
dstCol.b = ((srcCol.a*(srcCol.b - dstCol.b)) >> 8) + dstCol.b;
-
+
dstPixels[j*dst->width + i] = dstCol;
-
+
// TODO: Support other blending options
}
}
@@ -1240,7 +1085,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing
int length = strlen(text);
int posX = 0;
- Vector2 imSize = MeasureTextEx(font, text, font.size, spacing);
+ Vector2 imSize = MeasureTextEx(font, text, font.baseSize, spacing);
// NOTE: GetTextureData() not available in OpenGL ES
Image imFont = GetTextureData(font.texture);
@@ -1256,7 +1101,7 @@ Image ImageTextEx(SpriteFont font, const char *text, float fontSize, int spacing
for (int i = 0; i < length; i++)
{
- Rectangle letterRec = font.charRecs[(int)text[i] - 32];
+ Rectangle letterRec = font.chars[(int)text[i] - 32].rec;
for (int y = letterRec.y; y < (letterRec.y + letterRec.height); y++)
{
@@ -1516,14 +1361,15 @@ void ImageColorBrightness(Image *image, int brightness)
}
// Generate GPU mipmaps for a texture
-void GenTextureMipmaps(Texture2D texture)
+void GenTextureMipmaps(Texture2D *texture)
{
#if PLATFORM_WEB
- int potWidth = GetNextPOT(texture.width);
- int potHeight = GetNextPOT(texture.height);
+ // Calculate next power-of-two values
+ int potWidth = (int)powf(2, ceilf(logf((float)texture->width)/logf(2)));
+ int potHeight = (int)powf(2, ceilf(logf((float)texture->height)/logf(2)));
// Check if texture is POT
- if ((potWidth != texture.width) || (potHeight != texture.height))
+ if ((potWidth != texture->width) || (potHeight != texture->height))
{
TraceLog(WARNING, "Limited NPOT support, no mipmaps available for NPOT textures");
}
@@ -1533,11 +1379,94 @@ void GenTextureMipmaps(Texture2D texture)
#endif
}
-// Update GPU texture with new data
-// NOTE: pixels data must match texture.format
-void UpdateTexture(Texture2D texture, void *pixels)
+// Set texture scaling filter mode
+void SetTextureFilter(Texture2D texture, int filterMode)
{
- rlglUpdateTexture(texture.id, texture.width, texture.height, texture.format, pixels);
+ switch (filterMode)
+ {
+ case FILTER_POINT:
+ {
+ if (texture.mipmaps > 1)
+ {
+ // RL_FILTER_MIP_NEAREST - tex filter: POINT, mipmaps filter: POINT (sharp switching between mipmaps)
+ rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_NEAREST);
+
+ // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
+ rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST);
+ }
+ else
+ {
+ // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
+ rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_NEAREST);
+ rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST);
+ }
+ } break;
+ case FILTER_BILINEAR:
+ {
+ if (texture.mipmaps > 1)
+ {
+ // RL_FILTER_LINEAR_MIP_NEAREST - tex filter: BILINEAR, mipmaps filter: POINT (sharp switching between mipmaps)
+ // Alternative: RL_FILTER_NEAREST_MIP_LINEAR - tex filter: POINT, mipmaps filter: BILINEAR (smooth transition between mipmaps)
+ rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR_MIP_NEAREST);
+
+ // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+ rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
+ }
+ else
+ {
+ // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+ rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR);
+ rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
+ }
+ } break;
+ case FILTER_TRILINEAR:
+ {
+ if (texture.mipmaps > 1)
+ {
+ // RL_FILTER_MIP_LINEAR - tex filter: BILINEAR, mipmaps filter: BILINEAR (smooth transition between mipmaps)
+ rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_LINEAR);
+
+ // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+ rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
+ }
+ else
+ {
+ TraceLog(WARNING, "[TEX ID %i] No mipmaps available for TRILINEAR texture filtering", texture.id);
+
+ // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+ rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR);
+ rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
+ }
+ } break;
+ case FILTER_ANISOTROPIC_4X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 4); break;
+ case FILTER_ANISOTROPIC_8X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 8); break;
+ case FILTER_ANISOTROPIC_16X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 16); break;
+ default: break;
+ }
+}
+
+// Set texture wrapping mode
+void SetTextureWrap(Texture2D texture, int wrapMode)
+{
+ switch (wrapMode)
+ {
+ case WRAP_REPEAT:
+ {
+ rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_REPEAT);
+ rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_REPEAT);
+ } break;
+ case WRAP_CLAMP:
+ {
+ rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP);
+ rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP);
+ } break;
+ case WRAP_MIRROR:
+ {
+ rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP_MIRROR);
+ rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP_MIRROR);
+ } break;
+ default: break;
+ }
}
// Draw a Texture2D
@@ -1584,7 +1513,7 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V
rlEnableTexture(texture.id);
rlPushMatrix();
- rlTranslatef(destRec.x, destRec.y, 0);
+ rlTranslatef((float)destRec.x, (float)destRec.y, 0);
rlRotatef(rotation, 0, 0, 1);
rlTranslatef(-origin.x, -origin.y, 0);
@@ -1598,15 +1527,15 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V
// Bottom-right corner for texture and quad
rlTexCoord2f((float)sourceRec.x/texture.width, (float)(sourceRec.y + sourceRec.height)/texture.height);
- rlVertex2f(0.0f, destRec.height);
+ rlVertex2f(0.0f, (float)destRec.height);
// Top-right corner for texture and quad
rlTexCoord2f((float)(sourceRec.x + sourceRec.width)/texture.width, (float)(sourceRec.y + sourceRec.height)/texture.height);
- rlVertex2f(destRec.width, destRec.height);
+ rlVertex2f((float)destRec.width, (float)destRec.height);
// Top-left corner for texture and quad
rlTexCoord2f((float)(sourceRec.x + sourceRec.width)/texture.width, (float)sourceRec.y/texture.height);
- rlVertex2f(destRec.width, 0.0f);
+ rlVertex2f((float)destRec.width, 0.0f);
rlEnd();
rlPopMatrix();
@@ -1644,7 +1573,7 @@ static Image LoadDDS(const char *fileName)
unsigned int gBitMask;
unsigned int bBitMask;
unsigned int aBitMask;
- } ddsPixelFormat;
+ } DDSPixelFormat;
// DDS Header (124 bytes)
typedef struct {
@@ -1656,13 +1585,13 @@ static Image LoadDDS(const char *fileName)
unsigned int depth;
unsigned int mipmapCount;
unsigned int reserved1[11];
- ddsPixelFormat ddspf;
+ DDSPixelFormat ddspf;
unsigned int caps;
unsigned int caps2;
unsigned int caps3;
unsigned int caps4;
unsigned int reserved2;
- } ddsHeader;
+ } DDSHeader;
Image image;
@@ -1683,7 +1612,7 @@ static Image LoadDDS(const char *fileName)
// Verify the type of file
char filecode[4];
- fread(filecode, 1, 4, ddsFile);
+ fread(filecode, 4, 1, ddsFile);
if (strncmp(filecode, "DDS ", 4) != 0)
{
@@ -1691,33 +1620,33 @@ static Image LoadDDS(const char *fileName)
}
else
{
- ddsHeader header;
+ DDSHeader ddsHeader;
// Get the image header
- fread(&header, sizeof(ddsHeader), 1, ddsFile);
+ fread(&ddsHeader, sizeof(DDSHeader), 1, ddsFile);
- TraceLog(DEBUG, "[%s] DDS file header size: %i", fileName, sizeof(ddsHeader));
- TraceLog(DEBUG, "[%s] DDS file pixel format size: %i", fileName, header.ddspf.size);
- TraceLog(DEBUG, "[%s] DDS file pixel format flags: 0x%x", fileName, header.ddspf.flags);
- TraceLog(DEBUG, "[%s] DDS file format: 0x%x", fileName, header.ddspf.fourCC);
- TraceLog(DEBUG, "[%s] DDS file bit count: 0x%x", fileName, header.ddspf.rgbBitCount);
+ TraceLog(DEBUG, "[%s] DDS file header size: %i", fileName, sizeof(DDSHeader));
+ TraceLog(DEBUG, "[%s] DDS file pixel format size: %i", fileName, ddsHeader.ddspf.size);
+ TraceLog(DEBUG, "[%s] DDS file pixel format flags: 0x%x", fileName, ddsHeader.ddspf.flags);
+ TraceLog(DEBUG, "[%s] DDS file format: 0x%x", fileName, ddsHeader.ddspf.fourCC);
+ TraceLog(DEBUG, "[%s] DDS file bit count: 0x%x", fileName, ddsHeader.ddspf.rgbBitCount);
- image.width = header.width;
- image.height = header.height;
- image.mipmaps = 1; // Default value, could be changed (header.mipmapCount)
+ image.width = ddsHeader.width;
+ image.height = ddsHeader.height;
+ image.mipmaps = 1; // Default value, could be changed (ddsHeader.mipmapCount)
- if (header.ddspf.rgbBitCount == 16) // 16bit mode, no compressed
+ if (ddsHeader.ddspf.rgbBitCount == 16) // 16bit mode, no compressed
{
- if (header.ddspf.flags == 0x40) // no alpha channel
+ if (ddsHeader.ddspf.flags == 0x40) // no alpha channel
{
image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short));
fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile);
image.format = UNCOMPRESSED_R5G6B5;
}
- else if (header.ddspf.flags == 0x41) // with alpha channel
+ else if (ddsHeader.ddspf.flags == 0x41) // with alpha channel
{
- if (header.ddspf.aBitMask == 0x8000) // 1bit alpha
+ if (ddsHeader.ddspf.aBitMask == 0x8000) // 1bit alpha
{
image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short));
fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile);
@@ -1734,7 +1663,7 @@ static Image LoadDDS(const char *fileName)
image.format = UNCOMPRESSED_R5G5B5A1;
}
- else if (header.ddspf.aBitMask == 0xf000) // 4bit alpha
+ else if (ddsHeader.ddspf.aBitMask == 0xf000) // 4bit alpha
{
image.data = (unsigned short *)malloc(image.width*image.height*sizeof(unsigned short));
fread(image.data, image.width*image.height*sizeof(unsigned short), 1, ddsFile);
@@ -1753,7 +1682,7 @@ static Image LoadDDS(const char *fileName)
}
}
}
- if (header.ddspf.flags == 0x40 && header.ddspf.rgbBitCount == 24) // DDS_RGB, no compressed
+ if (ddsHeader.ddspf.flags == 0x40 && ddsHeader.ddspf.rgbBitCount == 24) // DDS_RGB, no compressed
{
// NOTE: not sure if this case exists...
image.data = (unsigned char *)malloc(image.width*image.height*3*sizeof(unsigned char));
@@ -1761,7 +1690,7 @@ static Image LoadDDS(const char *fileName)
image.format = UNCOMPRESSED_R8G8B8;
}
- else if (header.ddspf.flags == 0x41 && header.ddspf.rgbBitCount == 32) // DDS_RGBA, no compressed
+ else if (ddsHeader.ddspf.flags == 0x41 && ddsHeader.ddspf.rgbBitCount == 32) // DDS_RGBA, no compressed
{
image.data = (unsigned char *)malloc(image.width*image.height*4*sizeof(unsigned char));
fread(image.data, image.width*image.height*4, 1, ddsFile);
@@ -1780,27 +1709,27 @@ static Image LoadDDS(const char *fileName)
image.format = UNCOMPRESSED_R8G8B8A8;
}
- else if (((header.ddspf.flags == 0x04) || (header.ddspf.flags == 0x05)) && (header.ddspf.fourCC > 0)) // Compressed
+ else if (((ddsHeader.ddspf.flags == 0x04) || (ddsHeader.ddspf.flags == 0x05)) && (ddsHeader.ddspf.fourCC > 0)) // Compressed
{
- int bufsize;
+ int size; // DDS image data size
// Calculate data size, including all mipmaps
- if (header.mipmapCount > 1) bufsize = header.pitchOrLinearSize*2;
- else bufsize = header.pitchOrLinearSize;
+ if (ddsHeader.mipmapCount > 1) size = ddsHeader.pitchOrLinearSize*2;
+ else size = ddsHeader.pitchOrLinearSize;
- TraceLog(DEBUG, "Pitch or linear size: %i", header.pitchOrLinearSize);
+ TraceLog(DEBUG, "Pitch or linear size: %i", ddsHeader.pitchOrLinearSize);
- image.data = (unsigned char*)malloc(bufsize*sizeof(unsigned char));
+ image.data = (unsigned char*)malloc(size*sizeof(unsigned char));
- fread(image.data, 1, bufsize, ddsFile);
+ fread(image.data, size, 1, ddsFile);
- image.mipmaps = header.mipmapCount;
+ image.mipmaps = ddsHeader.mipmapCount;
- switch (header.ddspf.fourCC)
+ switch (ddsHeader.ddspf.fourCC)
{
case FOURCC_DXT1:
{
- if (header.ddspf.flags == 0x04) image.format = COMPRESSED_DXT1_RGB;
+ if (ddsHeader.ddspf.flags == 0x04) image.format = COMPRESSED_DXT1_RGB;
else image.format = COMPRESSED_DXT1_RGBA;
} break;
case FOURCC_DXT3: image.format = COMPRESSED_DXT3_RGBA; break;
@@ -1839,7 +1768,7 @@ static Image LoadPKM(const char *fileName)
unsigned short height; // Texture height (big-endian) (origHeight rounded to multiple of 4)
unsigned short origWidth; // Original width (big-endian)
unsigned short origHeight; // Original height (big-endian)
- } pkmHeader;
+ } PKMHeader;
// Formats list
// version 10: format: 0=ETC1_RGB, [1=ETC1_RGBA, 2=ETC1_RGB_MIP, 3=ETC1_RGBA_MIP] (not used)
@@ -1864,42 +1793,42 @@ static Image LoadPKM(const char *fileName)
}
else
{
- pkmHeader header;
+ PKMHeader pkmHeader;
// Get the image header
- fread(&header, sizeof(pkmHeader), 1, pkmFile);
+ fread(&pkmHeader, sizeof(PKMHeader), 1, pkmFile);
- if (strncmp(header.id, "PKM ", 4) != 0)
+ if (strncmp(pkmHeader.id, "PKM ", 4) != 0)
{
TraceLog(WARNING, "[%s] PKM file does not seem to be a valid image", fileName);
}
else
{
// NOTE: format, width and height come as big-endian, data must be swapped to little-endian
- header.format = ((header.format & 0x00FF) << 8) | ((header.format & 0xFF00) >> 8);
- header.width = ((header.width & 0x00FF) << 8) | ((header.width & 0xFF00) >> 8);
- header.height = ((header.height & 0x00FF) << 8) | ((header.height & 0xFF00) >> 8);
+ pkmHeader.format = ((pkmHeader.format & 0x00FF) << 8) | ((pkmHeader.format & 0xFF00) >> 8);
+ pkmHeader.width = ((pkmHeader.width & 0x00FF) << 8) | ((pkmHeader.width & 0xFF00) >> 8);
+ pkmHeader.height = ((pkmHeader.height & 0x00FF) << 8) | ((pkmHeader.height & 0xFF00) >> 8);
- TraceLog(DEBUG, "PKM (ETC) image width: %i", header.width);
- TraceLog(DEBUG, "PKM (ETC) image height: %i", header.height);
- TraceLog(DEBUG, "PKM (ETC) image format: %i", header.format);
+ TraceLog(DEBUG, "PKM (ETC) image width: %i", pkmHeader.width);
+ TraceLog(DEBUG, "PKM (ETC) image height: %i", pkmHeader.height);
+ TraceLog(DEBUG, "PKM (ETC) image format: %i", pkmHeader.format);
- image.width = header.width;
- image.height = header.height;
+ image.width = pkmHeader.width;
+ image.height = pkmHeader.height;
image.mipmaps = 1;
int bpp = 4;
- if (header.format == 3) bpp = 8;
+ if (pkmHeader.format == 3) bpp = 8;
int size = image.width*image.height*bpp/8; // Total data size in bytes
image.data = (unsigned char*)malloc(size*sizeof(unsigned char));
- fread(image.data, 1, size, pkmFile);
+ fread(image.data, size, 1, pkmFile);
- if (header.format == 0) image.format = COMPRESSED_ETC1_RGB;
- else if (header.format == 1) image.format = COMPRESSED_ETC2_RGB;
- else if (header.format == 3) image.format = COMPRESSED_ETC2_EAC_RGBA;
+ if (pkmHeader.format == 0) image.format = COMPRESSED_ETC1_RGB;
+ else if (pkmHeader.format == 1) image.format = COMPRESSED_ETC2_RGB;
+ else if (pkmHeader.format == 3) image.format = COMPRESSED_ETC2_EAC_RGBA;
}
fclose(pkmFile); // Close file pointer
@@ -1937,7 +1866,7 @@ static Image LoadKTX(const char *fileName)
unsigned int faces; // Cubemap faces, for no-cubemap = 1
unsigned int mipmapLevels; // Non-mipmapped textures = 1
unsigned int keyValueDataSize; // Used to encode any arbitrary data...
- } ktxHeader;
+ } KTXHeader;
// NOTE: Before start of every mipmap data block, we have: unsigned int dataSize
@@ -1956,31 +1885,31 @@ static Image LoadKTX(const char *fileName)
}
else
{
- ktxHeader header;
+ KTXHeader ktxHeader;
// Get the image header
- fread(&header, sizeof(ktxHeader), 1, ktxFile);
+ fread(&ktxHeader, sizeof(KTXHeader), 1, ktxFile);
- if ((header.id[1] != 'K') || (header.id[2] != 'T') || (header.id[3] != 'X') ||
- (header.id[4] != ' ') || (header.id[5] != '1') || (header.id[6] != '1'))
+ if ((ktxHeader.id[1] != 'K') || (ktxHeader.id[2] != 'T') || (ktxHeader.id[3] != 'X') ||
+ (ktxHeader.id[4] != ' ') || (ktxHeader.id[5] != '1') || (ktxHeader.id[6] != '1'))
{
TraceLog(WARNING, "[%s] KTX file does not seem to be a valid file", fileName);
}
else
{
- image.width = header.width;
- image.height = header.height;
- image.mipmaps = header.mipmapLevels;
+ image.width = ktxHeader.width;
+ image.height = ktxHeader.height;
+ image.mipmaps = ktxHeader.mipmapLevels;
- TraceLog(DEBUG, "KTX (ETC) image width: %i", header.width);
- TraceLog(DEBUG, "KTX (ETC) image height: %i", header.height);
- TraceLog(DEBUG, "KTX (ETC) image format: 0x%x", header.glInternalFormat);
+ TraceLog(DEBUG, "KTX (ETC) image width: %i", ktxHeader.width);
+ TraceLog(DEBUG, "KTX (ETC) image height: %i", ktxHeader.height);
+ TraceLog(DEBUG, "KTX (ETC) image format: 0x%x", ktxHeader.glInternalFormat);
unsigned char unused;
- if (header.keyValueDataSize > 0)
+ if (ktxHeader.keyValueDataSize > 0)
{
- for (int i = 0; i < header.keyValueDataSize; i++) fread(&unused, 1, 1, ktxFile);
+ for (int i = 0; i < ktxHeader.keyValueDataSize; i++) fread(&unused, sizeof(unsigned char), 1, ktxFile);
}
int dataSize;
@@ -1988,11 +1917,11 @@ static Image LoadKTX(const char *fileName)
image.data = (unsigned char*)malloc(dataSize*sizeof(unsigned char));
- fread(image.data, 1, dataSize, ktxFile);
+ fread(image.data, dataSize, 1, ktxFile);
- if (header.glInternalFormat == 0x8D64) image.format = COMPRESSED_ETC1_RGB;
- else if (header.glInternalFormat == 0x9274) image.format = COMPRESSED_ETC2_RGB;
- else if (header.glInternalFormat == 0x9278) image.format = COMPRESSED_ETC2_EAC_RGBA;
+ if (ktxHeader.glInternalFormat == 0x8D64) image.format = COMPRESSED_ETC1_RGB;
+ else if (ktxHeader.glInternalFormat == 0x9274) image.format = COMPRESSED_ETC2_RGB;
+ else if (ktxHeader.glInternalFormat == 0x9278) image.format = COMPRESSED_ETC2_EAC_RGBA;
}
fclose(ktxFile); // Close file pointer
@@ -2028,7 +1957,7 @@ static Image LoadPVR(const char *fileName)
unsigned int bitmaskAlpha;
unsigned int pvrTag;
unsigned int numSurfs;
- } pvrHeaderV2;
+ } PVRHeaderV2;
#endif
// PVR file v3 Header (52 bytes)
@@ -2047,7 +1976,7 @@ static Image LoadPVR(const char *fileName)
unsigned int numFaces;
unsigned int numMipmaps;
unsigned int metaDataSize;
- } pvrHeaderV3;
+ } PVRHeaderV3;
#if 0 // Not used...
// Metadata (usually 15 bytes)
@@ -2056,7 +1985,7 @@ static Image LoadPVR(const char *fileName)
unsigned int key;
unsigned int dataSize; // Not used?
unsigned char *data; // Not used?
- } pvrMetadata;
+ } PVRMetadata;
#endif
Image image;
@@ -2083,44 +2012,49 @@ static Image LoadPVR(const char *fileName)
// Load different PVR data formats
if (pvrVersion == 0x50)
{
- pvrHeaderV3 header;
+ PVRHeaderV3 pvrHeader;
// Get PVR image header
- fread(&header, sizeof(pvrHeaderV3), 1, pvrFile);
+ fread(&pvrHeader, sizeof(PVRHeaderV3), 1, pvrFile);
- if ((header.id[0] != 'P') || (header.id[1] != 'V') || (header.id[2] != 'R') || (header.id[3] != 3))
+ if ((pvrHeader.id[0] != 'P') || (pvrHeader.id[1] != 'V') || (pvrHeader.id[2] != 'R') || (pvrHeader.id[3] != 3))
{
TraceLog(WARNING, "[%s] PVR file does not seem to be a valid image", fileName);
}
else
{
- image.width = header.width;
- image.height = header.height;
- image.mipmaps = header.numMipmaps;
+ image.width = pvrHeader.width;
+ image.height = pvrHeader.height;
+ image.mipmaps = pvrHeader.numMipmaps;
// Check data format
- if (((header.channels[0] == 'l') && (header.channels[1] == 0)) && (header.channelDepth[0] == 8)) image.format = UNCOMPRESSED_GRAYSCALE;
- else if (((header.channels[0] == 'l') && (header.channels[1] == 'a')) && ((header.channelDepth[0] == 8) && (header.channelDepth[1] == 8))) image.format = UNCOMPRESSED_GRAY_ALPHA;
- else if ((header.channels[0] == 'r') && (header.channels[1] == 'g') && (header.channels[2] == 'b'))
+ if (((pvrHeader.channels[0] == 'l') && (pvrHeader.channels[1] == 0)) && (pvrHeader.channelDepth[0] == 8))
+ image.format = UNCOMPRESSED_GRAYSCALE;
+ else if (((pvrHeader.channels[0] == 'l') && (pvrHeader.channels[1] == 'a')) && ((pvrHeader.channelDepth[0] == 8) && (pvrHeader.channelDepth[1] == 8)))
+ image.format = UNCOMPRESSED_GRAY_ALPHA;
+ else if ((pvrHeader.channels[0] == 'r') && (pvrHeader.channels[1] == 'g') && (pvrHeader.channels[2] == 'b'))
{
- if (header.channels[3] == 'a')
+ if (pvrHeader.channels[3] == 'a')
{
- if ((header.channelDepth[0] == 5) && (header.channelDepth[1] == 5) && (header.channelDepth[2] == 5) && (header.channelDepth[3] == 1)) image.format = UNCOMPRESSED_R5G5B5A1;
- else if ((header.channelDepth[0] == 4) && (header.channelDepth[1] == 4) && (header.channelDepth[2] == 4) && (header.channelDepth[3] == 4)) image.format = UNCOMPRESSED_R4G4B4A4;
- else if ((header.channelDepth[0] == 8) && (header.channelDepth[1] == 8) && (header.channelDepth[2] == 8) && (header.channelDepth[3] == 8)) image.format = UNCOMPRESSED_R8G8B8A8;
+ if ((pvrHeader.channelDepth[0] == 5) && (pvrHeader.channelDepth[1] == 5) && (pvrHeader.channelDepth[2] == 5) && (pvrHeader.channelDepth[3] == 1))
+ image.format = UNCOMPRESSED_R5G5B5A1;
+ else if ((pvrHeader.channelDepth[0] == 4) && (pvrHeader.channelDepth[1] == 4) && (pvrHeader.channelDepth[2] == 4) && (pvrHeader.channelDepth[3] == 4))
+ image.format = UNCOMPRESSED_R4G4B4A4;
+ else if ((pvrHeader.channelDepth[0] == 8) && (pvrHeader.channelDepth[1] == 8) && (pvrHeader.channelDepth[2] == 8) && (pvrHeader.channelDepth[3] == 8))
+ image.format = UNCOMPRESSED_R8G8B8A8;
}
- else if (header.channels[3] == 0)
+ else if (pvrHeader.channels[3] == 0)
{
- if ((header.channelDepth[0] == 5) && (header.channelDepth[1] == 6) && (header.channelDepth[2] == 5)) image.format = UNCOMPRESSED_R5G6B5;
- else if ((header.channelDepth[0] == 8) && (header.channelDepth[1] == 8) && (header.channelDepth[2] == 8)) image.format = UNCOMPRESSED_R8G8B8;
+ if ((pvrHeader.channelDepth[0] == 5) && (pvrHeader.channelDepth[1] == 6) && (pvrHeader.channelDepth[2] == 5)) image.format = UNCOMPRESSED_R5G6B5;
+ else if ((pvrHeader.channelDepth[0] == 8) && (pvrHeader.channelDepth[1] == 8) && (pvrHeader.channelDepth[2] == 8)) image.format = UNCOMPRESSED_R8G8B8;
}
}
- else if (header.channels[0] == 2) image.format = COMPRESSED_PVRT_RGB;
- else if (header.channels[0] == 3) image.format = COMPRESSED_PVRT_RGBA;
+ else if (pvrHeader.channels[0] == 2) image.format = COMPRESSED_PVRT_RGB;
+ else if (pvrHeader.channels[0] == 3) image.format = COMPRESSED_PVRT_RGBA;
// Skip meta data header
unsigned char unused = 0;
- for (int i = 0; i < header.metaDataSize; i++) fread(&unused, sizeof(unsigned char), 1, pvrFile);
+ for (int i = 0; i < pvrHeader.metaDataSize; i++) fread(&unused, sizeof(unsigned char), 1, pvrFile);
// Calculate data size (depends on format)
int bpp = 0;
@@ -2174,7 +2108,7 @@ static Image LoadASTC(const char *fileName)
unsigned char width[3]; // Image width in pixels (24bit value)
unsigned char height[3]; // Image height in pixels (24bit value)
unsigned char lenght[3]; // Image Z-size (1 for 2D images)
- } astcHeader;
+ } ASTCHeader;
Image image;
@@ -2192,30 +2126,30 @@ static Image LoadASTC(const char *fileName)
}
else
{
- astcHeader header;
+ ASTCHeader astcHeader;
// Get ASTC image header
- fread(&header, sizeof(astcHeader), 1, astcFile);
+ fread(&astcHeader, sizeof(ASTCHeader), 1, astcFile);
- if ((header.id[3] != 0x5c) || (header.id[2] != 0xa1) || (header.id[1] != 0xab) || (header.id[0] != 0x13))
+ if ((astcHeader.id[3] != 0x5c) || (astcHeader.id[2] != 0xa1) || (astcHeader.id[1] != 0xab) || (astcHeader.id[0] != 0x13))
{
TraceLog(WARNING, "[%s] ASTC file does not seem to be a valid image", fileName);
}
else
{
// NOTE: Assuming Little Endian (could it be wrong?)
- image.width = 0x00000000 | ((int)header.width[2] << 16) | ((int)header.width[1] << 8) | ((int)header.width[0]);
- image.height = 0x00000000 | ((int)header.height[2] << 16) | ((int)header.height[1] << 8) | ((int)header.height[0]);
+ image.width = 0x00000000 | ((int)astcHeader.width[2] << 16) | ((int)astcHeader.width[1] << 8) | ((int)astcHeader.width[0]);
+ image.height = 0x00000000 | ((int)astcHeader.height[2] << 16) | ((int)astcHeader.height[1] << 8) | ((int)astcHeader.height[0]);
// NOTE: ASTC format only contains one mipmap level
image.mipmaps = 1;
TraceLog(DEBUG, "ASTC image width: %i", image.width);
TraceLog(DEBUG, "ASTC image height: %i", image.height);
- TraceLog(DEBUG, "ASTC image blocks: %ix%i", header.blockX, header.blockY);
+ TraceLog(DEBUG, "ASTC image blocks: %ix%i", astcHeader.blockX, astcHeader.blockY);
// NOTE: Each block is always stored in 128bit so we can calculate the bpp
- int bpp = 128/(header.blockX*header.blockY);
+ int bpp = 128/(astcHeader.blockX*astcHeader.blockY);
// NOTE: Currently we only support 2 blocks configurations: 4x4 and 8x8
if ((bpp == 8) || (bpp == 2))
diff --git a/src/utils.c b/src/utils.c
index 640c5720..9a2a723a 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,16 +1,23 @@
/**********************************************************************************************
*
-* raylib.utils
+* raylib.utils - Some common utility functions
*
-* Some utility functions
+* CONFIGURATION:
*
-* External libs:
-* tinfl - zlib DEFLATE algorithm decompression
+* #define SUPPORT_SAVE_PNG
+* Enable saving PNG fileformat
+* NOTE: Requires stb_image_write library
+*
+* #define SUPPORT_SAVE_BMP
+*
+* #define DO_NOT_TRACE_DEBUG_MSGS
+* Avoid showing DEBUG TraceLog() messages
+*
+* DEPENDENCIES:
* stb_image_write - PNG writting functions
*
-* Module Configuration Flags:
-* DO_NOT_TRACE_DEBUG_MSGS - Avoid showing DEBUG TraceLog() messages
*
+* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
*
@@ -42,16 +49,17 @@
#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()
+#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_png()
+ #include "external/stb_image_write.h" // Required for: stbi_write_bmp(), stbi_write_png()
#endif
-#include "external/tinfl.c" // Required for: tinfl_decompress_mem_to_mem()
- // NOTE: DEFLATE algorythm data decompression
+#define RRES_IMPLEMENTATION
+#include "rres.h"
+//#define NO_TRACELOG // Avoid TraceLog() output (any type)
#define DO_NOT_TRACE_DEBUG_MSGS // Avoid DEBUG messages tracing
//----------------------------------------------------------------------------------
@@ -74,143 +82,11 @@ static int android_close(void *cookie);
//----------------------------------------------------------------------------------
// Module Functions Definition - Utilities
//----------------------------------------------------------------------------------
-
-// Data decompression function
-// NOTE: Allocated data MUST be freed!
-unsigned char *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize)
-{
- int tempUncompSize;
- unsigned char *pUncomp;
-
- // Allocate buffer to hold decompressed data
- pUncomp = (mz_uint8 *)malloc((size_t)uncompSize);
-
- // Check correct memory allocation
- if (pUncomp == NULL)
- {
- TraceLog(WARNING, "Out of memory while decompressing data");
- }
- else
- {
- // Decompress data
- tempUncompSize = tinfl_decompress_mem_to_mem(pUncomp, (size_t)uncompSize, data, compSize, 1);
-
- if (tempUncompSize == -1)
- {
- TraceLog(WARNING, "Data decompression failed");
- free(pUncomp);
- }
-
- 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 pUncomp;
-}
-
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)
-// Creates a bitmap (BMP) file from an array of pixel data
-// NOTE: This function is not explicitly available to raylib users
-void WriteBitmap(const char *fileName, unsigned char *imgData, int width, int height)
-{
- int filesize = 54 + 3*width*height;
-
- unsigned char bmpFileHeader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0}; // Standard BMP file header
- unsigned char bmpInfoHeader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0}; // Standard BMP info header
-
- bmpFileHeader[2] = (unsigned char)(filesize);
- bmpFileHeader[3] = (unsigned char)(filesize>>8);
- bmpFileHeader[4] = (unsigned char)(filesize>>16);
- bmpFileHeader[5] = (unsigned char)(filesize>>24);
-
- bmpInfoHeader[4] = (unsigned char)(width);
- bmpInfoHeader[5] = (unsigned char)(width>>8);
- bmpInfoHeader[6] = (unsigned char)(width>>16);
- bmpInfoHeader[7] = (unsigned char)(width>>24);
- bmpInfoHeader[8] = (unsigned char)(height);
- bmpInfoHeader[9] = (unsigned char)(height>>8);
- bmpInfoHeader[10] = (unsigned char)(height>>16);
- bmpInfoHeader[11] = (unsigned char)(height>>24);
-
- FILE *bmpFile = fopen(fileName, "wb"); // Define a pointer to bitmap file and open it in write-binary mode
-
- if (bmpFile == NULL)
- {
- TraceLog(WARNING, "[%s] BMP file could not be created", fileName);
- }
- else
- {
- // NOTE: fwrite parameters are: data pointer, size in bytes of each element to be written, number of elements, file-to-write pointer
- fwrite(bmpFileHeader, sizeof(unsigned char), 14, bmpFile); // Write BMP file header data
- fwrite(bmpInfoHeader, sizeof(unsigned char), 40, bmpFile); // Write BMP info header data
-
- // Write pixel data to file
- for (int y = 0; y < height ; y++)
- {
- for (int x = 0; x < width; x++)
- {
- fputc(imgData[(x*4)+2 + (y*width*4)], bmpFile);
- fputc(imgData[(x*4)+1 + (y*width*4)], bmpFile);
- fputc(imgData[(x*4) + (y*width*4)], bmpFile);
- }
- }
- }
-
- fclose(bmpFile); // Close bitmap file
-}
-
-// Creates a PNG image file from an array of pixel data
-// NOTE: Uses stb_image_write
-void WritePNG(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_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
-// Outputs a trace log message (INFO, ERROR, WARNING)
-// NOTE: If a file has been init, output log is written there
-void TraceLog(int msgType, const char *text, ...)
-{
- va_list args;
- int traceDebugMsgs = 1;
-
-#ifdef DO_NOT_TRACE_DEBUG_MSGS
- traceDebugMsgs = 0;
-#endif
-
- switch(msgType)
- {
- case INFO: fprintf(stdout, "INFO: "); break;
- case ERROR: fprintf(stdout, "ERROR: "); break;
- case WARNING: fprintf(stdout, "WARNING: "); break;
- case DEBUG: if (traceDebugMsgs) fprintf(stdout, "DEBUG: "); break;
- default: break;
- }
-
- if ((msgType != DEBUG) || ((msgType == 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
-
-#if defined(PLATFORM_ANDROID)
+// Outputs a trace log message
void TraceLog(int msgType, const char *text, ...)
{
- static char buffer[100];
+#if !defined(NO_TRACELOG)
+ static char buffer[128];
int traceDebugMsgs = 1;
#ifdef DO_NOT_TRACE_DEBUG_MSGS
@@ -230,8 +106,9 @@ void TraceLog(int msgType, const char *text, ...)
strcat(buffer, "\n");
va_list args;
- va_start(args, buffer);
+ va_start(args, text);
+#if defined(PLATFORM_ANDROID)
switch(msgType)
{
case INFO: __android_log_vprint(ANDROID_LOG_INFO, "raylib", buffer, args); break;
@@ -240,12 +117,32 @@ void TraceLog(int msgType, const char *text, ...)
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 (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)
{
@@ -283,23 +180,6 @@ const char *GetExtension(const char *fileName)
return (dot + 1);
}
-// Calculate next power-of-two value for a given num
-int GetNextPOT(int num)
-{
- if (num != 0)
- {
- num--;
- num |= (num >> 1); // Or first 2 bits
- num |= (num >> 2); // Or next 2 bits
- num |= (num >> 4); // Or next 4 bits
- num |= (num >> 8); // Or next 8 bits
- num |= (num >> 16); // Or next 16 bits
- num++;
- }
-
- return num;
-}
-
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
diff --git a/src/utils.h b/src/utils.h
index 045b0692..3ffd025c 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -31,6 +31,8 @@
#include <android/asset_manager.h> // Required for: AAssetManager
#endif
+#include "rres.h"
+
//----------------------------------------------------------------------------------
// Some basic Defines
//----------------------------------------------------------------------------------
@@ -41,19 +43,8 @@
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
-typedef enum { IMAGE = 0, SOUND, MODEL, TEXT, RAW } DataType;
-
typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
-// One resource info header, every resource includes this header (8 byte)
-typedef struct {
- unsigned short id; // Resource unique identifier (2 byte)
- unsigned char type; // Resource type (1 byte)
- unsigned char comp; // Data Compression and Coding (1 byte)
- unsigned int size; // Data size in .rres file (compressed or not, only DATA) (4 byte)
- unsigned int srcSize; // Source data size (uncompressed, only DATA)
-} ResInfoHeader;
-
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
@@ -66,17 +57,14 @@ extern "C" { // Prevents name mangling of functions
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
-unsigned char *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize);
+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 WriteBitmap(const char *fileName, unsigned char *imgData, int width, int height);
-void WritePNG(const char *fileName, unsigned char *imgData, int width, int height, int compSize);
+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
-void TraceLog(int msgType, const char *text, ...); // Outputs a trace log message
-const char *GetExtension(const char *fileName); // Returns extension of a filename
-int GetNextPOT(int num); // Calculate next power-of-two value for a given num
-
#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()