Update C sources, add new functions

This commit is contained in:
Milan Nikolic 2017-10-26 19:00:27 +02:00
parent 661c7a9f55
commit 0f4ce7d6d9
30 changed files with 8465 additions and 2315 deletions

View file

@ -69,6 +69,7 @@
#define SUPPORT_FILEFORMAT_WAV
#define SUPPORT_FILEFORMAT_OGG
#define SUPPORT_FILEFORMAT_XM
#define SUPPORT_FILEFORMAT_MOD
//-------------------------------------------------
#if defined(AUDIO_STANDALONE)
@ -79,7 +80,7 @@
#include "utils.h" // Required for: fopen() Android mapping
#endif
#ifdef __APPLE__
#if defined(__APPLE__)
#include "OpenAL/al.h" // OpenAL basic header
#include "OpenAL/alc.h" // OpenAL context header (like OpenGL, OpenAL requires a context to work)
#else
@ -170,7 +171,7 @@ typedef struct MusicData {
} MusicData;
#if defined(AUDIO_STANDALONE)
typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
typedef enum { LOG_INFO = 0, LOG_ERROR, LOG_WARNING, LOG_DEBUG, LOG_OTHER } TraceLogType;
#endif
//----------------------------------------------------------------------------------
@ -193,7 +194,7 @@ static Wave LoadFLAC(const char *fileName); // Load FLAC file
#if defined(AUDIO_STANDALONE)
bool IsFileExtension(const char *fileName, const char *ext); // Check file extension
void TraceLog(int msgType, const char *text, ...); // Outputs trace log message (INFO, ERROR, WARNING)
void TraceLog(int msgType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
#endif
//----------------------------------------------------------------------------------
@ -206,7 +207,7 @@ void InitAudioDevice(void)
// Open and initialize a device with default settings
ALCdevice *device = alcOpenDevice(NULL);
if (!device) TraceLog(ERROR, "Audio device could not be opened");
if (!device) TraceLog(LOG_ERROR, "Audio device could not be opened");
else
{
ALCcontext *context = alcCreateContext(device, NULL);
@ -217,11 +218,11 @@ void InitAudioDevice(void)
alcCloseDevice(device);
TraceLog(ERROR, "Could not initialize audio context");
TraceLog(LOG_ERROR, "Could not initialize audio context");
}
else
{
TraceLog(INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER));
TraceLog(LOG_INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER));
// Listener definition (just for 2D)
alListener3f(AL_POSITION, 0.0f, 0.0f, 0.0f);
@ -239,7 +240,7 @@ void CloseAudioDevice(void)
ALCdevice *device;
ALCcontext *context = alcGetCurrentContext();
if (context == NULL) TraceLog(WARNING, "Could not get current audio context for closing");
if (context == NULL) TraceLog(LOG_WARNING, "Could not get current audio context for closing");
device = alcGetContextsDevice(context);
@ -247,7 +248,7 @@ void CloseAudioDevice(void)
alcDestroyContext(context);
alcCloseDevice(device);
TraceLog(INFO, "Audio device closed successfully");
TraceLog(LOG_INFO, "Audio device closed successfully");
}
// Check if device has been initialized successfully
@ -298,12 +299,12 @@ Wave LoadWave(const char *fileName)
// 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);
else TraceLog(LOG_WARNING, "[%s] Resource file does not contain wave data", fileName);
UnloadResource(rres);
}
#endif
else TraceLog(WARNING, "[%s] Audio fileformat not supported, it can't be loaded", fileName);
else TraceLog(LOG_WARNING, "[%s] Audio fileformat not supported, it can't be loaded", fileName);
return wave;
}
@ -358,7 +359,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; // Requires OpenAL extension: AL_EXT_FLOAT32
default: TraceLog(WARNING, "Wave sample size not supported: %i", wave.sampleSize); break;
default: TraceLog(LOG_WARNING, "Wave sample size not supported: %i", wave.sampleSize); break;
}
}
else if (wave.channels == 2)
@ -368,10 +369,10 @@ 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; // Requires OpenAL extension: AL_EXT_FLOAT32
default: TraceLog(WARNING, "Wave sample size not supported: %i", wave.sampleSize); break;
default: TraceLog(LOG_WARNING, "Wave sample size not supported: %i", wave.sampleSize); break;
}
}
else TraceLog(WARNING, "Wave number of channels not supported: %i", wave.channels);
else TraceLog(LOG_WARNING, "Wave number of channels not supported: %i", wave.channels);
// Create an audio source
ALuint source;
@ -396,7 +397,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 (%i Hz, %i bit, %s)", source, buffer, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo");
TraceLog(LOG_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;
@ -411,7 +412,7 @@ void UnloadWave(Wave wave)
{
if (wave.data != NULL) free(wave.data);
TraceLog(INFO, "Unloaded wave data from RAM");
TraceLog(LOG_INFO, "Unloaded wave data from RAM");
}
// Unload sound
@ -422,7 +423,7 @@ void UnloadSound(Sound sound)
alDeleteSources(1, &sound.source);
alDeleteBuffers(1, &sound.buffer);
TraceLog(INFO, "[SND ID %i][BUFR ID %i] Unloaded sound data from RAM", sound.source, sound.buffer);
TraceLog(LOG_INFO, "[SND ID %i][BUFR ID %i] Unloaded sound data from RAM", sound.source, sound.buffer);
}
// Update sound buffer with new data
@ -434,9 +435,9 @@ void UpdateSound(Sound sound, const void *data, int samplesCount)
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);
TraceLog(LOG_DEBUG, "UpdateSound() : AL_FREQUENCY: %i", sampleRate);
TraceLog(LOG_DEBUG, "UpdateSound() : AL_BITS: %i", sampleSize);
TraceLog(LOG_DEBUG, "UpdateSound() : AL_CHANNELS: %i", channels);
unsigned int dataSize = samplesCount*channels*sampleSize/8; // Size of data in bytes
@ -457,7 +458,7 @@ void PlaySound(Sound sound)
{
alSourcePlay(sound.source); // Play the sound
//TraceLog(INFO, "Playing sound");
//TraceLog(LOG_INFO, "Playing sound");
// Find the current position of the sound being played
// NOTE: Only work when the entire file is in a single buffer
@ -570,7 +571,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels)
// NOTE: Only supported mono <--> stereo
if (wave->channels != channels)
{
void *data = malloc(wave->sampleCount*channels*wave->sampleSize/8);
void *data = malloc(wave->sampleCount*wave->sampleSize/8*channels);
if ((wave->channels == 1) && (channels == 2)) // mono ---> stereo (duplicate mono information)
{
@ -607,7 +608,7 @@ Wave WaveCopy(Wave wave)
{
Wave newWave = { 0 };
newWave.data = malloc(wave.sampleCount*wave.channels*wave.sampleSize/8);
newWave.data = malloc(wave.sampleCount*wave.sampleSize/8*wave.channels);
if (newWave.data != NULL)
{
@ -632,14 +633,14 @@ void WaveCrop(Wave *wave, int initSample, int finalSample)
{
int sampleCount = finalSample - initSample;
void *data = malloc(sampleCount*wave->channels*wave->sampleSize/8);
void *data = malloc(sampleCount*wave->sampleSize/8*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");
else TraceLog(LOG_WARNING, "Wave crop range out of bounds");
}
// Get samples data from wave as a floats array
@ -675,7 +676,7 @@ Music LoadMusicStream(const char *fileName)
// Open ogg audio stream
music->ctxOgg = stb_vorbis_open_filename(fileName, NULL, NULL);
if (music->ctxOgg == NULL) TraceLog(WARNING, "[%s] OGG audio file could not be opened", fileName);
if (music->ctxOgg == NULL) TraceLog(LOG_WARNING, "[%s] OGG audio file could not be opened", fileName);
else
{
stb_vorbis_info info = stb_vorbis_get_info(music->ctxOgg); // Get Ogg file info
@ -687,10 +688,10 @@ Music LoadMusicStream(const char *fileName)
music->ctxType = MUSIC_AUDIO_OGG;
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);
TraceLog(LOG_DEBUG, "[%s] FLAC total samples: %i", fileName, music->totalSamples);
TraceLog(LOG_DEBUG, "[%s] OGG sample rate: %i", fileName, info.sample_rate);
TraceLog(LOG_DEBUG, "[%s] OGG channels: %i", fileName, info.channels);
TraceLog(LOG_DEBUG, "[%s] OGG memory required: %i", fileName, info.temp_memory_required);
}
}
#if defined(SUPPORT_FILEFORMAT_FLAC)
@ -698,7 +699,7 @@ Music LoadMusicStream(const char *fileName)
{
music->ctxFlac = drflac_open_file(fileName);
if (music->ctxFlac == NULL) TraceLog(WARNING, "[%s] FLAC audio file could not be opened", fileName);
if (music->ctxFlac == NULL) TraceLog(LOG_WARNING, "[%s] FLAC audio file could not be opened", fileName);
else
{
music->stream = InitAudioStream(music->ctxFlac->sampleRate, music->ctxFlac->bitsPerSample, music->ctxFlac->channels);
@ -707,10 +708,10 @@ Music LoadMusicStream(const char *fileName)
music->ctxType = MUSIC_AUDIO_FLAC;
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);
TraceLog(LOG_DEBUG, "[%s] FLAC total samples: %i", fileName, music->totalSamples);
TraceLog(LOG_DEBUG, "[%s] FLAC sample rate: %i", fileName, music->ctxFlac->sampleRate);
TraceLog(LOG_DEBUG, "[%s] FLAC bits per sample: %i", fileName, music->ctxFlac->bitsPerSample);
TraceLog(LOG_DEBUG, "[%s] FLAC channels: %i", fileName, music->ctxFlac->channels);
}
}
#endif
@ -730,10 +731,10 @@ Music LoadMusicStream(const char *fileName)
music->ctxType = MUSIC_MODULE_XM;
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);
TraceLog(LOG_DEBUG, "[%s] XM number of samples: %i", fileName, music->totalSamples);
TraceLog(LOG_DEBUG, "[%s] XM track length: %11.6f sec", fileName, (float)music->totalSamples/48000.0f);
}
else TraceLog(WARNING, "[%s] XM file could not be opened", fileName);
else TraceLog(LOG_WARNING, "[%s] XM file could not be opened", fileName);
}
#endif
#if defined(SUPPORT_FILEFORMAT_MOD)
@ -749,13 +750,13 @@ Music LoadMusicStream(const char *fileName)
music->ctxType = MUSIC_MODULE_MOD;
music->loopCount = -1; // Infinite loop by default
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);
TraceLog(LOG_DEBUG, "[%s] MOD number of samples: %i", fileName, music->samplesLeft);
TraceLog(LOG_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);
else TraceLog(LOG_WARNING, "[%s] MOD file could not be opened", fileName);
}
#endif
else TraceLog(WARNING, "[%s] Audio fileformat not supported, it can't be loaded", fileName);
else TraceLog(LOG_WARNING, "[%s] Audio fileformat not supported, it can't be loaded", fileName);
return music;
}
@ -797,23 +798,32 @@ void ResumeMusicStream(Music music)
ALenum state;
alGetSourcei(music->stream.source, AL_SOURCE_STATE, &state);
if (state == AL_PAUSED) alSourcePlay(music->stream.source);
if (state == AL_PAUSED)
{
TraceLog(LOG_INFO, "[AUD ID %i] Resume music stream playing", music->stream.source);
alSourcePlay(music->stream.source);
}
}
// Stop music playing (close stream)
// TODO: To clear a buffer, make sure they have been already processed!
void StopMusicStream(Music music)
{
alSourceStop(music->stream.source);
/*
// Clear stream buffers
// WARNING: Queued buffers must have been processed before unqueueing and reloaded with data!!!
void *pcm = calloc(AUDIO_BUFFER_SIZE*music->stream.sampleSize/8*music->stream.channels, 1);
for (int i = 0; i < MAX_STREAM_BUFFERS; i++)
{
//UpdateAudioStream(music->stream, pcm, AUDIO_BUFFER_SIZE); // Update one buffer at a time
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)
@ -846,14 +856,14 @@ void UpdateMusicStream(Music music)
if (processed > 0)
{
bool active = true;
bool streamEnding = false;
// 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);
void *pcm = calloc(AUDIO_BUFFER_SIZE*music->stream.sampleSize/8*music->stream.channels, 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
// individual L or R for ogg shorts
for (int i = 0; i < numBuffersToProcess; i++)
{
@ -891,16 +901,16 @@ void UpdateMusicStream(Music music)
if (music->samplesLeft <= 0)
{
active = false;
streamEnding = true;
break;
}
}
// This error is registered when UpdateAudioStream() fails
if (alGetError() == AL_INVALID_VALUE) TraceLog(WARNING, "OpenAL: Error buffering data...");
// Free allocated pcm data
free(pcm);
// Reset audio stream for looping
if (!active)
if (streamEnding)
{
StopMusicStream(music); // Stop music (and reset)
@ -917,8 +927,6 @@ void UpdateMusicStream(Music music)
// just make sure to play again on window restore
if (state != AL_PLAYING) PlayMusicStream(music);
}
free(pcm);
}
}
@ -985,7 +993,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
if ((channels > 0) && (channels < 3)) stream.channels = channels;
else
{
TraceLog(WARNING, "Init audio stream: Number of channels not supported: %i", channels);
TraceLog(LOG_WARNING, "Init audio stream: Number of channels not supported: %i", channels);
stream.channels = 1; // Fallback to mono channel
}
@ -997,7 +1005,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
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; // Requires OpenAL extension: AL_EXT_FLOAT32
default: TraceLog(WARNING, "Init audio stream: Sample size not supported: %i", sampleSize); break;
default: TraceLog(LOG_WARNING, "Init audio stream: Sample size not supported: %i", sampleSize); break;
}
}
else if (stream.channels == 2)
@ -1007,7 +1015,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
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; // Requires OpenAL extension: AL_EXT_FLOAT32
default: TraceLog(WARNING, "Init audio stream: Sample size not supported: %i", sampleSize); break;
default: TraceLog(LOG_WARNING, "Init audio stream: Sample size not supported: %i", sampleSize); break;
}
}
@ -1034,7 +1042,7 @@ AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize, un
alSourceQueueBuffers(stream.source, MAX_STREAM_BUFFERS, stream.buffers);
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");
TraceLog(LOG_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;
}
@ -1061,11 +1069,12 @@ void CloseAudioStream(AudioStream stream)
alDeleteSources(1, &stream.source);
alDeleteBuffers(MAX_STREAM_BUFFERS, stream.buffers);
TraceLog(INFO, "[AUD ID %i] Unloaded audio stream data", stream.source);
TraceLog(LOG_INFO, "[AUD ID %i] Unloaded audio stream data", stream.source);
}
// Update audio stream buffers with data
// NOTE: Only updates one buffer per call
// NOTE 1: Only updates one buffer of the stream source: unqueue -> update -> queue
// NOTE 2: To unqueue a buffer it needs to be processed: IsAudioBufferProcessed()
void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
{
ALuint buffer = 0;
@ -1074,9 +1083,10 @@ void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount)
// Check if any buffer was available for unqueue
if (alGetError() != AL_INVALID_VALUE)
{
alBufferData(buffer, stream.format, data, samplesCount*stream.channels*stream.sampleSize/8, stream.sampleRate);
alBufferData(buffer, stream.format, data, samplesCount*stream.sampleSize/8*stream.channels, stream.sampleRate);
alSourceQueueBuffers(stream.source, 1, &buffer);
}
else TraceLog(LOG_WARNING, "[AUD ID %i] Audio buffer not available for unqueuing", stream.source);
}
// Check if any audio stream buffers requires refill
@ -1159,7 +1169,7 @@ static Wave LoadWAV(const char *fileName)
if (wavFile == NULL)
{
TraceLog(WARNING, "[%s] WAV file could not be opened", fileName);
TraceLog(LOG_WARNING, "[%s] WAV file could not be opened", fileName);
wave.data = NULL;
}
else
@ -1171,7 +1181,7 @@ static Wave LoadWAV(const char *fileName)
if (strncmp(wavRiffHeader.chunkID, "RIFF", 4) ||
strncmp(wavRiffHeader.format, "WAVE", 4))
{
TraceLog(WARNING, "[%s] Invalid RIFF or WAVE Header", fileName);
TraceLog(LOG_WARNING, "[%s] Invalid RIFF or WAVE Header", fileName);
}
else
{
@ -1182,7 +1192,7 @@ static Wave LoadWAV(const char *fileName)
if ((wavFormat.subChunkID[0] != 'f') || (wavFormat.subChunkID[1] != 'm') ||
(wavFormat.subChunkID[2] != 't') || (wavFormat.subChunkID[3] != ' '))
{
TraceLog(WARNING, "[%s] Invalid Wave format", fileName);
TraceLog(LOG_WARNING, "[%s] Invalid Wave format", fileName);
}
else
{
@ -1196,7 +1206,7 @@ static Wave LoadWAV(const char *fileName)
if ((wavData.subChunkID[0] != 'd') || (wavData.subChunkID[1] != 'a') ||
(wavData.subChunkID[2] != 't') || (wavData.subChunkID[3] != 'a'))
{
TraceLog(WARNING, "[%s] Invalid data header", fileName);
TraceLog(LOG_WARNING, "[%s] Invalid data header", fileName);
}
else
{
@ -1214,7 +1224,7 @@ static Wave LoadWAV(const char *fileName)
// 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);
TraceLog(LOG_WARNING, "[%s] WAV sample size (%ibit) not supported, converted to 16bit", fileName, wave.sampleSize);
WaveFormat(&wave, wave.sampleRate, 16, wave.channels);
}
@ -1222,13 +1232,13 @@ static Wave LoadWAV(const char *fileName)
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);
TraceLog(LOG_WARNING, "[%s] WAV channels number (%i) not supported, converted to 2 channels", fileName, wave.channels);
}
// NOTE: subChunkSize comes in bytes, we need to translate it to number of samples
wave.sampleCount = (wavData.subChunkSize/(wave.sampleSize/8))/wave.channels;
TraceLog(INFO, "[%s] WAV file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo");
TraceLog(LOG_INFO, "[%s] WAV file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo");
}
}
}
@ -1245,35 +1255,31 @@ static Wave LoadWAV(const char *fileName)
// NOTE: Using stb_vorbis library
static Wave LoadOGG(const char *fileName)
{
Wave wave;
Wave wave = { 0 };
stb_vorbis *oggFile = stb_vorbis_open_filename(fileName, NULL, NULL);
if (oggFile == NULL)
{
TraceLog(WARNING, "[%s] OGG file could not be opened", fileName);
wave.data = NULL;
}
if (oggFile == NULL) TraceLog(LOG_WARNING, "[%s] OGG file could not be opened", fileName);
else
{
stb_vorbis_info info = stb_vorbis_get_info(oggFile);
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);
wave.sampleCount = (int)stb_vorbis_stream_length_in_samples(oggFile); // Independent by channel
float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile);
if (totalSeconds > 10) TraceLog(WARNING, "[%s] Ogg audio length is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds);
if (totalSeconds > 10) TraceLog(LOG_WARNING, "[%s] Ogg audio length is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds);
wave.data = (short *)malloc(wave.sampleCount*wave.channels*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);
TraceLog(DEBUG, "[%s] Samples obtained: %i", fileName, numSamplesOgg);
TraceLog(LOG_DEBUG, "[%s] Samples obtained: %i", fileName, numSamplesOgg);
TraceLog(INFO, "[%s] OGG file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo");
TraceLog(LOG_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);
}
@ -1297,10 +1303,10 @@ static Wave LoadFLAC(const char *fileName)
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.channels > 2) TraceLog(LOG_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");
if (wave.data == NULL) TraceLog(LOG_WARNING, "[%s] FLAC data could not be loaded", fileName);
else TraceLog(LOG_INFO, "[%s] FLAC file loaded successfully (%i Hz, %i bit, %s)", fileName, wave.sampleRate, wave.sampleSize, (wave.channels == 1) ? "Mono" : "Stereo");
return wave;
}
@ -1322,35 +1328,26 @@ bool IsFileExtension(const char *fileName, const char *ext)
return result;
}
// Outputs a trace log message (INFO, ERROR, WARNING)
// NOTE: If a file has been init, output log is written there
// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
void TraceLog(int msgType, const char *text, ...)
{
va_list args;
int traceDebugMsgs = 0;
#ifdef DO_NOT_TRACE_DEBUG_MSGS
traceDebugMsgs = 0;
#endif
va_start(args, text);
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;
case LOG_INFO: fprintf(stdout, "INFO: "); break;
case LOG_ERROR: fprintf(stdout, "ERROR: "); break;
case LOG_WARNING: fprintf(stdout, "WARNING: "); break;
case LOG_DEBUG: fprintf(stdout, "DEBUG: "); break;
default: break;
}
if ((msgType != DEBUG) || ((msgType == DEBUG) && (traceDebugMsgs)))
{
va_start(args, text);
vfprintf(stdout, text, args);
va_end(args);
vfprintf(stdout, text, args);
fprintf(stdout, "\n");
fprintf(stdout, "\n");
}
va_end(args);
if (msgType == ERROR) exit(1); // If ERROR message, exit program
if (msgType == LOG_ERROR) exit(1);
}
#endif

View file

@ -181,7 +181,14 @@ void SetCameraMoveControls(int frontKey, int backKey,
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Camera move modes (first person and third person cameras)
typedef enum { MOVE_FRONT = 0, MOVE_BACK, MOVE_RIGHT, MOVE_LEFT, MOVE_UP, MOVE_DOWN } CameraMove;
typedef enum {
MOVE_FRONT = 0,
MOVE_BACK,
MOVE_RIGHT,
MOVE_LEFT,
MOVE_UP,
MOVE_DOWN
} CameraMove;
//----------------------------------------------------------------------------------
// Global Variables Definition
@ -203,15 +210,14 @@ static int cameraMode = CAMERA_CUSTOM; // Current camera mode
#if defined(CAMERA_STANDALONE)
// NOTE: Camera controls depend on some raylib input functions
// TODO: Set your own input functions (used in UpdateCamera())
static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; }
static void SetMousePosition(Vector2 pos) {}
static void EnableCursor() {} // Unlock cursor
static void DisableCursor() {} // Lock cursor
static int IsKeyDown(int key) { return 0; }
static int IsMouseButtonDown(int button) { return 0;}
static int GetMouseWheelMove() { return 0; }
static int GetScreenWidth() { return 1280; }
static int GetScreenHeight() { return 720; }
static void ShowCursor() {}
static void HideCursor() {}
static int IsKeyDown(int key) { return 0; }
static Vector2 GetMousePosition() { return (Vector2){ 0.0f, 0.0f }; }
#endif
//----------------------------------------------------------------------------------
@ -242,18 +248,23 @@ void SetCameraMode(Camera camera, int mode)
cameraAngle.y = -asinf(fabsf(dy)/distance.y); // Camera angle in plane XY (0 aligned with X, move positive CW)
// NOTE: Just testing what cameraAngle means
//cameraAngle.x = 0.0f*DEG2RAD; // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
//cameraAngle.x = 0.0f*DEG2RAD; // Camera angle in plane XZ (0 aligned with Z, move positive CCW)
//cameraAngle.y = -60.0f*DEG2RAD; // Camera angle in plane XY (0 aligned with X, move positive CW)
playerEyesPosition = camera.position.y;
// Lock cursor for first person and third person cameras
if ((mode == CAMERA_FIRST_PERSON) ||
(mode == CAMERA_THIRD_PERSON)) DisableCursor();
else EnableCursor();
cameraMode = mode;
}
// Update camera depending on selected mode
// NOTE: Camera controls depend on some raylib functions:
// Mouse: GetMousePosition(), SetMousePosition(), IsMouseButtonDown(), GetMouseWheelMove()
// System: GetScreenWidth(), GetScreenHeight(), ShowCursor(), HideCursor()
// System: EnableCursor(), DisableCursor()
// Mouse: IsMouseButtonDown(), GetMousePosition(), GetMouseWheelMove()
// Keys: IsKeyDown()
// TODO: Port to quaternion-based camera
void UpdateCamera(Camera *camera)
@ -284,36 +295,10 @@ void UpdateCamera(Camera *camera)
if (cameraMode != CAMERA_CUSTOM)
{
// Get screen size
int screenWidth = GetScreenWidth();
int screenHeight = GetScreenHeight();
if ((cameraMode == CAMERA_FIRST_PERSON) ||
(cameraMode == CAMERA_THIRD_PERSON))
{
HideCursor();
mousePositionDelta.x = mousePosition.x - previousMousePosition.x;
mousePositionDelta.y = mousePosition.y - previousMousePosition.y;
if (mousePosition.x < (float)screenHeight/3.0f) SetMousePosition((Vector2){ screenWidth - screenHeight/3, mousePosition.y });
else if (mousePosition.y < (float)screenHeight/3.0f) SetMousePosition((Vector2){ mousePosition.x, screenHeight - screenHeight/3 });
else if (mousePosition.x > (screenWidth - (float)screenHeight/3.0f)) SetMousePosition((Vector2){ screenHeight/3, mousePosition.y });
else if (mousePosition.y > (screenHeight - (float)screenHeight/3.0f)) SetMousePosition((Vector2){ mousePosition.x, screenHeight/3 });
else
{
mousePositionDelta.x = mousePosition.x - previousMousePosition.x;
mousePositionDelta.y = mousePosition.y - previousMousePosition.y;
}
}
else // CAMERA_FREE, CAMERA_ORBITAL
{
ShowCursor();
mousePositionDelta.x = mousePosition.x - previousMousePosition.x;
mousePositionDelta.y = mousePosition.y - previousMousePosition.y;
}
// NOTE: We GetMousePosition() again because it can be modified by a previous SetMousePosition() call
// If using directly mousePosition variable we have problems on CAMERA_FIRST_PERSON and CAMERA_THIRD_PERSON
previousMousePosition = GetMousePosition();
previousMousePosition = mousePosition;
}
// Support for multiple automatic camera modes

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,6 @@ import "C"
import (
"io"
"reflect"
"unsafe"
)
@ -480,6 +479,13 @@ func SetWindowIcon(image Image) {
C.SetWindowIcon(*cimage)
}
// SetWindowTitle - Set title for window (only PLATFORM_DESKTOP)
func SetWindowTitle(title string) {
ctitle := C.CString(title)
defer C.free(unsafe.Pointer(ctitle))
C.SetWindowTitle(ctitle)
}
// SetWindowPosition - Set window position on screen (only PLATFORM_DESKTOP)
func SetWindowPosition(x, y int32) {
cx := (C.int)(x)
@ -620,48 +626,51 @@ func GetHexValue(color Color) int32 {
// ColorToFloat - Converts Color to float array and normalizes
func ColorToFloat(color Color) []float32 {
ccolor := color.cptr()
ret := C.ColorToFloat(*ccolor)
var data []float32
sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&data)))
sliceHeader.Cap = 4
sliceHeader.Len = 4
sliceHeader.Data = uintptr(unsafe.Pointer(ret))
data := make([]float32, 0)
data[0] = float32(color.R) / 255
data[0] = float32(color.G) / 255
data[0] = float32(color.B) / 255
data[0] = float32(color.A) / 255
return data
}
// VectorToFloat - Converts Vector3 to float array
func VectorToFloat(vec Vector3) []float32 {
cvec := vec.cptr()
ret := C.VectorToFloat(*cvec)
var data []float32
sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&data)))
sliceHeader.Cap = 3
sliceHeader.Len = 3
sliceHeader.Data = uintptr(unsafe.Pointer(ret))
data := make([]float32, 0)
data[0] = vec.X
data[1] = vec.Y
data[2] = vec.Z
return data
}
// MatrixToFloat - Converts Matrix to float array
func MatrixToFloat(mat Matrix) []float32 {
cmat := mat.cptr()
ret := C.MatrixToFloat(*cmat)
data := make([]float32, 0)
var data []float32
sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&data)))
sliceHeader.Cap = 16
sliceHeader.Len = 16
sliceHeader.Data = uintptr(unsafe.Pointer(ret))
data[0] = mat.M0
data[1] = mat.M4
data[2] = mat.M8
data[3] = mat.M12
data[4] = mat.M1
data[5] = mat.M5
data[6] = mat.M9
data[7] = mat.M13
data[8] = mat.M2
data[9] = mat.M6
data[10] = mat.M10
data[11] = mat.M14
data[12] = mat.M3
data[13] = mat.M7
data[14] = mat.M11
data[15] = mat.M15
return data
}
// GetRandomValue - Returns a random value between min and max (both included)
func GetRandomValue(min int32, max int32) int32 {
func GetRandomValue(min, max int32) int32 {
cmin := (C.int)(min)
cmax := (C.int)(max)
ret := C.GetRandomValue(cmin, cmax)
@ -689,13 +698,15 @@ func SetConfigFlags(flags byte) {
C.SetConfigFlags(cflags)
}
// TakeScreenshot - Takes a screenshot and saves it in the same folder as executable
func TakeScreenshot() {
C.TakeScreenshot()
// TakeScreenshot - Takes a screenshot of current screen (saved a .png)
func TakeScreenshot(name string) {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
C.TakeScreenshot(cname)
}
// StorageSaveValue - Storage save integer value (to defined position)
func StorageSaveValue(position int32, value int32) {
func StorageSaveValue(position, value int32) {
cposition := (C.int)(position)
cvalue := (C.int)(value)
C.StorageSaveValue(cposition, cvalue)
@ -781,7 +792,7 @@ func GetGamepadName(gamepad int32) string {
}
// IsGamepadButtonPressed - Detect if a gamepad button has been pressed once
func IsGamepadButtonPressed(gamepad int32, button int32) bool {
func IsGamepadButtonPressed(gamepad, button int32) bool {
cgamepad := (C.int)(gamepad)
cbutton := (C.int)(button)
ret := C.IsGamepadButtonPressed(cgamepad, cbutton)
@ -790,7 +801,7 @@ func IsGamepadButtonPressed(gamepad int32, button int32) bool {
}
// IsGamepadButtonDown - Detect if a gamepad button is being pressed
func IsGamepadButtonDown(gamepad int32, button int32) bool {
func IsGamepadButtonDown(gamepad, button int32) bool {
cgamepad := (C.int)(gamepad)
cbutton := (C.int)(button)
ret := C.IsGamepadButtonDown(cgamepad, cbutton)
@ -799,7 +810,7 @@ func IsGamepadButtonDown(gamepad int32, button int32) bool {
}
// IsGamepadButtonReleased - Detect if a gamepad button has been released once
func IsGamepadButtonReleased(gamepad int32, button int32) bool {
func IsGamepadButtonReleased(gamepad, button int32) bool {
cgamepad := (C.int)(gamepad)
cbutton := (C.int)(button)
ret := C.IsGamepadButtonReleased(cgamepad, cbutton)
@ -808,7 +819,7 @@ func IsGamepadButtonReleased(gamepad int32, button int32) bool {
}
// IsGamepadButtonUp - Detect if a gamepad button is NOT being pressed
func IsGamepadButtonUp(gamepad int32, button int32) bool {
func IsGamepadButtonUp(gamepad, button int32) bool {
cgamepad := (C.int)(gamepad)
cbutton := (C.int)(button)
ret := C.IsGamepadButtonUp(cgamepad, cbutton)
@ -832,7 +843,7 @@ func GetGamepadAxisCount(gamepad int32) int32 {
}
// GetGamepadAxisMovement - Return axis movement value for a gamepad axis
func GetGamepadAxisMovement(gamepad int32, axis int32) float32 {
func GetGamepadAxisMovement(gamepad, axis int32) float32 {
cgamepad := (C.int)(gamepad)
caxis := (C.int)(axis)
ret := C.GetGamepadAxisMovement(cgamepad, caxis)

2050
raylib/external/par_shapes.h vendored Normal file

File diff suppressed because it is too large Load diff

913
raylib/external/rgif.h vendored Normal file
View file

@ -0,0 +1,913 @@
/**********************************************************************************************
*
* rgif.h original implementation by Charlie Tangora [ctangora -at- gmail -dot- com]
* adapted to C99, reformatted and renamed by Ramon Santamaria (@raysan5)
*
* This file offers a simple, very limited way to create animated GIFs directly in code.
*
* Those looking for particular cleverness are likely to be disappointed; it's pretty
* much a straight-ahead implementation of the GIF format with optional Floyd-Steinberg
* dithering. (It does at least use delta encoding - only the changed portions of each
* frame are saved.)
*
* So resulting files are often quite large. The hope is that it will be handy nonetheless
* as a quick and easily-integrated way for programs to spit out animations.
*
* Only RGBA8 is currently supported as an input format. (The alpha is ignored.)
*
* CONFIGURATION:
*
* #define RGIF_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.
*
* USAGE:
* 1) Create a GifWriter struct. Pass it to GifBegin() to initialize and write the header.
* 2) Pass subsequent frames to GifWriteFrame().
* 3) Finally, call GifEnd() to close the file handle and free memory.
*
*
* LICENSE: public domain (www.unlicense.org)
*
* This is free and unencumbered software released into the public domain.
* Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
* software, either in source code form or as a compiled binary, for any purpose,
* commercial or non-commercial, and by any means.
*
* In jurisdictions that recognize copyright laws, the author or authors of this
* software dedicate any and all copyright interest in the software to the public
* domain. We make this dedication for the benefit of the public at large and to
* the detriment of our heirs and successors. We intend this dedication to be an
* overt act of relinquishment in perpetuity of all present and future rights to
* this software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**********************************************************************************************/
#ifndef GIF_H
#define GIF_H
#include <stdio.h> // Required for: FILE
//#define RGIF_STATIC
#ifdef RGIF_STATIC
#define RGIFDEF static // Functions just visible to module including this file
#else
#ifdef __cplusplus
#define RGIFDEF extern "C" // Functions visible from other files (no name mangling of functions in C++)
#else
#define RGIFDEF extern // Functions visible from other files
#endif
#endif
//----------------------------------------------------------------------------------
// Module Functions Declaration
//----------------------------------------------------------------------------------
// NOTE: By default use bitDepth = 8, dither = false
RGIFDEF bool GifBegin(const char *filename, unsigned int width, unsigned int height, unsigned int delay, unsigned int bitDepth, bool dither);
RGIFDEF bool GifWriteFrame(const unsigned char *image, unsigned int width, unsigned int height, unsigned int delay, int bitDepth, bool dither);
RGIFDEF bool GifEnd();
#endif // GIF_H
/***********************************************************************************
*
* GIF IMPLEMENTATION
*
************************************************************************************/
#if defined(RGIF_IMPLEMENTATION)
#include <stdio.h> // Required for: FILE, fopen(), fclose()
#include <string.h> // Required for: memcpy()
// Define these macros to hook into a custom memory allocator.
// GIF_TEMP_MALLOC and GIF_TEMP_FREE will only be called in stack fashion - frees in the reverse order of mallocs
// and any temp memory allocated by a function will be freed before it exits.
#if !defined(GIF_TEMP_MALLOC)
#include <stdlib.h>
#define GIF_TEMP_MALLOC malloc
#define GIF_TEMP_FREE free
#endif
// Check if custom malloc/free functions defined, if not, using standard ones
// GIF_MALLOC and GIF_FREE are used only by GifBegin and GifEnd respectively,
// to allocate a buffer the size of the image, which is used to find changed pixels for delta-encoding.
#if !defined(GIF_MALLOC)
#include <stdlib.h> // Required for: malloc(), free()
#define GIF_MALLOC(size) malloc(size)
#define GIF_FREE(ptr) free(ptr)
#endif
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define GIFMIN(a, b) (((a)<(b))?(a):(b))
#define GIFMAX(a, b) (((a)>(b))?(a):(b))
#define GIFABS(x) ((x)<0?-(x):(x))
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Gif palette structure
typedef struct GifPalette {
int bitDepth;
unsigned char r[256];
unsigned char g[256];
unsigned char b[256];
// k-d tree over RGB space, organized in heap fashion
// i.e. left child of node i is node i*2, right child is node i*2 + 1
// nodes 256-511 are implicitly the leaves, containing a color
unsigned char treeSplitElt[255];
unsigned char treeSplit[255];
} GifPalette;
// Simple structure to write out the LZW-compressed
// portion of the imageone bit at a time
typedef struct GifBitStatus {
unsigned char bitIndex; // how many bits in the partial byte written so far
unsigned char byte; // current partial byte
unsigned int chunkIndex;
unsigned char chunk[256]; // bytes are written in here until we have 256 of them, then written to the file
} GifBitStatus;
// The LZW dictionary is a 256-ary tree constructed
// as the file is encoded, this is one node
typedef struct GifLzwNode {
uint16_t m_next[256];
} GifLzwNode;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
const int gifTransparentIndex = 0; // Transparent color index
static FILE *gifFile;
unsigned char *gifFrame;
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
static void GifGetClosestPaletteColor(GifPalette *pPal, int r, int g, int b, int *bestInd, int *bestDiff, int treeRoot);
static void GifSwapPixels(unsigned char *image, int pixA, int pixB);
static int GifPartition(unsigned char *image, const int left, const int right, const int elt, int pivotIndex);
static void GifPartitionByMedian(unsigned char *image, int left, int right, int com, int neededCenter);
static void GifSplitPalette(unsigned char *image, int numPixels, int firstElt, int lastElt, int splitElt, int splitDist, int treeNode, bool buildForDither, GifPalette *pal);
static int GifPickChangedPixels(const unsigned char *lastFrame, unsigned char *frame, int numPixels);
static void GifMakePalette(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned int width, unsigned int height, int bitDepth, bool buildForDither, GifPalette *pPal);
static void GifDitherImage(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned char *outFrame, unsigned int width, unsigned int height, GifPalette *pPal);
static void GifThresholdImage(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned char *outFrame, unsigned int width, unsigned int height, GifPalette *pPal);
static void GifWriteBit(GifBitStatus *stat, unsigned int bit);
static void GifWriteChunk(FILE *f, GifBitStatus *stat);
static void GifWriteCode(FILE *f, GifBitStatus *stat, unsigned int code, unsigned int length);
static void GifWritePalette(const GifPalette *pPal, FILE *f);
static void GifWriteLzwImage(FILE *f, unsigned char *image, unsigned int left, unsigned int top, unsigned int width, unsigned int height, unsigned int delay, GifPalette *pPal);
//----------------------------------------------------------------------------------
// Module Functions Definition
//----------------------------------------------------------------------------------
// Creates a gif file
// NOTE: Initializes internal file pointer (only one gif recording at a time)
// The delay value is the time between frames in hundredths of a second - note that not all viewers pay much attention to this value.
RGIFDEF bool GifBegin(const char *filename, unsigned int width, unsigned int height, unsigned int delay, unsigned int bitDepth, bool dither)
{
#if _MSC_VER >= 1400
gifFile = 0;
fopen_s(&gifFile, filename, "wb");
#else
gifFile = fopen(filename, "wb");
#endif
if (!gifFile) return false;
// Allocate space for one gif frame
gifFrame = (unsigned char *)GIF_MALLOC(width*height*4);
// GIF Header
fputs("GIF89a",gifFile);
// Reference: http://www.onicos.com/staff/iz/formats/gif.html
// GIF Screen Descriptor
fputc(width & 0xff, gifFile);
fputc((width >> 8) & 0xff, gifFile); // Screen width (2 byte)
fputc(height & 0xff, gifFile);
fputc((height >> 8) & 0xff, gifFile); // Screen height (2 byte)
fputc(0xf0, gifFile); // Color table flags: unsorted global color table of 2 entries (1 byte, bit-flags)
fputc(0, gifFile); // Background color index
fputc(0, gifFile); // Pixel Aspect Ratio (square, we need to specify this because it's 1989)
// GIF Global Color table (just a dummy palette)
// Color 0: black
fputc(0, gifFile);
fputc(0, gifFile);
fputc(0, gifFile);
// Color 1: also black
fputc(0, gifFile);
fputc(0, gifFile);
fputc(0, gifFile);
if (delay != 0)
{
// Application Extension Block (19 bytes long)
fputc(0x21, gifFile); // GIF Extension code
fputc(0xff, gifFile); // Application Extension Label
fputc(11, gifFile); // Length of Application Block (11 byte)
fputs("NETSCAPE2.0", gifFile); // Application Identifier (Netscape 2.0 block)
fputc(0x03, gifFile); // Length of Data Sub-Block (3 bytes)
fputc(0x01, gifFile); // 0x01
fputc(0x00, gifFile); // This specifies the number of times,
fputc(0x00, gifFile); // the loop should be executed (infinitely)
fputc(0x00, gifFile); // Data Sub-Block Terminator.
}
return true;
}
// Writes out a new frame to a GIF in progress.
// NOTE: gifFile should have been initialized with GifBegin()
// AFAIK, it is legal to use different bit depths for different frames of an image -
// this may be handy to save bits in animations that don't change much.
RGIFDEF bool GifWriteFrame(const unsigned char *image, unsigned int width, unsigned int height, unsigned int delay, int bitDepth, bool dither)
{
if (!gifFile) return false;
const unsigned char *oldImage = gifFrame;
GifPalette pal;
GifMakePalette((dither ? NULL : oldImage), image, width, height, bitDepth, dither, &pal);
if (dither) GifDitherImage(oldImage, image, gifFrame, width, height, &pal);
else GifThresholdImage(oldImage, image, gifFrame, width, height, &pal);
GifWriteLzwImage(gifFile, gifFrame, 0, 0, width, height, delay, &pal);
return true;
}
// Writes the EOF code, closes the file handle, and frees temp memory used by a GIF.
// Many if not most viewers will still display a GIF properly if the EOF code is missing,
// but it's still a good idea to write it out.
RGIFDEF bool GifEnd()
{
if (!gifFile) return false;
fputc(0x3b, gifFile); // Trailer (end of file)
fclose(gifFile);
GIF_FREE(gifFrame);
gifFile = NULL;
gifFrame = NULL;
return true;
}
//----------------------------------------------------------------------------------
// Module specific Functions Definition
//----------------------------------------------------------------------------------
// walks the k-d tree to pick the palette entry for a desired color.
// Takes as in/out parameters the current best color and its error -
// only changes them if it finds a better color in its subtree.
// this is the major hotspot in the code at the moment.
static void GifGetClosestPaletteColor(GifPalette *pPal, int r, int g, int b, int *bestInd, int *bestDiff, int treeRoot)
{
// base case, reached the bottom of the tree
if (treeRoot > (1<<pPal->bitDepth)-1)
{
int ind = treeRoot-(1<<pPal->bitDepth);
if (ind == gifTransparentIndex) return;
// check whether this color is better than the current winner
int r_err = r - ((int32_t)pPal->r[ind]);
int g_err = g - ((int32_t)pPal->g[ind]);
int b_err = b - ((int32_t)pPal->b[ind]);
int diff = GIFABS(r_err)+GIFABS(g_err)+GIFABS(b_err);
if (diff < *bestDiff)
{
*bestInd = ind;
*bestDiff = diff;
}
return;
}
// take the appropriate color (r, g, or b) for this node of the k-d tree
int comps[3]; comps[0] = r; comps[1] = g; comps[2] = b;
int splitComp = comps[pPal->treeSplitElt[treeRoot]];
int splitPos = pPal->treeSplit[treeRoot];
if (splitPos > splitComp)
{
// check the left subtree
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2);
if (*bestDiff > (splitPos - splitComp))
{
// cannot prove there's not a better value in the right subtree, check that too
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2 + 1);
}
}
else
{
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2 + 1);
if (*bestDiff > splitComp - splitPos)
{
GifGetClosestPaletteColor(pPal, r, g, b, bestInd, bestDiff, treeRoot*2);
}
}
}
static void GifSwapPixels(unsigned char *image, int pixA, int pixB)
{
unsigned char rA = image[pixA*4];
unsigned char gA = image[pixA*4 + 1];
unsigned char bA = image[pixA*4+2];
unsigned char aA = image[pixA*4+3];
unsigned char rB = image[pixB*4];
unsigned char gB = image[pixB*4 + 1];
unsigned char bB = image[pixB*4+2];
unsigned char aB = image[pixA*4+3];
image[pixA*4] = rB;
image[pixA*4 + 1] = gB;
image[pixA*4+2] = bB;
image[pixA*4+3] = aB;
image[pixB*4] = rA;
image[pixB*4 + 1] = gA;
image[pixB*4+2] = bA;
image[pixB*4+3] = aA;
}
// just the partition operation from quicksort
static int GifPartition(unsigned char *image, const int left, const int right, const int elt, int pivotIndex)
{
const int pivotValue = image[(pivotIndex)*4+elt];
GifSwapPixels(image, pivotIndex, right-1);
int storeIndex = left;
bool split = 0;
for (int ii=left; ii<right-1; ++ii)
{
int arrayVal = image[ii*4+elt];
if (arrayVal < pivotValue)
{
GifSwapPixels(image, ii, storeIndex);
++storeIndex;
}
else if (arrayVal == pivotValue)
{
if (split)
{
GifSwapPixels(image, ii, storeIndex);
++storeIndex;
}
split = !split;
}
}
GifSwapPixels(image, storeIndex, right-1);
return storeIndex;
}
// Perform an incomplete sort, finding all elements above and below the desired median
static void GifPartitionByMedian(unsigned char *image, int left, int right, int com, int neededCenter)
{
if (left < right-1)
{
int pivotIndex = left + (right-left)/2;
pivotIndex = GifPartition(image, left, right, com, pivotIndex);
// Only "sort" the section of the array that contains the median
if (pivotIndex > neededCenter)
GifPartitionByMedian(image, left, pivotIndex, com, neededCenter);
if (pivotIndex < neededCenter)
GifPartitionByMedian(image, pivotIndex + 1, right, com, neededCenter);
}
}
// Builds a palette by creating a balanced k-d tree of all pixels in the image
static void GifSplitPalette(unsigned char *image, int numPixels, int firstElt, int lastElt, int splitElt, int splitDist,
int treeNode, bool buildForDither, GifPalette *pal)
{
if (lastElt <= firstElt || numPixels == 0)
return;
// base case, bottom of the tree
if (lastElt == firstElt + 1)
{
if (buildForDither)
{
// Dithering needs at least one color as dark as anything
// in the image and at least one brightest color -
// otherwise it builds up error and produces strange artifacts
if (firstElt == 1)
{
// special case: the darkest color in the image
unsigned int r=255, g=255, b=255;
for (int ii=0; ii<numPixels; ++ii)
{
r = GIFMIN(r, image[ii*4+0]);
g = GIFMIN(g, image[ii*4 + 1]);
b = GIFMIN(b, image[ii*4+2]);
}
pal->r[firstElt] = r;
pal->g[firstElt] = g;
pal->b[firstElt] = b;
return;
}
if (firstElt == (1 << pal->bitDepth)-1)
{
// special case: the lightest color in the image
unsigned int r=0, g=0, b=0;
for (int ii=0; ii<numPixels; ++ii)
{
r = GIFMAX(r, image[ii*4+0]);
g = GIFMAX(g, image[ii*4 + 1]);
b = GIFMAX(b, image[ii*4+2]);
}
pal->r[firstElt] = r;
pal->g[firstElt] = g;
pal->b[firstElt] = b;
return;
}
}
// otherwise, take the average of all colors in this subcube
uint64_t r=0, g=0, b=0;
for (int ii=0; ii<numPixels; ++ii)
{
r += image[ii*4+0];
g += image[ii*4 + 1];
b += image[ii*4+2];
}
r += numPixels / 2; // round to nearest
g += numPixels / 2;
b += numPixels / 2;
r /= numPixels;
g /= numPixels;
b /= numPixels;
pal->r[firstElt] = (unsigned char)r;
pal->g[firstElt] = (unsigned char)g;
pal->b[firstElt] = (unsigned char)b;
return;
}
// Find the axis with the largest range
int minR = 255, maxR = 0;
int minG = 255, maxG = 0;
int minB = 255, maxB = 0;
for (int ii=0; ii<numPixels; ++ii)
{
int r = image[ii*4+0];
int g = image[ii*4 + 1];
int b = image[ii*4+2];
if (r > maxR) maxR = r;
if (r < minR) minR = r;
if (g > maxG) maxG = g;
if (g < minG) minG = g;
if (b > maxB) maxB = b;
if (b < minB) minB = b;
}
int rRange = maxR - minR;
int gRange = maxG - minG;
int bRange = maxB - minB;
// and split along that axis. (incidentally, this means this isn't a "proper" k-d tree but I don't know what else to call it)
int splitCom = 1;
if (bRange > gRange) splitCom = 2;
if (rRange > bRange && rRange > gRange) splitCom = 0;
int subPixelsA = numPixels *(splitElt - firstElt) / (lastElt - firstElt);
int subPixelsB = numPixels-subPixelsA;
GifPartitionByMedian(image, 0, numPixels, splitCom, subPixelsA);
pal->treeSplitElt[treeNode] = splitCom;
pal->treeSplit[treeNode] = image[subPixelsA*4+splitCom];
GifSplitPalette(image, subPixelsA, firstElt, splitElt, splitElt-splitDist, splitDist/2, treeNode*2, buildForDither, pal);
GifSplitPalette(image+subPixelsA*4, subPixelsB, splitElt, lastElt, splitElt+splitDist, splitDist/2, treeNode*2 + 1, buildForDither, pal);
}
// Finds all pixels that have changed from the previous image and
// moves them to the fromt of th buffer.
// This allows us to build a palette optimized for the colors of the
// changed pixels only.
static int GifPickChangedPixels(const unsigned char *lastFrame, unsigned char *frame, int numPixels)
{
int numChanged = 0;
unsigned char *writeIter = frame;
for (int ii=0; ii<numPixels; ++ii)
{
if (lastFrame[0] != frame[0] ||
lastFrame[1] != frame[1] ||
lastFrame[2] != frame[2])
{
writeIter[0] = frame[0];
writeIter[1] = frame[1];
writeIter[2] = frame[2];
++numChanged;
writeIter += 4;
}
lastFrame += 4;
frame += 4;
}
return numChanged;
}
// Creates a palette by placing all the image pixels in a k-d tree and then averaging the blocks at the bottom.
// This is known as the "modified median split" technique
static void GifMakePalette(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned int width, unsigned int height, int bitDepth, bool buildForDither, GifPalette *pPal)
{
pPal->bitDepth = bitDepth;
// SplitPalette is destructive (it sorts the pixels by color) so
// we must create a copy of the image for it to destroy
int imageSize = width*height*4*sizeof(unsigned char);
unsigned char *destroyableImage = (unsigned char*)GIF_TEMP_MALLOC(imageSize);
memcpy(destroyableImage, nextFrame, imageSize);
int numPixels = width*height;
if (lastFrame)
numPixels = GifPickChangedPixels(lastFrame, destroyableImage, numPixels);
const int lastElt = 1 << bitDepth;
const int splitElt = lastElt/2;
const int splitDist = splitElt/2;
GifSplitPalette(destroyableImage, numPixels, 1, lastElt, splitElt, splitDist, 1, buildForDither, pPal);
GIF_TEMP_FREE(destroyableImage);
// add the bottom node for the transparency index
pPal->treeSplit[1 << (bitDepth-1)] = 0;
pPal->treeSplitElt[1 << (bitDepth-1)] = 0;
pPal->r[0] = pPal->g[0] = pPal->b[0] = 0;
}
// Implements Floyd-Steinberg dithering, writes palette value to alpha
static void GifDitherImage(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned char *outFrame, unsigned int width, unsigned int height, GifPalette *pPal)
{
int numPixels = width*height;
// quantPixels initially holds color*256 for all pixels
// The extra 8 bits of precision allow for sub-single-color error values
// to be propagated
int32_t *quantPixels = (int32_t*)GIF_TEMP_MALLOC(sizeof(int32_t)*numPixels*4);
for (int ii=0; ii<numPixels*4; ++ii)
{
unsigned char pix = nextFrame[ii];
int32_t pix16 = (int32_t)pix*256;
quantPixels[ii] = pix16;
}
for (unsigned int yy=0; yy<height; ++yy)
{
for (unsigned int xx=0; xx<width; ++xx)
{
int32_t *nextPix = quantPixels + 4*(yy*width+xx);
const unsigned char *lastPix = lastFrame? lastFrame + 4*(yy*width+xx) : NULL;
// Compute the colors we want (rounding to nearest)
int32_t rr = (nextPix[0] + 127) / 256;
int32_t gg = (nextPix[1] + 127) / 256;
int32_t bb = (nextPix[2] + 127) / 256;
// if it happens that we want the color from last frame, then just write out
// a transparent pixel
if (lastFrame &&
lastPix[0] == rr &&
lastPix[1] == gg &&
lastPix[2] == bb)
{
nextPix[0] = rr;
nextPix[1] = gg;
nextPix[2] = bb;
nextPix[3] = gifTransparentIndex;
continue;
}
int32_t bestDiff = 1000000;
int32_t bestInd = gifTransparentIndex;
// Search the palete
GifGetClosestPaletteColor(pPal, rr, gg, bb, &bestInd, &bestDiff, 1);
// Write the result to the temp buffer
int32_t r_err = nextPix[0] - (int32_t)(pPal->r[bestInd])*256;
int32_t g_err = nextPix[1] - (int32_t)(pPal->g[bestInd])*256;
int32_t b_err = nextPix[2] - (int32_t)(pPal->b[bestInd])*256;
nextPix[0] = pPal->r[bestInd];
nextPix[1] = pPal->g[bestInd];
nextPix[2] = pPal->b[bestInd];
nextPix[3] = bestInd;
// Propagate the error to the four adjacent locations
// that we haven't touched yet
int quantloc_7 = (yy*width+xx + 1);
int quantloc_3 = (yy*width+width+xx-1);
int quantloc_5 = (yy*width+width+xx);
int quantloc_1 = (yy*width+width+xx + 1);
if (quantloc_7 < numPixels)
{
int32_t *pix7 = quantPixels+4*quantloc_7;
pix7[0] += GIFMAX(-pix7[0], r_err*7 / 16);
pix7[1] += GIFMAX(-pix7[1], g_err*7 / 16);
pix7[2] += GIFMAX(-pix7[2], b_err*7 / 16);
}
if (quantloc_3 < numPixels)
{
int32_t *pix3 = quantPixels+4*quantloc_3;
pix3[0] += GIFMAX(-pix3[0], r_err*3 / 16);
pix3[1] += GIFMAX(-pix3[1], g_err*3 / 16);
pix3[2] += GIFMAX(-pix3[2], b_err*3 / 16);
}
if (quantloc_5 < numPixels)
{
int32_t *pix5 = quantPixels+4*quantloc_5;
pix5[0] += GIFMAX(-pix5[0], r_err*5 / 16);
pix5[1] += GIFMAX(-pix5[1], g_err*5 / 16);
pix5[2] += GIFMAX(-pix5[2], b_err*5 / 16);
}
if (quantloc_1 < numPixels)
{
int32_t *pix1 = quantPixels+4*quantloc_1;
pix1[0] += GIFMAX(-pix1[0], r_err / 16);
pix1[1] += GIFMAX(-pix1[1], g_err / 16);
pix1[2] += GIFMAX(-pix1[2], b_err / 16);
}
}
}
// Copy the palettized result to the output buffer
for (int ii=0; ii<numPixels*4; ++ii)
{
outFrame[ii] = quantPixels[ii];
}
GIF_TEMP_FREE(quantPixels);
}
// Picks palette colors for the image using simple thresholding, no dithering
static void GifThresholdImage(const unsigned char *lastFrame, const unsigned char *nextFrame, unsigned char *outFrame, unsigned int width, unsigned int height, GifPalette *pPal)
{
unsigned int numPixels = width*height;
for (unsigned int ii=0; ii<numPixels; ++ii)
{
// if a previous color is available, and it matches the current color,
// set the pixel to transparent
if (lastFrame &&
lastFrame[0] == nextFrame[0] &&
lastFrame[1] == nextFrame[1] &&
lastFrame[2] == nextFrame[2])
{
outFrame[0] = lastFrame[0];
outFrame[1] = lastFrame[1];
outFrame[2] = lastFrame[2];
outFrame[3] = gifTransparentIndex;
}
else
{
// palettize the pixel
int32_t bestDiff = 1000000;
int32_t bestInd = 1;
GifGetClosestPaletteColor(pPal, nextFrame[0], nextFrame[1], nextFrame[2], &bestInd, &bestDiff, 1);
// Write the resulting color to the output buffer
outFrame[0] = pPal->r[bestInd];
outFrame[1] = pPal->g[bestInd];
outFrame[2] = pPal->b[bestInd];
outFrame[3] = bestInd;
}
if (lastFrame) lastFrame += 4;
outFrame += 4;
nextFrame += 4;
}
}
// insert a single bit
static void GifWriteBit(GifBitStatus *stat, unsigned int bit)
{
bit = bit & 1;
bit = bit << stat->bitIndex;
stat->byte |= bit;
++stat->bitIndex;
if (stat->bitIndex > 7)
{
// move the newly-finished byte to the chunk buffer
stat->chunk[stat->chunkIndex++] = stat->byte;
// and start a new byte
stat->bitIndex = 0;
stat->byte = 0;
}
}
// write all bytes so far to the file
static void GifWriteChunk(FILE *f, GifBitStatus *stat)
{
fputc(stat->chunkIndex, f);
fwrite(stat->chunk, 1, stat->chunkIndex, f);
stat->bitIndex = 0;
stat->byte = 0;
stat->chunkIndex = 0;
}
static void GifWriteCode(FILE *f, GifBitStatus *stat, unsigned int code, unsigned int length)
{
for (unsigned int ii=0; ii<length; ++ii)
{
GifWriteBit(stat, code);
code = code >> 1;
if (stat->chunkIndex == 255)
{
GifWriteChunk(f, stat);
}
}
}
// write a 256-color (8-bit) image palette to the file
static void GifWritePalette(const GifPalette *pPal, FILE *f)
{
fputc(0, f); // first color: transparency
fputc(0, f);
fputc(0, f);
for (int ii=1; ii<(1 << pPal->bitDepth); ++ii)
{
unsigned int r = pPal->r[ii];
unsigned int g = pPal->g[ii];
unsigned int b = pPal->b[ii];
fputc(r, f);
fputc(g, f);
fputc(b, f);
}
}
// write the image header, LZW-compress and write out the image
static void GifWriteLzwImage(FILE *f, unsigned char *image, unsigned int left, unsigned int top, unsigned int width, unsigned int height, unsigned int delay, GifPalette *pPal)
{
// graphics control extension
fputc(0x21, f);
fputc(0xf9, f);
fputc(0x04, f);
fputc(0x05, f); // leave prev frame in place, this frame has transparency
fputc(delay & 0xff, f);
fputc((delay >> 8) & 0xff, f);
fputc(gifTransparentIndex, f); // transparent color index
fputc(0, f);
fputc(0x2c, f); // image descriptor block
fputc(left & 0xff, f); // corner of image in canvas space
fputc((left >> 8) & 0xff, f);
fputc(top & 0xff, f);
fputc((top >> 8) & 0xff, f);
fputc(width & 0xff, f); // width and height of image
fputc((width >> 8) & 0xff, f);
fputc(height & 0xff, f);
fputc((height >> 8) & 0xff, f);
//fputc(0, f); // no local color table, no transparency
//fputc(0x80, f); // no local color table, but transparency
fputc(0x80 + pPal->bitDepth-1, f); // local color table present, 2 ^ bitDepth entries
GifWritePalette(pPal, f);
const int minCodeSize = pPal->bitDepth;
const unsigned int clearCode = 1 << pPal->bitDepth;
fputc(minCodeSize, f); // min code size 8 bits
GifLzwNode *codetree = (GifLzwNode *)GIF_TEMP_MALLOC(sizeof(GifLzwNode)*4096);
memset(codetree, 0, sizeof(GifLzwNode)*4096);
int32_t curCode = -1;
unsigned int codeSize = minCodeSize + 1;
unsigned int maxCode = clearCode + 1;
GifBitStatus stat;
stat.byte = 0;
stat.bitIndex = 0;
stat.chunkIndex = 0;
GifWriteCode(f, &stat, clearCode, codeSize); // start with a fresh LZW dictionary
for (unsigned int yy=0; yy<height; ++yy)
{
for (unsigned int xx=0; xx<width; ++xx)
{
unsigned char nextValue = image[(yy*width+xx)*4+3];
// "loser mode" - no compression, every single code is followed immediately by a clear
//WriteCode(f, stat, nextValue, codeSize);
//WriteCode(f, stat, 256, codeSize);
if (curCode < 0)
{
// first value in a new run
curCode = nextValue;
}
else if (codetree[curCode].m_next[nextValue])
{
// current run already in the dictionary
curCode = codetree[curCode].m_next[nextValue];
}
else
{
// finish the current run, write a code
GifWriteCode(f, &stat, curCode, codeSize);
// insert the new run into the dictionary
codetree[curCode].m_next[nextValue] = ++maxCode;
if (maxCode >= (1ul << codeSize))
{
// dictionary entry count has broken a size barrier,
// we need more bits for codes
codeSize++;
}
if (maxCode == 4095)
{
// the dictionary is full, clear it out and begin anew
GifWriteCode(f, &stat, clearCode, codeSize); // clear tree
memset(codetree, 0, sizeof(GifLzwNode)*4096);
curCode = -1;
codeSize = minCodeSize + 1;
maxCode = clearCode + 1;
}
curCode = nextValue;
}
}
}
// compression footer
GifWriteCode(f, &stat, curCode, codeSize);
GifWriteCode(f, &stat, clearCode, codeSize);
GifWriteCode(f, &stat, clearCode + 1, minCodeSize + 1);
// write out the last partial chunk
while (stat.bitIndex) GifWriteBit(&stat, 0);
if (stat.chunkIndex) GifWriteChunk(f, &stat);
fputc(0, f); // image block terminator
GIF_TEMP_FREE(codetree);
}
#endif // RGIF_IMPLEMENTATION

View file

@ -1,4 +1,4 @@
/* stb_image - v2.15 - public domain image loader - http://nothings.org/stb_image.h
/* stb_image - v2.16 - public domain image loader - http://nothings.org/stb_image.h
no warranty implied; use at your own risk
Do this:
@ -48,6 +48,7 @@ LICENSE
RECENT REVISION HISTORY:
2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
@ -58,10 +59,6 @@ RECENT REVISION HISTORY:
correct channel count for PNG & BMP
2.10 (2016-01-22) avoid warning introduced in 2.09
2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
2.07 (2015-09-13) partial animated GIF support
limited 16-bit PSD support
minor bugs, code cleanup, and compiler warnings
See end of file for full revision history.
@ -83,6 +80,7 @@ RECENT REVISION HISTORY:
Optimizations & bugfixes
Fabian "ryg" Giesen
Arseny Kapoulkine
John-Mark Allen
Bug & warning fixes
Marc LeBlanc David Woo Guillaume George Martins Mozeiko
@ -98,7 +96,7 @@ RECENT REVISION HISTORY:
Michaelangel007@github Philipp Wiesemann Dale Weiler github:grim210
Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:sammyhw
Blazej Dariusz Roszkowski Gregory Mullen github:phprus
Christian Floisand Kevin Schmidt github:poppolopoppo
*/
#ifndef STBI_INCLUDE_STB_IMAGE_H
@ -134,11 +132,12 @@ RECENT REVISION HISTORY:
// with each pixel consisting of N interleaved 8-bit components; the first
// pixel pointed to is top-left-most in the image. There is no padding between
// image scanlines or between pixels, regardless of format. The number of
// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise.
// If req_comp is non-zero, *comp has the number of components that _would_
// have been output otherwise. E.g. if you set req_comp to 4, you will always
// get RGBA output, but you can check *comp to see if it's trivially opaque
// because e.g. there were only 3 channels in the source image.
// components N is 'desired_channels' if desired_channels is non-zero, or
// *channels_in_file otherwise. If desired_channels is non-zero,
// *channels_in_file has the number of components that _would_ have been
// output otherwise. E.g. if you set desired_channels to 4, you will always
// get RGBA output, but you can check *channels_in_file to see if it's trivially
// opaque because e.g. there were only 3 channels in the source image.
//
// An output image with N components has the following components interleaved
// in this order in each pixel:
@ -150,10 +149,10 @@ RECENT REVISION HISTORY:
// 4 red, green, blue, alpha
//
// If image loading fails for any reason, the return value will be NULL,
// and *x, *y, *comp will be unchanged. The function stbi_failure_reason()
// can be queried for an extremely brief, end-user unfriendly explanation
// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid
// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
// and *x, *y, *channels_in_file will be unchanged. The function
// stbi_failure_reason() can be queried for an extremely brief, end-user
// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS
// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
// more user-friendly ones.
//
// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
@ -310,7 +309,7 @@ RECENT REVISION HISTORY:
enum
{
STBI_default = 0, // only used for req_comp
STBI_default = 0, // only used for desired_channels
STBI_grey = 1,
STBI_grey_alpha = 2,
@ -352,12 +351,12 @@ typedef struct
// 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 *channels_in_file, int desired_channels);
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_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
@ -366,22 +365,24 @@ STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_i
// 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);
STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_us *stbi_load_16_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_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
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 *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 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
#endif
#endif
@ -639,7 +640,7 @@ static int stbi__cpuid3(void)
#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
static int stbi__sse2_available()
static int stbi__sse2_available(void)
{
int info3 = stbi__cpuid3();
return ((info3 >> 26) & 1) != 0;
@ -647,7 +648,7 @@ static int stbi__sse2_available()
#else // assume GCC-style if not VC++
#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
static int stbi__sse2_available()
static int stbi__sse2_available(void)
{
// If we're even attempting to compile this on GCC/Clang, that means
// -msse2 is on, which means the compiler is allowed to use SSE2
@ -1029,6 +1030,30 @@ static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int chan
return enlarged;
}
static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)
{
int row;
size_t bytes_per_row = (size_t)w * bytes_per_pixel;
stbi_uc temp[2048];
stbi_uc *bytes = (stbi_uc *)image;
for (row = 0; row < (h>>1); row++) {
stbi_uc *row0 = bytes + row*bytes_per_row;
stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row;
// swap row0 with row1
size_t bytes_left = bytes_per_row;
while (bytes_left) {
size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp);
memcpy(temp, row0, bytes_copy);
memcpy(row0, row1, bytes_copy);
memcpy(row1, temp, bytes_copy);
row0 += bytes_copy;
row1 += bytes_copy;
bytes_left -= bytes_copy;
}
}
}
static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
{
stbi__result_info ri;
@ -1046,21 +1071,8 @@ static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x,
// @TODO: move stbi__convert_format to here
if (stbi__vertically_flip_on_load) {
int w = *x, h = *y;
int channels = req_comp ? req_comp : *comp;
int row,col,z;
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 < 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;
}
}
}
stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc));
}
return (unsigned char *) result;
@ -1084,21 +1096,8 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x,
// @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;
}
}
}
stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16));
}
return (stbi__uint16 *) result;
@ -1108,21 +1107,8 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x,
static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)
{
if (stbi__vertically_flip_on_load && result != NULL) {
int w = *x, h = *y;
int depth = req_comp ? req_comp : *comp;
int row,col,z;
float temp;
// @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;
}
}
}
int channels = req_comp ? req_comp : *comp;
stbi__vertical_flip(result, *x, *y, channels * sizeof(float));
}
}
#endif
@ -1191,6 +1177,20 @@ STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, i
#endif //!STBI_NO_STDIO
STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels)
{
stbi__context s;
stbi__start_mem(&s,buffer,len);
return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
}
STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels)
{
stbi__context s;
stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user);
return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
}
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;
@ -2806,7 +2806,7 @@ static int stbi__process_marker(stbi__jpeg *z, int m)
if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG");
for (i=0; i < 64; ++i)
z->dequant[t][stbi__jpeg_dezigzag[i]] = sixteen ? stbi__get16be(z->s) : stbi__get8(z->s);
z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s));
L -= (sixteen ? 129 : 65);
}
return L==0;
@ -3611,20 +3611,20 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
} else if (z->s->img_n == 4) {
if (z->app14_color_transform == 0) { // CMYK
for (i=0; i < z->s->img_x; ++i) {
stbi_uc k = coutput[3][i];
out[0] = stbi__blinn_8x8(coutput[0][i], k);
out[1] = stbi__blinn_8x8(coutput[1][i], k);
out[2] = stbi__blinn_8x8(coutput[2][i], k);
stbi_uc m = coutput[3][i];
out[0] = stbi__blinn_8x8(coutput[0][i], m);
out[1] = stbi__blinn_8x8(coutput[1][i], m);
out[2] = stbi__blinn_8x8(coutput[2][i], m);
out[3] = 255;
out += n;
}
} else if (z->app14_color_transform == 2) { // YCCK
z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
for (i=0; i < z->s->img_x; ++i) {
stbi_uc k = coutput[3][i];
out[0] = stbi__blinn_8x8(255 - out[0], k);
out[1] = stbi__blinn_8x8(255 - out[1], k);
out[2] = stbi__blinn_8x8(255 - out[2], k);
stbi_uc m = coutput[3][i];
out[0] = stbi__blinn_8x8(255 - out[0], m);
out[1] = stbi__blinn_8x8(255 - out[1], m);
out[2] = stbi__blinn_8x8(255 - out[2], m);
out += n;
}
} else { // YCbCr + alpha? Ignore the fourth channel for now
@ -3649,10 +3649,10 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
}
} else if (z->s->img_n == 4 && z->app14_color_transform == 0) {
for (i=0; i < z->s->img_x; ++i) {
stbi_uc k = coutput[3][i];
stbi_uc r = stbi__blinn_8x8(coutput[0][i], k);
stbi_uc g = stbi__blinn_8x8(coutput[1][i], k);
stbi_uc b = stbi__blinn_8x8(coutput[2][i], k);
stbi_uc m = coutput[3][i];
stbi_uc r = stbi__blinn_8x8(coutput[0][i], m);
stbi_uc g = stbi__blinn_8x8(coutput[1][i], m);
stbi_uc b = stbi__blinn_8x8(coutput[2][i], m);
out[0] = stbi__compute_y(r, g, b);
out[1] = 255;
out += n;
@ -4297,11 +4297,10 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
img_width_bytes = (((img_n * x * depth) + 7) >> 3);
img_len = (img_width_bytes + 1) * y;
if (s->img_x == x && s->img_y == y) {
if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG");
} else { // interlaced:
if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
}
// we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
// but issue #276 reported a PNG in the wild that had extra data at the end (all zeros),
// so just check for raw_len < img_len always.
if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
for (j=0; j < y; ++j) {
stbi_uc *cur = a->out + stride*j;
@ -4654,9 +4653,10 @@ static void stbi__de_iphone(stbi__png *z)
stbi_uc a = p[3];
stbi_uc t = p[0];
if (a) {
p[0] = p[2] * 255 / a;
p[1] = p[1] * 255 / a;
p[2] = t * 255 / a;
stbi_uc half = a / 2;
p[0] = (p[2] * 255 + half) / a;
p[1] = (p[1] * 255 + half) / a;
p[2] = ( t * 255 + half) / a;
} else {
p[0] = p[2];
p[2] = t;
@ -4819,6 +4819,9 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
if (req_comp >= 3) s->img_out_n = req_comp;
if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))
return 0;
} else if (has_trans) {
// non-paletted image with tRNS -> source image has (constant) alpha
++s->img_n;
}
STBI_FREE(z->expanded); z->expanded = NULL;
return 1;
@ -6966,6 +6969,13 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
/*
revision history:
2.16 (2017-07-23) all functions have 16-bit variants;
STBI_NO_STDIO works again;
compilation fixes;
fix rounding in unpremultiply;
optimize vertical flip;
disable raw_len validation;
documentation fixes
2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode;
warning fixes; disable run-time SSE detection on gcc;
uniform handling of optional "return" values;

View file

@ -1,4 +1,4 @@
/* stb_image_resize - v0.94 - public domain image resizing
/* stb_image_resize - v0.95 - public domain image resizing
by Jorge L Rodriguez (@VinoBS) - 2014
http://github.com/nothings/stb
@ -156,8 +156,10 @@
Jorge L Rodriguez: Implementation
Sean Barrett: API design, optimizations
Aras Pranckevicius: bugfix
Nathan Reed: warning fixes
REVISIONS
0.95 (2017-07-23) fixed warnings
0.94 (2017-03-18) fixed warnings
0.93 (2017-03-03) fixed bug with certain combinations of heights
0.92 (2017-01-02) fix integer overflow on large (>2GB) images
@ -393,8 +395,9 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
#ifndef STBIR_MALLOC
#include <stdlib.h>
#define STBIR_MALLOC(size,c) malloc(size)
#define STBIR_FREE(ptr,c) free(ptr)
// use comma operator to evaluate c, to avoid "unused parameter" warnings
#define STBIR_MALLOC(size,c) ((void)(c), malloc(size))
#define STBIR_FREE(ptr,c) ((void)(c), free(ptr))
#endif
#ifndef _MSC_VER
@ -983,7 +986,7 @@ static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max)
return (m);
}
return n; // NOTREACHED
// NOTREACHED
default:
STBIR_ASSERT(!"Unimplemented edge type");

View file

@ -1,5 +1,5 @@
/* stb_image_write - v1.05 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015
/* stb_image_write - v1.07 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
no warranty implied; use at your own risk
Before #including,
@ -35,6 +35,7 @@ USAGE:
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
int stbi_write_jpg(char const *filename, int w, int h, int comp, const float *data);
There are also four equivalent functions that use an arbitrary write function. You are
expected to open/close your file-equivalent before and after calling these:
@ -43,6 +44,7 @@ USAGE:
int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
where the callback is:
void stbi_write_func(void *context, void *data, int size);
@ -79,6 +81,10 @@ USAGE:
TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
data, set the global variable 'stbi_write_tga_with_rle' to 0.
JPEG does ignore alpha channels in input data; quality is between 1 and 100.
Higher quality looks better but results in a bigger image.
JPEG baseline (no JPEG progressive).
CREDITS:
@ -94,6 +100,9 @@ CREDITS:
Alan Hickman
initial file IO callback implementation
Emmanuel Julien
JPEG
Jon Olick (original jo_jpeg.cpp code)
Daniel Gibson
bugfixes:
github:Chribba
Guillaume Chereau
@ -131,6 +140,7 @@ STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const
STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);
#endif
typedef void stbi_write_func(void *context, void *data, int size);
@ -139,6 +149,7 @@ STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w,
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
#ifdef __cplusplus
}
@ -277,6 +288,11 @@ static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
va_end(v);
}
static void stbiw__putc(stbi__write_context *s, unsigned char c)
{
s->func(s->context, &c, 1);
}
static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
{
unsigned char arr[3];
@ -450,7 +466,7 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v
return 1;
}
int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
{
stbi__write_context s;
stbi__start_write_callbacks(&s, func, context);
@ -458,7 +474,7 @@ int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, i
}
#ifndef STBI_WRITE_NO_STDIO
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
{
stbi__write_context s;
if (stbi__start_write_file(&s,filename)) {
@ -620,7 +636,7 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f
}
}
int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
{
stbi__write_context s;
stbi__start_write_callbacks(&s, func, context);
@ -628,7 +644,7 @@ int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, i
}
#ifndef STBI_WRITE_NO_STDIO
int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
{
stbi__write_context s;
if (stbi__start_write_file(&s,filename)) {
@ -1013,9 +1029,359 @@ STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x,
return 1;
}
/* ***************************************************************************
*
* JPEG writer
*
* This is based on Jon Olick's jo_jpeg.cpp:
* public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html
*/
static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18,
24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 };
static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) {
int bitBuf = *bitBufP, bitCnt = *bitCntP;
bitCnt += bs[1];
bitBuf |= bs[0] << (24 - bitCnt);
while(bitCnt >= 8) {
unsigned char c = (bitBuf >> 16) & 255;
stbiw__putc(s, c);
if(c == 255) {
stbiw__putc(s, 0);
}
bitBuf <<= 8;
bitCnt -= 8;
}
*bitBufP = bitBuf;
*bitCntP = bitCnt;
}
static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) {
float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p;
float z1, z2, z3, z4, z5, z11, z13;
float tmp0 = d0 + d7;
float tmp7 = d0 - d7;
float tmp1 = d1 + d6;
float tmp6 = d1 - d6;
float tmp2 = d2 + d5;
float tmp5 = d2 - d5;
float tmp3 = d3 + d4;
float tmp4 = d3 - d4;
// Even part
float tmp10 = tmp0 + tmp3; // phase 2
float tmp13 = tmp0 - tmp3;
float tmp11 = tmp1 + tmp2;
float tmp12 = tmp1 - tmp2;
d0 = tmp10 + tmp11; // phase 3
d4 = tmp10 - tmp11;
z1 = (tmp12 + tmp13) * 0.707106781f; // c4
d2 = tmp13 + z1; // phase 5
d6 = tmp13 - z1;
// Odd part
tmp10 = tmp4 + tmp5; // phase 2
tmp11 = tmp5 + tmp6;
tmp12 = tmp6 + tmp7;
// The rotator is modified from fig 4-8 to avoid extra negations.
z5 = (tmp10 - tmp12) * 0.382683433f; // c6
z2 = tmp10 * 0.541196100f + z5; // c2-c6
z4 = tmp12 * 1.306562965f + z5; // c2+c6
z3 = tmp11 * 0.707106781f; // c4
z11 = tmp7 + z3; // phase 5
z13 = tmp7 - z3;
*d5p = z13 + z2; // phase 6
*d3p = z13 - z2;
*d1p = z11 + z4;
*d7p = z11 - z4;
*d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6;
}
static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {
int tmp1 = val < 0 ? -val : val;
val = val < 0 ? val-1 : val;
bits[1] = 1;
while(tmp1 >>= 1) {
++bits[1];
}
bits[0] = val & ((1<<bits[1])-1);
}
static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {
const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };
const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] };
int dataOff, i, diff, end0pos;
int DU[64];
// DCT rows
for(dataOff=0; dataOff<64; dataOff+=8) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]);
}
// DCT columns
for(dataOff=0; dataOff<8; ++dataOff) {
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+8], &CDU[dataOff+16], &CDU[dataOff+24], &CDU[dataOff+32], &CDU[dataOff+40], &CDU[dataOff+48], &CDU[dataOff+56]);
}
// Quantize/descale/zigzag the coefficients
for(i=0; i<64; ++i) {
float v = CDU[i]*fdtbl[i];
// DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);
}
// Encode DC
diff = DU[0] - DC;
if (diff == 0) {
stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]);
} else {
unsigned short bits[2];
stbiw__jpg_calcBits(diff, bits);
stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]);
stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
}
// Encode ACs
end0pos = 63;
for(; (end0pos>0)&&(DU[end0pos]==0); --end0pos) {
}
// end0pos = first element in reverse order !=0
if(end0pos == 0) {
stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
return DU[0];
}
for(i = 1; i <= end0pos; ++i) {
int startpos = i;
int nrzeroes;
unsigned short bits[2];
for (; DU[i]==0 && i<=end0pos; ++i) {
}
nrzeroes = i-startpos;
if ( nrzeroes >= 16 ) {
int lng = nrzeroes>>4;
int nrmarker;
for (nrmarker=1; nrmarker <= lng; ++nrmarker)
stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes);
nrzeroes &= 15;
}
stbiw__jpg_calcBits(DU[i], bits);
stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]);
stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
}
if(end0pos != 63) {
stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
}
return DU[0];
}
static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) {
// Constants that don't pollute global namespace
static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0};
static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};
static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d};
static const unsigned char std_ac_luminance_values[] = {
0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,
0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,
0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,
0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,
0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa
};
static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0};
static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};
static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77};
static const unsigned char std_ac_chrominance_values[] = {
0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,
0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,
0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,
0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,
0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,
0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa
};
// Huffman tables
static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}};
static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}};
static const unsigned short YAC_HT[256][2] = {
{10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0},
{2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}
};
static const unsigned short UVAC_HT[256][2] = {
{0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},
{16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0},
{1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}
};
static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22,
37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99};
static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99};
static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,
1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f };
int row, col, i, k;
float fdtbl_Y[64], fdtbl_UV[64];
unsigned char YTable[64], UVTable[64];
if(!data || !width || !height || comp > 4 || comp < 1) {
return 0;
}
quality = quality ? quality : 90;
quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;
quality = quality < 50 ? 5000 / quality : 200 - quality * 2;
for(i = 0; i < 64; ++i) {
int uvti, yti = (YQT[i]*quality+50)/100;
YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti);
uvti = (UVQT[i]*quality+50)/100;
UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti);
}
for(row = 0, k = 0; row < 8; ++row) {
for(col = 0; col < 8; ++col, ++k) {
fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
}
}
// Write Headers
{
static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 };
static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };
const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width),
3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };
s->func(s->context, (void*)head0, sizeof(head0));
s->func(s->context, (void*)YTable, sizeof(YTable));
stbiw__putc(s, 1);
s->func(s->context, UVTable, sizeof(UVTable));
s->func(s->context, (void*)head1, sizeof(head1));
s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1);
s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values));
stbiw__putc(s, 0x10); // HTYACinfo
s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1);
s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values));
stbiw__putc(s, 1); // HTUDCinfo
s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1);
s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values));
stbiw__putc(s, 0x11); // HTUACinfo
s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1);
s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values));
s->func(s->context, (void*)head2, sizeof(head2));
}
// Encode 8x8 macroblocks
{
static const unsigned short fillBits[] = {0x7F, 7};
const unsigned char *imageData = (const unsigned char *)data;
int DCY=0, DCU=0, DCV=0;
int bitBuf=0, bitCnt=0;
// comp == 2 is grey+alpha (alpha is ignored)
int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;
int x, y, pos;
for(y = 0; y < height; y += 8) {
for(x = 0; x < width; x += 8) {
float YDU[64], UDU[64], VDU[64];
for(row = y, pos = 0; row < y+8; ++row) {
for(col = x; col < x+8; ++col, ++pos) {
int p = row*width*comp + col*comp;
float r, g, b;
if(row >= height) {
p -= width*comp*(row+1 - height);
}
if(col >= width) {
p -= comp*(col+1 - width);
}
r = imageData[p+0];
g = imageData[p+ofsG];
b = imageData[p+ofsB];
YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128;
UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b;
VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b;
}
}
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
}
}
// Do the bit alignment of the EOI marker
stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits);
}
// EOI
stbiw__putc(s, 0xFF);
stbiw__putc(s, 0xD9);
return 1;
}
STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality)
{
stbi__write_context s;
stbi__start_write_callbacks(&s, func, context);
return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality);
}
#ifndef STBI_WRITE_NO_STDIO
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)
{
stbi__write_context s;
if (stbi__start_write_file(&s,filename)) {
int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);
stbi__end_write_file(&s);
return r;
} else
return 0;
}
#endif
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history
1.07 (2017-07-24)
doc fix
1.06 (2017-07-23)
writing JPEG (using Jon Olick's code)
1.05 ???
1.04 (2017-03-03)
monochrome BMP expansion
1.03 ???

316
raylib/external/stb_perlin.h vendored Normal file
View file

@ -0,0 +1,316 @@
// stb_perlin.h - v0.3 - perlin noise
// public domain single-file C implementation by Sean Barrett
//
// LICENSE
//
// See end of file.
//
//
// to create the implementation,
// #define STB_PERLIN_IMPLEMENTATION
// in *one* C/CPP file that includes this file.
//
//
// Documentation:
//
// float stb_perlin_noise3( float x,
// float y,
// float z,
// int x_wrap=0,
// int y_wrap=0,
// int z_wrap=0)
//
// This function computes a random value at the coordinate (x,y,z).
// Adjacent random values are continuous but the noise fluctuates
// its randomness with period 1, i.e. takes on wholly unrelated values
// at integer points. Specifically, this implements Ken Perlin's
// revised noise function from 2002.
//
// The "wrap" parameters can be used to create wraparound noise that
// wraps at powers of two. The numbers MUST be powers of two. Specify
// 0 to mean "don't care". (The noise always wraps every 256 due
// details of the implementation, even if you ask for larger or no
// wrapping.)
//
// Fractal Noise:
//
// Three common fractal noise functions are included, which produce
// a wide variety of nice effects depending on the parameters
// provided. Note that each function will call stb_perlin_noise3
// 'octaves' times, so this parameter will affect runtime.
//
// float stb_perlin_ridge_noise3(float x, float y, float z,
// float lacunarity, float gain, float offset, int octaves,
// int x_wrap, int y_wrap, int z_wrap);
//
// float stb_perlin_fbm_noise3(float x, float y, float z,
// float lacunarity, float gain, int octaves,
// int x_wrap, int y_wrap, int z_wrap);
//
// float stb_perlin_turbulence_noise3(float x, float y, float z,
// float lacunarity, float gain,int octaves,
// int x_wrap, int y_wrap, int z_wrap);
//
// Typical values to start playing with:
// octaves = 6 -- number of "octaves" of noise3() to sum
// lacunarity = ~ 2.0 -- spacing between successive octaves (use exactly 2.0 for wrapping output)
// gain = 0.5 -- relative weighting applied to each successive octave
// offset = 1.0? -- used to invert the ridges, may need to be larger, not sure
//
//
// Contributors:
// Jack Mott - additional noise functions
//
#ifdef __cplusplus
extern "C" {
#endif
extern float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap);
extern float stb_perlin_ridge_noise3(float x, float y, float z,float lacunarity, float gain, float offset, int octaves,int x_wrap, int y_wrap, int z_wrap);
extern float stb_perlin_fbm_noise3(float x, float y, float z,float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap);
extern float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap);
#ifdef __cplusplus
}
#endif
#ifdef STB_PERLIN_IMPLEMENTATION
// not same permutation table as Perlin's reference to avoid copyright issues;
// Perlin's table can be found at http://mrl.nyu.edu/~perlin/noise/
// @OPTIMIZE: should this be unsigned char instead of int for cache?
static unsigned char stb__perlin_randtab[512] =
{
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
// and a second copy so we don't need an extra mask or static initializer
23, 125, 161, 52, 103, 117, 70, 37, 247, 101, 203, 169, 124, 126, 44, 123,
152, 238, 145, 45, 171, 114, 253, 10, 192, 136, 4, 157, 249, 30, 35, 72,
175, 63, 77, 90, 181, 16, 96, 111, 133, 104, 75, 162, 93, 56, 66, 240,
8, 50, 84, 229, 49, 210, 173, 239, 141, 1, 87, 18, 2, 198, 143, 57,
225, 160, 58, 217, 168, 206, 245, 204, 199, 6, 73, 60, 20, 230, 211, 233,
94, 200, 88, 9, 74, 155, 33, 15, 219, 130, 226, 202, 83, 236, 42, 172,
165, 218, 55, 222, 46, 107, 98, 154, 109, 67, 196, 178, 127, 158, 13, 243,
65, 79, 166, 248, 25, 224, 115, 80, 68, 51, 184, 128, 232, 208, 151, 122,
26, 212, 105, 43, 179, 213, 235, 148, 146, 89, 14, 195, 28, 78, 112, 76,
250, 47, 24, 251, 140, 108, 186, 190, 228, 170, 183, 139, 39, 188, 244, 246,
132, 48, 119, 144, 180, 138, 134, 193, 82, 182, 120, 121, 86, 220, 209, 3,
91, 241, 149, 85, 205, 150, 113, 216, 31, 100, 41, 164, 177, 214, 153, 231,
38, 71, 185, 174, 97, 201, 29, 95, 7, 92, 54, 254, 191, 118, 34, 221,
131, 11, 163, 99, 234, 81, 227, 147, 156, 176, 17, 142, 69, 12, 110, 62,
27, 255, 0, 194, 59, 116, 242, 252, 19, 21, 187, 53, 207, 129, 64, 135,
61, 40, 167, 237, 102, 223, 106, 159, 197, 189, 215, 137, 36, 32, 22, 5,
};
static float stb__perlin_lerp(float a, float b, float t)
{
return a + (b-a) * t;
}
static int stb__perlin_fastfloor(float a)
{
int ai = (int) a;
return (a < ai) ? ai-1 : ai;
}
// different grad function from Perlin's, but easy to modify to match reference
static float stb__perlin_grad(int hash, float x, float y, float z)
{
static float basis[12][4] =
{
{ 1, 1, 0 },
{ -1, 1, 0 },
{ 1,-1, 0 },
{ -1,-1, 0 },
{ 1, 0, 1 },
{ -1, 0, 1 },
{ 1, 0,-1 },
{ -1, 0,-1 },
{ 0, 1, 1 },
{ 0,-1, 1 },
{ 0, 1,-1 },
{ 0,-1,-1 },
};
// perlin's gradient has 12 cases so some get used 1/16th of the time
// and some 2/16ths. We reduce bias by changing those fractions
// to 5/64ths and 6/64ths, and the same 4 cases get the extra weight.
static unsigned char indices[64] =
{
0,1,2,3,4,5,6,7,8,9,10,11,
0,9,1,11,
0,1,2,3,4,5,6,7,8,9,10,11,
0,1,2,3,4,5,6,7,8,9,10,11,
0,1,2,3,4,5,6,7,8,9,10,11,
0,1,2,3,4,5,6,7,8,9,10,11,
};
// if you use reference permutation table, change 63 below to 15 to match reference
// (this is why the ordering of the table above is funky)
float *grad = basis[indices[hash & 63]];
return grad[0]*x + grad[1]*y + grad[2]*z;
}
float stb_perlin_noise3(float x, float y, float z, int x_wrap, int y_wrap, int z_wrap)
{
float u,v,w;
float n000,n001,n010,n011,n100,n101,n110,n111;
float n00,n01,n10,n11;
float n0,n1;
unsigned int x_mask = (x_wrap-1) & 255;
unsigned int y_mask = (y_wrap-1) & 255;
unsigned int z_mask = (z_wrap-1) & 255;
int px = stb__perlin_fastfloor(x);
int py = stb__perlin_fastfloor(y);
int pz = stb__perlin_fastfloor(z);
int x0 = px & x_mask, x1 = (px+1) & x_mask;
int y0 = py & y_mask, y1 = (py+1) & y_mask;
int z0 = pz & z_mask, z1 = (pz+1) & z_mask;
int r0,r1, r00,r01,r10,r11;
#define stb__perlin_ease(a) (((a*6-15)*a + 10) * a * a * a)
x -= px; u = stb__perlin_ease(x);
y -= py; v = stb__perlin_ease(y);
z -= pz; w = stb__perlin_ease(z);
r0 = stb__perlin_randtab[x0];
r1 = stb__perlin_randtab[x1];
r00 = stb__perlin_randtab[r0+y0];
r01 = stb__perlin_randtab[r0+y1];
r10 = stb__perlin_randtab[r1+y0];
r11 = stb__perlin_randtab[r1+y1];
n000 = stb__perlin_grad(stb__perlin_randtab[r00+z0], x , y , z );
n001 = stb__perlin_grad(stb__perlin_randtab[r00+z1], x , y , z-1 );
n010 = stb__perlin_grad(stb__perlin_randtab[r01+z0], x , y-1, z );
n011 = stb__perlin_grad(stb__perlin_randtab[r01+z1], x , y-1, z-1 );
n100 = stb__perlin_grad(stb__perlin_randtab[r10+z0], x-1, y , z );
n101 = stb__perlin_grad(stb__perlin_randtab[r10+z1], x-1, y , z-1 );
n110 = stb__perlin_grad(stb__perlin_randtab[r11+z0], x-1, y-1, z );
n111 = stb__perlin_grad(stb__perlin_randtab[r11+z1], x-1, y-1, z-1 );
n00 = stb__perlin_lerp(n000,n001,w);
n01 = stb__perlin_lerp(n010,n011,w);
n10 = stb__perlin_lerp(n100,n101,w);
n11 = stb__perlin_lerp(n110,n111,w);
n0 = stb__perlin_lerp(n00,n01,v);
n1 = stb__perlin_lerp(n10,n11,v);
return stb__perlin_lerp(n0,n1,u);
}
float stb_perlin_ridge_noise3(float x, float y, float z,float lacunarity, float gain, float offset, int octaves,int x_wrap, int y_wrap, int z_wrap)
{
int i;
float frequency = 1.0f;
float prev = 1.0f;
float amplitude = 0.5f;
float sum = 0.0f;
for (i = 0; i < octaves; i++) {
float r = (float)(stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap));
r = r<0 ? -r : r; // fabs()
r = offset - r;
r = r*r;
sum += r*amplitude*prev;
prev = r;
frequency *= lacunarity;
amplitude *= gain;
}
return sum;
}
float stb_perlin_fbm_noise3(float x, float y, float z,float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap)
{
int i;
float frequency = 1.0f;
float amplitude = 1.0f;
float sum = 0.0f;
for (i = 0; i < octaves; i++) {
sum += stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap)*amplitude;
frequency *= lacunarity;
amplitude *= gain;
}
return sum;
}
float stb_perlin_turbulence_noise3(float x, float y, float z, float lacunarity, float gain, int octaves,int x_wrap, int y_wrap, int z_wrap)
{
int i;
float frequency = 1.0f;
float amplitude = 1.0f;
float sum = 0.0f;
for (i = 0; i < octaves; i++) {
float r = stb_perlin_noise3(x*frequency,y*frequency,z*frequency,x_wrap,y_wrap,z_wrap)*amplitude;
r = r<0 ? -r : r; // fabs()
sum += r;
frequency *= lacunarity;
amplitude *= gain;
}
return sum;
}
#endif // STB_PERLIN_IMPLEMENTATION
/*
------------------------------------------------------------------------------
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
------------------------------------------------------------------------------
*/

View file

@ -524,17 +524,6 @@ static int rect_height_compare(const void *a, const void *b)
return (p->w > q->w) ? -1 : (p->w < q->w);
}
static int rect_width_compare(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;
const stbrp_rect *q = (const stbrp_rect *) b;
if (p->w > q->w)
return -1;
if (p->w < q->w)
return 1;
return (p->h > q->h) ? -1 : (p->h < q->h);
}
static int rect_original_order(const void *a, const void *b)
{
const stbrp_rect *p = (const stbrp_rect *) a;

View file

@ -1,4 +1,4 @@
// stb_truetype.h - v1.15 - public domain
// stb_truetype.h - v1.17 - public domain
// authored from 2009-2016 by Sean Barrett / RAD Game Tools
//
// This library processes TrueType files:
@ -6,6 +6,7 @@
// extract glyph metrics
// extract glyph shapes
// render glyphs to one-channel bitmaps with antialiasing (box filter)
// render glyphs to one-channel SDF bitmaps (signed-distance field/function)
//
// Todo:
// non-MS cmaps
@ -26,9 +27,10 @@
// Ryan Gordon
// Simon Glass
// github:IntellectualKitty
// Imanol Celaya
//
// Bug/warning reports/fixes:
// "Zer" on mollyrocket (with fix)
// "Zer" on mollyrocket
// Cass Everitt
// stoiko (Haemimont Games)
// Brian Hook
@ -51,9 +53,12 @@
// Thomas Fields
// Derek Vinyard
// Cort Stratton
// github:oyvindjam
//
// VERSION HISTORY
//
// 1.17 (2017-07-23) make more arguments const; doc fix
// 1.16 (2017-07-12) SDF support
// 1.15 (2017-03-03) make more arguments const
// 1.14 (2017-01-16) num-fonts-in-TTC function
// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
@ -92,7 +97,7 @@
// Improved 3D API (more shippable):
// #include "stb_rect_pack.h" -- optional, but you really want it
// stbtt_PackBegin()
// stbtt_PackSetOversample() -- for improved quality on small fonts
// stbtt_PackSetOversampling() -- for improved quality on small fonts
// stbtt_PackFontRanges() -- pack and renders
// stbtt_PackEnd()
// stbtt_GetPackedQuad()
@ -110,6 +115,7 @@
// Character advance/positioning
// stbtt_GetCodepointHMetrics()
// stbtt_GetFontVMetrics()
// stbtt_GetFontVMetricsOS2()
// stbtt_GetCodepointKernAdvance()
//
// Starting with version 1.06, the rasterizer was replaced with a new,
@ -407,6 +413,18 @@ int main(int arg, char **argv)
#ifndef STBTT_sqrt
#include <math.h>
#define STBTT_sqrt(x) sqrt(x)
#define STBTT_pow(x,y) pow(x,y)
#endif
#ifndef STBTT_cos
#include <math.h>
#define STBTT_cos(x) cos(x)
#define STBTT_acos(x) acos(x)
#endif
#ifndef STBTT_fabs
#include <math.h>
#define STBTT_fabs(x) fabs(x)
#endif
#ifndef STBTT_fabs
@ -432,7 +450,7 @@ int main(int arg, char **argv)
#endif
#ifndef STBTT_memcpy
#include <memory.h>
#include <string.h>
#define STBTT_memcpy memcpy
#define STBTT_memset memset
#endif
@ -548,7 +566,7 @@ STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc);
#define STBTT_POINT_SIZE(x) (-(x))
STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size,
STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);
// Creates character bitmaps from the font_index'th font found in fontdata (use
// font_index=0 if you don't know what that is). It creates num_chars_in_range
@ -573,7 +591,7 @@ typedef struct
unsigned char h_oversample, v_oversample; // don't set these, they're used internally
} stbtt_pack_range;
STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);
// Creates character bitmaps from multiple ranges of characters stored in
// ranges. This will usually create a better-packed bitmap than multiple
// calls to stbtt_PackFontRange. Note that you can call this multiple
@ -715,6 +733,12 @@ STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, in
// these are expressed in unscaled coordinates, so you must multiply by
// the scale factor for a given size
STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap);
// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2
// table (specific to MS/Windows TTF files).
//
// Returns 1 on success (table present), 0 on failure.
STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);
// the bounding box around all possible characters
@ -809,6 +833,10 @@ STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, uns
// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel
// shift for the character
STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint);
// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering
// is performed (see stbtt_PackSetOversampling)
STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
// get the bbox of the bitmap centered around the glyph origin; so the
// bitmap width is ix1-ix0, height is iy1-iy0, and location to place
@ -826,6 +854,7 @@ STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float
STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);
STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph);
STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);
STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);
@ -848,6 +877,64 @@ STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap
int invert, // if non-zero, vertically flip shape
void *userdata); // context for to STBTT_MALLOC
//////////////////////////////////////////////////////////////////////////////
//
// Signed Distance Function (or Field) rendering
STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata);
// frees the SDF bitmap allocated below
STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);
// These functions compute a discretized SDF field for a single character, suitable for storing
// in a single-channel texture, sampling with bilinear filtering, and testing against
// larger than some threshhold to produce scalable fonts.
// info -- the font
// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap
// glyph/codepoint -- the character to generate the SDF for
// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0),
// which allows effects like bit outlines
// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)
// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale)
// if positive, > onedge_value is inside; if negative, < onedge_value is inside
// width,height -- output height & width of the SDF bitmap (including padding)
// xoff,yoff -- output origin of the character
// return value -- a 2D array of bytes 0..255, width*height in size
//
// pixel_dist_scale & onedge_value are a scale & bias that allows you to make
// optimal use of the limited 0..255 for your application, trading off precision
// and special effects. SDF values outside the range 0..255 are clamped to 0..255.
//
// Example:
// scale = stbtt_ScaleForPixelHeight(22)
// padding = 5
// onedge_value = 180
// pixel_dist_scale = 180/5.0 = 36.0
//
// This will create an SDF bitmap in which the character is about 22 pixels
// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled
// shape, sample the SDF at each pixel and fill the pixel if the SDF value
// is greater than or equal to 180/255. (You'll actually want to antialias,
// which is beyond the scope of this example.) Additionally, you can compute
// offset outlines (e.g. to stroke the character border inside & outside,
// or only outside). For example, to fill outside the character up to 3 SDF
// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above
// choice of variables maps a range from 5 pixels outside the shape to
// 2 pixels inside the shape to 0..255; this is intended primarily for apply
// outside effects only (the interior range is needed to allow proper
// antialiasing of the font at *smaller* sizes)
//
// The function computes the SDF analytically at each SDF pixel, not by e.g.
// building a higher-res bitmap and approximating it. In theory the quality
// should be as high as possible for an SDF of this size & representation, but
// unclear if this is true in practice (perhaps building a higher-res bitmap
// and computing from that can allow drop-out prevention).
//
// The algorithm has not been optimized at all, so expect it to be slow
// if computing lots of characters or very large sizes.
//////////////////////////////////////////////////////////////////////////////
//
// Finding the right font...
@ -2201,6 +2288,17 @@ STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, in
if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);
}
STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap)
{
int tab = stbtt__find_table(info->data, info->fontstart, "OS/2");
if (!tab)
return 0;
if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68);
if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70);
if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72);
return 1;
}
STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)
{
*x0 = ttSHORT(info->data + info->head + 36);
@ -2693,19 +2791,18 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
// from the other y segment, and it might ignored as an empty segment. to avoid
// that, we need to explicitly produce segments based on x positions.
// rename variables to clear pairs
// rename variables to clearly-defined pairs
float y0 = y_top;
float x1 = (float) (x);
float x2 = (float) (x+1);
float x3 = xb;
float y3 = y_bottom;
float y1,y2;
// x = e->x + e->dx * (y-y_top)
// (y-y_top) = (x - e->x) / e->dx
// y = (x - e->x) / e->dx + y_top
y1 = (x - x0) / dx + y_top;
y2 = (x+1 - x0) / dx + y_top;
float y1 = (x - x0) / dx + y_top;
float y2 = (x+1 - x0) / dx + y_top;
if (x0 < x1 && x3 > x2) { // three segments descending down-right
stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);
@ -3600,6 +3697,29 @@ STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stb
return k;
}
STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph)
{
stbtt_MakeGlyphBitmapSubpixel(info,
output,
out_w - (prefilter_x - 1),
out_h - (prefilter_y - 1),
out_stride,
scale_x,
scale_y,
shift_x,
shift_y,
glyph);
if (prefilter_x > 1)
stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x);
if (prefilter_y > 1)
stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y);
*sub_x = stbtt__oversample_shift(prefilter_x);
*sub_y = stbtt__oversample_shift(prefilter_y);
}
// rects array must be big enough to accommodate all characters in the given ranges
STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)
{
@ -3688,7 +3808,7 @@ STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect
stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);
}
STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)
{
stbtt_fontinfo info;
int i,j,n, return_value = 1;
@ -3724,7 +3844,7 @@ STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, unsigned char *fontd
return return_value;
}
STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, unsigned char *fontdata, int font_index, float font_size,
STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,
int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)
{
stbtt_pack_range range;
@ -3763,6 +3883,387 @@ STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int
*xpos += b->xadvance;
}
//////////////////////////////////////////////////////////////////////////////
//
// sdf computation
//
#define STBTT_min(a,b) ((a) < (b) ? (a) : (b))
#define STBTT_max(a,b) ((a) < (b) ? (b) : (a))
static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2])
{
float q0perp = q0[1]*ray[0] - q0[0]*ray[1];
float q1perp = q1[1]*ray[0] - q1[0]*ray[1];
float q2perp = q2[1]*ray[0] - q2[0]*ray[1];
float roperp = orig[1]*ray[0] - orig[0]*ray[1];
float a = q0perp - 2*q1perp + q2perp;
float b = q1perp - q0perp;
float c = q0perp - roperp;
float s0 = 0., s1 = 0.;
int num_s = 0;
if (a != 0.0) {
float discr = b*b - a*c;
if (discr > 0.0) {
float rcpna = -1 / a;
float d = (float) sqrt(discr);
s0 = (b+d) * rcpna;
s1 = (b-d) * rcpna;
if (s0 >= 0.0 && s0 <= 1.0)
num_s = 1;
if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) {
if (num_s == 0) s0 = s1;
++num_s;
}
}
} else {
// 2*b*s + c = 0
// s = -c / (2*b)
s0 = c / (-2 * b);
if (s0 >= 0.0 && s0 <= 1.0)
num_s = 1;
}
if (num_s == 0)
return 0;
else {
float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);
float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;
float q0d = q0[0]*rayn_x + q0[1]*rayn_y;
float q1d = q1[0]*rayn_x + q1[1]*rayn_y;
float q2d = q2[0]*rayn_x + q2[1]*rayn_y;
float rod = orig[0]*rayn_x + orig[1]*rayn_y;
float q10d = q1d - q0d;
float q20d = q2d - q0d;
float q0rd = q0d - rod;
hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;
hits[0][1] = a*s0+b;
if (num_s > 1) {
hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;
hits[1][1] = a*s1+b;
return 2;
} else {
return 1;
}
}
}
static int equal(float *a, float *b)
{
return (a[0] == b[0] && a[1] == b[1]);
}
static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts)
{
int i;
float orig[2], ray[2] = { 1, 0 };
float y_frac;
int winding = 0;
orig[0] = x;
orig[1] = y;
// make sure y never passes through a vertex of the shape
y_frac = (float) fmod(y, 1.0f);
if (y_frac < 0.01f)
y += 0.01f;
else if (y_frac > 0.99f)
y -= 0.01f;
orig[1] = y;
// test a ray from (-infinity,y) to (x,y)
for (i=0; i < nverts; ++i) {
if (verts[i].type == STBTT_vline) {
int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y;
int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y;
if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
if (x_inter < x)
winding += (y0 < y1) ? 1 : -1;
}
}
if (verts[i].type == STBTT_vcurve) {
int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ;
int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy;
int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ;
int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2));
int by = STBTT_max(y0,STBTT_max(y1,y2));
if (y > ay && y < by && x > ax) {
float q0[2],q1[2],q2[2];
float hits[2][2];
q0[0] = (float)x0;
q0[1] = (float)y0;
q1[0] = (float)x1;
q1[1] = (float)y1;
q2[0] = (float)x2;
q2[1] = (float)y2;
if (equal(q0,q1) || equal(q1,q2)) {
x0 = (int)verts[i-1].x;
y0 = (int)verts[i-1].y;
x1 = (int)verts[i ].x;
y1 = (int)verts[i ].y;
if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {
float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;
if (x_inter < x)
winding += (y0 < y1) ? 1 : -1;
}
} else {
int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);
if (num_hits >= 1)
if (hits[0][0] < 0)
winding += (hits[0][1] < 0 ? -1 : 1);
if (num_hits >= 2)
if (hits[1][0] < 0)
winding += (hits[1][1] < 0 ? -1 : 1);
}
}
}
}
return winding;
}
static float stbtt__cuberoot( float x )
{
if (x<0)
return -(float) STBTT_pow(-x,1.0f/3.0f);
else
return (float) STBTT_pow( x,1.0f/3.0f);
}
// x^3 + c*x^2 + b*x + a = 0
static int stbtt__solve_cubic(float a, float b, float c, float* r)
{
float s = -a / 3;
float p = b - a*a / 3;
float q = a * (2*a*a - 9*b) / 27 + c;
float p3 = p*p*p;
float d = q*q + 4*p3 / 27;
if (d >= 0) {
float z = (float) STBTT_sqrt(d);
float u = (-q + z) / 2;
float v = (-q - z) / 2;
u = stbtt__cuberoot(u);
v = stbtt__cuberoot(v);
r[0] = s + u + v;
return 1;
} else {
float u = (float) STBTT_sqrt(-p/3);
float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative
float m = (float) STBTT_cos(v);
float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;
r[0] = s + u * 2 * m;
r[1] = s - u * (m + n);
r[2] = s - u * (m - n);
//STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?
//STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);
//STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);
return 3;
}
}
STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
{
float scale_x = scale, scale_y = scale;
int ix0,iy0,ix1,iy1;
int w,h;
unsigned char *data;
// if one scale is 0, use same scale for both
if (scale_x == 0) scale_x = scale_y;
if (scale_y == 0) {
if (scale_x == 0) return NULL; // if both scales are 0, return NULL
scale_y = scale_x;
}
stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);
// if empty, return NULL
if (ix0 == ix1 || iy0 == iy1)
return NULL;
ix0 -= padding;
iy0 -= padding;
ix1 += padding;
iy1 += padding;
w = (ix1 - ix0);
h = (iy1 - iy0);
if (width ) *width = w;
if (height) *height = h;
if (xoff ) *xoff = ix0;
if (yoff ) *yoff = iy0;
// invert for y-downwards bitmaps
scale_y = -scale_y;
{
int x,y,i,j;
float *precompute;
stbtt_vertex *verts;
int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);
data = (unsigned char *) STBTT_malloc(w * h, info->userdata);
precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata);
for (i=0,j=num_verts-1; i < num_verts; j=i++) {
if (verts[i].type == STBTT_vline) {
float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;
float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));
precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;
} else if (verts[i].type == STBTT_vcurve) {
float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;
float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;
float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;
float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
float len2 = bx*bx + by*by;
if (len2 != 0.0f)
precompute[i] = 1.0f / (bx*bx + by*by);
else
precompute[i] = 0.0f;
} else
precompute[i] = 0.0f;
}
for (y=iy0; y < iy1; ++y) {
for (x=ix0; x < ix1; ++x) {
float val;
float min_dist = 999999.0f;
float sx = (float) x + 0.5f;
float sy = (float) y + 0.5f;
float x_gspace = (sx / scale_x);
float y_gspace = (sy / scale_y);
int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path
for (i=0; i < num_verts; ++i) {
float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
// check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve
float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
if (dist2 < min_dist*min_dist)
min_dist = (float) STBTT_sqrt(dist2);
if (verts[i].type == STBTT_vline) {
float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
// coarse culling against bbox
//if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
// sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
STBTT_assert(i != 0);
if (dist < min_dist) {
// check position along line
// x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0)
// minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy)
float dx = x1-x0, dy = y1-y0;
float px = x0-sx, py = y0-sy;
// minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy
// derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve
float t = -(px*dx + py*dy) / (dx*dx + dy*dy);
if (t >= 0.0f && t <= 1.0f)
min_dist = dist;
}
} else if (verts[i].type == STBTT_vcurve) {
float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y;
float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y;
float box_x0 = STBTT_min(STBTT_min(x0,x1),x2);
float box_y0 = STBTT_min(STBTT_min(y0,y1),y2);
float box_x1 = STBTT_max(STBTT_max(x0,x1),x2);
float box_y1 = STBTT_max(STBTT_max(y0,y1),y2);
// coarse culling against bbox to avoid computing cubic unnecessarily
if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {
int num=0;
float ax = x1-x0, ay = y1-y0;
float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
float mx = x0 - sx, my = y0 - sy;
float res[3],px,py,t,it;
float a_inv = precompute[i];
if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
float a = 3*(ax*bx + ay*by);
float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);
float c = mx*ax+my*ay;
if (a == 0.0) { // if a is 0, it's linear
if (b != 0.0) {
res[num++] = -c/b;
}
} else {
float discriminant = b*b - 4*a*c;
if (discriminant < 0)
num = 0;
else {
float root = (float) STBTT_sqrt(discriminant);
res[0] = (-b - root)/(2*a);
res[1] = (-b + root)/(2*a);
num = 2; // don't bother distinguishing 1-solution case, as code below will still work
}
}
} else {
float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point
float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;
float d = (mx*ax+my*ay) * a_inv;
num = stbtt__solve_cubic(b, c, d, res);
}
if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
t = res[0], it = 1.0f - t;
px = it*it*x0 + 2*t*it*x1 + t*t*x2;
py = it*it*y0 + 2*t*it*y1 + t*t*y2;
dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
if (dist2 < min_dist * min_dist)
min_dist = (float) STBTT_sqrt(dist2);
}
if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {
t = res[1], it = 1.0f - t;
px = it*it*x0 + 2*t*it*x1 + t*t*x2;
py = it*it*y0 + 2*t*it*y1 + t*t*y2;
dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
if (dist2 < min_dist * min_dist)
min_dist = (float) STBTT_sqrt(dist2);
}
if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {
t = res[2], it = 1.0f - t;
px = it*it*x0 + 2*t*it*x1 + t*t*x2;
py = it*it*y0 + 2*t*it*y1 + t*t*y2;
dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);
if (dist2 < min_dist * min_dist)
min_dist = (float) STBTT_sqrt(dist2);
}
}
}
}
if (winding == 0)
min_dist = -min_dist; // if outside the shape, value is negative
val = onedge_value + pixel_dist_scale * min_dist;
if (val < 0)
val = 0;
else if (val > 255)
val = 255;
data[(y-iy0)*w+(x-ix0)] = (unsigned char) val;
}
}
STBTT_free(precompute, info->userdata);
STBTT_free(verts, info->userdata);
}
return data;
}
STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)
{
return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff);
}
STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)
{
STBTT_free(bitmap, userdata);
}
//////////////////////////////////////////////////////////////////////////////
//
@ -3970,6 +4471,10 @@ STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const
// FULL VERSION HISTORY
//
// 1.16 (2017-07-12) SDF support
// 1.15 (2017-03-03) make more arguments const
// 1.14 (2017-01-16) num-fonts-in-TTC function
// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts
// 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

View file

@ -193,6 +193,7 @@
#undef __forceinline
#endif
#define __forceinline
#define alloca __builtin_alloca
#elif !defined(_MSC_VER)
#if __GNUC__
#define __forceinline inline

View file

@ -1,4 +1,4 @@
// Ogg Vorbis audio decoder - v1.10 - public domain
// Ogg Vorbis audio decoder - v1.11 - public domain
// http://nothings.org/stb_vorbis/
//
// Original version written by Sean Barrett in 2007.
@ -29,9 +29,10 @@
// Bernhard Wodo Evan Balster alxprd@github
// Tom Beaumont Ingo Leitgeb Nicolas Guillemot
// Phillip Bennefall Rohit Thiago Goulart
// manxorist@github saga musix
// manxorist@github saga musix github:infatum
//
// Partial history:
// 1.11 - 2017/07/23 - fix MinGW compilation
// 1.10 - 2017/03/03 - more robust seeking; fix negative ilog(); clear error in open_memory
// 1.09 - 2016/04/04 - back out 'truncation of last frame' fix from previous version
// 1.08 - 2016/04/02 - warnings; setup memory leaks; truncation of last frame

View file

@ -148,8 +148,9 @@ float GetGesturePinchAngle(void); // Get gesture pinch ang
int __stdcall QueryPerformanceCounter(unsigned long long int *lpPerformanceCount);
int __stdcall QueryPerformanceFrequency(unsigned long long int *lpFrequency);
#elif defined(__linux__)
#include <sys/time.h> // Required for: timespec
#include <time.h> // Required for: clock_gettime()
//#define _POSIX_C_SOURCE 199309L // Required for CLOCK_MONOTONIC if compiled with c99 without gnu ext.
#include <sys/time.h> // Required for: timespec
#include <time.h> // Required for: clock_gettime()
#endif
//----------------------------------------------------------------------------------

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,66 @@ package raylib
*/
import "C"
import "unsafe"
import "reflect"
// Shader location point type
const (
LocVertexPosition = iota
LocVertexTexcoord01
LocVertexTexcoord02
LocVertexNormal
LocVertexTangent
LocVertexColor
LocMatrixMvp
LocMatrixModel
LocMatrixView
LocMatrixProjection
LocVectorView
LocColorDiffuse
LocColorSpecular
LocColorAmbient
LocMapAlbedo
LocMapMetalness
LocMapNormal
LocMapRoughness
LocMapOccusion
LocMapEmission
LocMapHeight
LocMapCubemap
LocMapIrradiance
LocMapPrefilter
LocMapBrdf
)
// Material map type
const (
// MapDiffuse
MapAlbedo = iota
MapMetalness
MapNormal
MapRoughness
MapOcclusion
MapEmission
MapHeight
// NOTE: Uses GL_TEXTURE_CUBE_MAP
MapCubemap
// NOTE: Uses GL_TEXTURE_CUBE_MAP
MapIrradiance
// NOTE: Uses GL_TEXTURE_CUBE_MAP
MapPrefilter
MapBrdf
)
const (
MapDiffuse = MapAlbedo
MapSpecular = MapMetalness
LocMapDiffuse = LocMapAlbedo
LocMapSpecular = LocMapMetalness
)
const (
MaxShaderLocations = 32
MaxMaterialMaps = 12
)
// Mesh - Vertex data definning a mesh
type Mesh struct {
@ -50,22 +109,14 @@ func NewMeshFromPointer(ptr unsafe.Pointer) Mesh {
// Material type
type Material struct {
// Standard shader (supports 3 map textures)
// Shader
Shader Shader
// Diffuse texture (binded to shader mapTexture0Loc)
TexDiffuse Texture2D
// Normal texture (binded to shader mapTexture1Loc)
TexNormal Texture2D
// Specular texture (binded to shader mapTexture2Loc)
TexSpecular Texture2D
// Diffuse color
ColDiffuse Color
// Ambient color
ColAmbient Color
// Specular color
ColSpecular Color
// Glossiness level (Ranges from 0 to 1000)
Glossiness float32
// Maps
Maps [MaxMaterialMaps]MaterialMap
// Padding
_ [4]byte
// Generic parameters (if required)
Params *[]float32
}
func (m *Material) cptr() *C.Material {
@ -73,8 +124,8 @@ func (m *Material) cptr() *C.Material {
}
// NewMaterial - Returns new Material
func NewMaterial(shader Shader, texDiffuse, texNormal, texSpecular Texture2D, colDiffuse, colAmbient, colSpecular Color, glossiness float32) Material {
return Material{shader, texDiffuse, texNormal, texSpecular, colDiffuse, colAmbient, colSpecular, glossiness}
func NewMaterial(shader Shader, maps [MaxMaterialMaps]MaterialMap, params *[]float32) Material {
return Material{shader, maps, [4]byte{}, params}
}
// NewMaterialFromPointer - Returns new Material from pointer
@ -82,6 +133,16 @@ func NewMaterialFromPointer(ptr unsafe.Pointer) Material {
return *(*Material)(ptr)
}
// MaterialMap type
type MaterialMap struct {
// Texture
Texture Texture2D
// Color
Color Color
// Value
Value float32
}
// Model type
type Model struct {
// Vertex data buffers (RAM and VRAM)
@ -274,18 +335,6 @@ func LoadMesh(fileName string) Mesh {
return v
}
// LoadMeshEx - Load mesh from vertex data
func LoadMeshEx(numVertex int32, vData []float32, vtData []float32, vnData []float32, cData []Color) Mesh {
cnumVertex := (C.int)(numVertex)
cvData := (*C.float)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&vData)).Data))
cvtData := (*C.float)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&vtData)).Data))
cvnData := (*C.float)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&vnData)).Data))
ccData := (*C.Color)(unsafe.Pointer((*reflect.SliceHeader)(unsafe.Pointer(&cData)).Data))
ret := C.LoadMeshEx(cnumVertex, cvData, cvtData, cvnData, ccData)
v := NewMeshFromPointer(unsafe.Pointer(&ret))
return v
}
// LoadModel - Load model from file
func LoadModel(fileName string) Model {
cfileName := C.CString(fileName)
@ -296,32 +345,17 @@ func LoadModel(fileName string) Model {
}
// LoadModelFromMesh - Load model from mesh data
func LoadModelFromMesh(data Mesh, dynamic bool) Model {
func LoadModelFromMesh(data Mesh) Model {
cdata := data.cptr()
cdynamic := 0
if dynamic {
cdynamic = 1
}
ret := C.LoadModelFromMesh(*cdata, C.bool(cdynamic))
ret := C.LoadModelFromMesh(*cdata)
v := NewModelFromPointer(unsafe.Pointer(&ret))
return v
}
// LoadHeightmap - Load heightmap model from image data
func LoadHeightmap(heightmap *Image, size Vector3) Model {
cheightmap := heightmap.cptr()
csize := size.cptr()
ret := C.LoadHeightmap(*cheightmap, *csize)
v := NewModelFromPointer(unsafe.Pointer(&ret))
return v
}
// LoadCubicmap - Load cubes-based map model from image data
func LoadCubicmap(cubicmap *Image) Model {
ccubicmap := cubicmap.cptr()
ret := C.LoadCubicmap(*ccubicmap)
v := NewModelFromPointer(unsafe.Pointer(&ret))
return v
// UnloadModel - Unload model from memory (RAM and/or VRAM)
func UnloadModel(model Model) {
cmodel := model.cptr()
C.UnloadModel(*cmodel)
}
// UnloadMesh - Unload mesh from memory (RAM and/or VRAM)
@ -330,10 +364,104 @@ func UnloadMesh(mesh *Mesh) {
C.UnloadMesh(cmesh)
}
// UnloadModel - Unload model from memory (RAM and/or VRAM)
func UnloadModel(model Model) {
cmodel := model.cptr()
C.UnloadModel(*cmodel)
// GenMeshPlane - Generate plane mesh (with subdivisions)
func GenMeshPlane(width, length float32, resX, resZ int) Mesh {
cwidth := (C.float)(width)
clength := (C.float)(length)
cresX := (C.int)(resX)
cresZ := (C.int)(resZ)
ret := C.GenMeshPlane(cwidth, clength, cresX, cresZ)
v := NewMeshFromPointer(unsafe.Pointer(&ret))
return v
}
// GenMeshCube - Generate cuboid mesh
func GenMeshCube(width, height, length float32) Mesh {
cwidth := (C.float)(width)
cheight := (C.float)(height)
clength := (C.float)(length)
ret := C.GenMeshCube(cwidth, cheight, clength)
v := NewMeshFromPointer(unsafe.Pointer(&ret))
return v
}
// GenMeshSphere - Generate sphere mesh (standard sphere)
func GenMeshSphere(radius float32, rings, slices int) Mesh {
cradius := (C.float)(radius)
crings := (C.int)(rings)
cslices := (C.int)(slices)
ret := C.GenMeshSphere(cradius, crings, cslices)
v := NewMeshFromPointer(unsafe.Pointer(&ret))
return v
}
// GenMeshHemiSphere - Generate half-sphere mesh (no bottom cap)
func GenMeshHemiSphere(radius float32, rings, slices int) Mesh {
cradius := (C.float)(radius)
crings := (C.int)(rings)
cslices := (C.int)(slices)
ret := C.GenMeshHemiSphere(cradius, crings, cslices)
v := NewMeshFromPointer(unsafe.Pointer(&ret))
return v
}
// GenMeshCylinder - Generate cylinder mesh
func GenMeshCylinder(radius, height float32, slices int) Mesh {
cradius := (C.float)(radius)
cheight := (C.float)(height)
cslices := (C.int)(slices)
ret := C.GenMeshCylinder(cradius, cheight, cslices)
v := NewMeshFromPointer(unsafe.Pointer(&ret))
return v
}
// GenMeshTorus - Generate torus mesh
func GenMeshTorus(radius, size float32, radSeg, sides int) Mesh {
cradius := (C.float)(radius)
csize := (C.float)(size)
cradSeg := (C.int)(radSeg)
csides := (C.int)(sides)
ret := C.GenMeshTorus(cradius, csize, cradSeg, csides)
v := NewMeshFromPointer(unsafe.Pointer(&ret))
return v
}
// GenMeshKnot - Generate trefoil knot mesh
func GenMeshKnot(radius, size float32, radSeg, sides int) Mesh {
cradius := (C.float)(radius)
csize := (C.float)(size)
cradSeg := (C.int)(radSeg)
csides := (C.int)(sides)
ret := C.GenMeshKnot(cradius, csize, cradSeg, csides)
v := NewMeshFromPointer(unsafe.Pointer(&ret))
return v
}
// GenMeshHeightmap - Generate heightmap mesh from image data
func GenMeshHeightmap(heightmap Image, size Vector3) Mesh {
cheightmap := heightmap.cptr()
csize := size.cptr()
ret := C.GenMeshHeightmap(*cheightmap, *csize)
v := NewMeshFromPointer(unsafe.Pointer(&ret))
return v
}
// GenMeshCubicmap - Generate cubes-based map mesh from image data
func GenMeshCubicmap(cubicmap Image, size Vector3) Mesh {
ccubicmap := cubicmap.cptr()
csize := size.cptr()
ret := C.GenMeshCubicmap(*ccubicmap, *csize)
v := NewMeshFromPointer(unsafe.Pointer(&ret))
return v
}
// LoadMaterial - Load material data (.MTL)
@ -345,9 +473,9 @@ func LoadMaterial(fileName string) Material {
return v
}
// LoadDefaultMaterial - Load default material (uses default models shader)
func LoadDefaultMaterial() Material {
ret := C.LoadDefaultMaterial()
// LoadMaterialDefault - Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)
func LoadMaterialDefault() Material {
ret := C.LoadMaterialDefault()
v := NewMaterialFromPointer(unsafe.Pointer(&ret))
return v
}

View file

@ -1,30 +1,29 @@
/**********************************************************************************************
/**********************************************************************************************
*
* raylib v1.7.0
* raylib v1.8.0
*
* A simple and easy-to-use library to learn videogames programming (www.raylib.com)
*
* FEATURES:
* - Library written in plain C code (C99)
* - Uses PascalCase/camelCase notation
* - Written in plain C code (C99) in PascalCase/camelCase notation
* - Multiple platforms support: Windows, Linux, Mac, Android, Raspberry Pi and HTML5
* - Hardware accelerated with OpenGL (1.1, 2.1, 3.3 or ES 2.0)
* - Unique OpenGL abstraction layer (usable as standalone module): [rlgl]
* - Powerful fonts module with SpriteFonts support (XNA bitmap fonts, AngelCode fonts, TTF)
* - Multiple textures support, including compressed formats and mipmaps generation
* - Basic 3d support for Shapes, Models, Billboards, Heightmaps and Cubicmaps
* - Powerful math module for Vector, Matrix and Quaternion operations: [raymath]
* - Outstanding texture formats support, including compressed formats (DXT, ETC, PVRT, ASTC)
* - Basic 3d support for Geometrics, Models, Billboards, Heightmaps and Cubicmaps
* - Flexible Materials system, supporting classic maps and PBR maps
* - Shaders support, including Model shaders and Postprocessing shaders
* - Powerful math module for Vector2, Vector3, 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 bindings for Lua, Go and Pascal
* - Complete bindings to LUA (raylib-lua) and Go (raylib-go)
*
* 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]
* One custom font is loaded by default when InitWindow() [core]
* If using OpenGL 3.3 or ES2, one default shader is loaded automatically (internally defined) [rlgl]
* 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]
@ -33,12 +32,16 @@
*
* OPTIONAL DEPENDENCIES:
* stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA) [textures]
* stb_image_resize (Sean Barret) for image resizing algorythms [textures]
* stb_image_write (Sean Barret) for image writting (PNG) [utils]
* stb_truetype (Sean Barret) for ttf fonts loading [text]
* stb_vorbis (Sean Barret) for ogg audio loading [audio]
* stb_perlin (Sean Barret) for Perlin noise image generation [textures]
* par_shapes (Philip Rideout) for parametric 3d shapes generation [models]
* jar_xm (Joshua Reisenauer) for XM audio module loading [audio]
* jar_mod (Joshua Reisenauer) for MOD audio module loading [audio]
* dr_flac (David Reid) for FLAC audio file loading [audio]
* rgif (Charlie Tangora, Ramon Santamaria) for GIF recording [core]
* tinfl for data decompression (DEFLATE algorithm) [rres]
*
*
@ -76,14 +79,17 @@
//#define PLATFORM_WEB // HTML5 (emscripten, asm.js)
// Security check in case no PLATFORM_* defined
#if !defined(PLATFORM_DESKTOP) && !defined(PLATFORM_ANDROID) && !defined(PLATFORM_RPI) && !defined(PLATFORM_WEB)
#define PLATFORM_DESKTOP
#if !defined(PLATFORM_DESKTOP) && \
!defined(PLATFORM_ANDROID) && \
!defined(PLATFORM_RPI) && \
!defined(PLATFORM_WEB)
#define PLATFORM_DESKTOP
#endif
#if defined(_WIN32) && defined(BUILDING_DLL)
#define RLAPI __declspec(dllexport) // We are building raylib as a Win32 DLL
#elif defined(_WIN32) && defined(RAYLIB_DLL)
#define RLAPI __declspec(dllimport) // We are using raylib as a Win32 DLL
#if defined(_WIN32) && defined(BUILD_LIBTYPE_SHARED)
#define RLAPI __declspec(dllexport) // We are building raylib as a Win32 shared library (.dll)
#elif defined(_WIN32) && defined(USE_LIBTYPE_SHARED)
#define RLAPI __declspec(dllimport) // We are using raylib as a Win32 shared library (.dll)
#else
#define RLAPI // We are building or using raylib as a static library (or Linux shared library)
#endif
@ -293,14 +299,17 @@
#define MAGENTA CLITERAL{ 255, 0, 255, 255 } // Magenta
#define RAYWHITE CLITERAL{ 245, 245, 245, 255 } // My own White (raylib logo)
// Shader and material limits
#define MAX_SHADER_LOCATIONS 32 // Maximum number of predefined locations stored in shader struct
#define MAX_MATERIAL_MAPS 12 // Maximum number of texture maps stored in shader struct
//----------------------------------------------------------------------------------
// Structures Definition
//----------------------------------------------------------------------------------
#ifndef __cplusplus
// Boolean type
#if !defined(_STDBOOL_H)
#ifndef bool
typedef enum { false, true } bool;
#define _STDBOOL_H
#endif
#endif
@ -351,7 +360,7 @@ typedef struct Image {
int format; // Data format (TextureFormat type)
} Image;
// Texture2D type, bpp always RGBA (32bit)
// Texture2D type
// NOTE: Data stored in GPU memory
typedef struct Texture2D {
unsigned int id; // OpenGL texture id
@ -403,63 +412,46 @@ typedef struct Camera2D {
// Bounding box type
typedef struct BoundingBox {
Vector3 min; // minimum vertex box-corner
Vector3 max; // maximum vertex box-corner
Vector3 min; // Minimum vertex box-corner
Vector3 max; // Maximum vertex box-corner
} BoundingBox;
// Vertex data definning a mesh
// NOTE: Data stored in CPU memory (and GPU)
typedef struct Mesh {
int vertexCount; // number of vertices stored in arrays
int triangleCount; // number of triangles stored (indexed or not)
float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0)
float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5)
float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4)
unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
unsigned short *indices;// vertex indices (in case vertex data comes indexed)
int vertexCount; // Number of vertices stored in arrays
int triangleCount; // Number of triangles stored (indexed or not)
float *vertices; // Vertex position (XYZ - 3 components per vertex) (shader-location = 0)
float *texcoords; // Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
float *texcoords2; // Vertex second texture coordinates (useful for lightmaps) (shader-location = 5)
float *normals; // Vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
float *tangents; // Vertex tangents (XYZ - 3 components per vertex) (shader-location = 4)
unsigned char *colors; // Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
unsigned short *indices;// Vertex indices (in case vertex data comes indexed)
unsigned int vaoId; // OpenGL Vertex Array Object id
unsigned int vboId[7]; // OpenGL Vertex Buffer Objects id (7 types of vertex data)
} Mesh;
// Shader type (generic shader)
// Shader type (generic)
typedef struct Shader {
unsigned int id; // Shader program id
// Vertex attributes locations (default locations)
int vertexLoc; // Vertex attribute location point (default-location = 0)
int texcoordLoc; // Texcoord attribute location point (default-location = 1)
int texcoord2Loc; // Texcoord2 attribute location point (default-location = 5)
int normalLoc; // Normal attribute location point (default-location = 2)
int tangentLoc; // Tangent attribute location point (default-location = 4)
int colorLoc; // Color attibute location point (default-location = 3)
// Uniform locations
int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader)
int colDiffuseLoc; // Diffuse color uniform location point (fragment shader)
int colAmbientLoc; // Ambient color uniform location point (fragment shader)
int colSpecularLoc; // Specular color uniform location point (fragment shader)
// Texture map locations (generic for any kind of map)
int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0)
int mapTexture1Loc; // Map texture uniform location point (default-texture-unit = 1)
int mapTexture2Loc; // Map texture uniform location point (default-texture-unit = 2)
unsigned int id; // Shader program id
int locs[MAX_SHADER_LOCATIONS]; // Shader locations array
} Shader;
// Material type
// Material texture map
typedef struct MaterialMap {
Texture2D texture; // Material map texture
Color color; // Material map color
float value; // Material map value
} MaterialMap;
// Material type (generic)
typedef struct Material {
Shader shader; // Standard shader (supports 3 map textures)
Texture2D texDiffuse; // Diffuse texture (binded to shader mapTexture0Loc)
Texture2D texNormal; // Normal texture (binded to shader mapTexture1Loc)
Texture2D texSpecular; // Specular texture (binded to shader mapTexture2Loc)
Color colDiffuse; // Diffuse color
Color colAmbient; // Ambient color
Color colSpecular; // Specular color
float glossiness; // Glossiness level (Ranges from 0 to 1000)
Shader shader; // Material shader
MaterialMap maps[MAX_MATERIAL_MAPS]; // Material maps
float *params; // Material generic parameters (if required)
} Material;
// Model type
@ -475,12 +467,12 @@ typedef struct Ray {
Vector3 direction; // Ray direction
} Ray;
// Information returned from a raycast
// Raycast hit information
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
Vector3 position; // Position of nearest hit
Vector3 normal; // Surface normal of hit
} RayHitInfo;
// Wave type, defines audio wave data
@ -531,18 +523,82 @@ typedef struct RRESData {
// RRES type (pointer to RRESData array)
typedef struct RRESData *RRES;
// Head-Mounted-Display device parameters
typedef struct VrDeviceInfo {
int hResolution; // HMD horizontal resolution in pixels
int vResolution; // HMD vertical resolution in pixels
float hScreenSize; // HMD horizontal size in meters
float vScreenSize; // HMD vertical size in meters
float vScreenCenter; // HMD screen center in meters
float eyeToScreenDistance; // HMD distance between eye and display in meters
float lensSeparationDistance; // HMD lens separation distance in meters
float interpupillaryDistance; // HMD IPD (distance between pupils) in meters
float lensDistortionValues[4]; // HMD lens distortion constant parameters
float chromaAbCorrection[4]; // HMD chromatic aberration correction parameters
} VrDeviceInfo;
//----------------------------------------------------------------------------------
// Enumerators Definition
//----------------------------------------------------------------------------------
// Trace log type
typedef enum {
INFO = 0,
WARNING,
ERROR,
DEBUG,
OTHER
LOG_INFO = 0,
LOG_WARNING,
LOG_ERROR,
LOG_DEBUG,
LOG_OTHER
} LogType;
// Shader location point type
typedef enum {
LOC_VERTEX_POSITION = 0,
LOC_VERTEX_TEXCOORD01,
LOC_VERTEX_TEXCOORD02,
LOC_VERTEX_NORMAL,
LOC_VERTEX_TANGENT,
LOC_VERTEX_COLOR,
LOC_MATRIX_MVP,
LOC_MATRIX_MODEL,
LOC_MATRIX_VIEW,
LOC_MATRIX_PROJECTION,
LOC_VECTOR_VIEW,
LOC_COLOR_DIFFUSE,
LOC_COLOR_SPECULAR,
LOC_COLOR_AMBIENT,
LOC_MAP_ALBEDO, // LOC_MAP_DIFFUSE
LOC_MAP_METALNESS, // LOC_MAP_SPECULAR
LOC_MAP_NORMAL,
LOC_MAP_ROUGHNESS,
LOC_MAP_OCCUSION,
LOC_MAP_EMISSION,
LOC_MAP_HEIGHT,
LOC_MAP_CUBEMAP,
LOC_MAP_IRRADIANCE,
LOC_MAP_PREFILTER,
LOC_MAP_BRDF
} ShaderLocationIndex;
#define LOC_MAP_DIFFUSE LOC_MAP_ALBEDO
#define LOC_MAP_SPECULAR LOC_MAP_METALNESS
// Material map type
typedef enum {
MAP_ALBEDO = 0, // MAP_DIFFUSE
MAP_METALNESS = 1, // MAP_SPECULAR
MAP_NORMAL = 2,
MAP_ROUGHNESS = 3,
MAP_OCCLUSION,
MAP_EMISSION,
MAP_HEIGHT,
MAP_CUBEMAP, // NOTE: Uses GL_TEXTURE_CUBE_MAP
MAP_IRRADIANCE, // NOTE: Uses GL_TEXTURE_CUBE_MAP
MAP_PREFILTER, // NOTE: Uses GL_TEXTURE_CUBE_MAP
MAP_BRDF
} TexmapIndex;
#define MAP_DIFFUSE MAP_ALBEDO
#define MAP_SPECULAR MAP_METALNESS
// Texture formats
// NOTE: Support depends on OpenGL version and platform
typedef enum {
@ -553,6 +609,7 @@ typedef enum {
UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha)
UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha)
UNCOMPRESSED_R8G8B8A8, // 32 bpp
UNCOMPRESSED_R32G32B32, // 32 bit per channel (float) - HDR
COMPRESSED_DXT1_RGB, // 4 bpp (no alpha)
COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha)
COMPRESSED_DXT3_RGBA, // 8 bpp
@ -622,13 +679,10 @@ typedef enum {
HMD_DEFAULT_DEVICE = 0,
HMD_OCULUS_RIFT_DK2,
HMD_OCULUS_RIFT_CV1,
HMD_OCULUS_GO,
HMD_VALVE_HTC_VIVE,
HMD_SAMSUNG_GEAR_VR,
HMD_GOOGLE_CARDBOARD,
HMD_SONY_PLAYSTATION_VR,
HMD_RAZER_OSVR,
HMD_FOVE_VR,
} VrDevice;
HMD_SONY_PSVR
} VrDeviceType;
// RRESData type
typedef enum {
@ -654,74 +708,94 @@ extern "C" { // Prevents name mangling of functions
//------------------------------------------------------------------------------------
// Window and Graphics Device Functions (Module: core)
//------------------------------------------------------------------------------------
#if defined(PLATFORM_ANDROID)
RLAPI void InitWindow(int width, int height, void *state); // Init Android Activity and OpenGL Graphics (struct android_app)
#elif defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
RLAPI void InitWindow(int width, int height, const char *title); // Initialize Window and OpenGL Graphics
#endif
RLAPI void CloseWindow(void); // Close Window and Terminate Context
RLAPI bool WindowShouldClose(void); // Detect if KEY_ESCAPE pressed or Close icon pressed
RLAPI bool IsWindowMinimized(void); // Detect if window has been minimized (or lost focus)
RLAPI void ToggleFullscreen(void); // Fullscreen toggle (only PLATFORM_DESKTOP)
// Window-related functions
#if defined(PLATFORM_ANDROID)
RLAPI void InitWindow(int width, int height, void *state); // Initialize Android activity
#elif defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
RLAPI void InitWindow(int width, int height, const char *title); // Initialize window and OpenGL context
#endif
RLAPI void CloseWindow(void); // Close window and unload OpenGL context
RLAPI bool WindowShouldClose(void); // Check if KEY_ESCAPE pressed or Close icon pressed
RLAPI bool IsWindowMinimized(void); // Check if window has been minimized (or lost focus)
RLAPI void ToggleFullscreen(void); // Toggle fullscreen mode (only PLATFORM_DESKTOP)
RLAPI void SetWindowIcon(Image image); // Set icon for window (only PLATFORM_DESKTOP)
RLAPI void SetWindowTitle(const char *title); // Set title for window (only PLATFORM_DESKTOP)
RLAPI void SetWindowPosition(int x, int y); // Set window position on screen (only PLATFORM_DESKTOP)
RLAPI void SetWindowMonitor(int monitor); // Set monitor for the current window (fullscreen mode)
RLAPI void SetWindowMinSize(int width, int height); // Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE)
RLAPI int GetScreenWidth(void); // Get current screen width
RLAPI int GetScreenHeight(void); // Get current screen height
#if !defined(PLATFORM_ANDROID)
// Cursor-related functions
RLAPI void ShowCursor(void); // Shows cursor
RLAPI void HideCursor(void); // Hides cursor
RLAPI bool IsCursorHidden(void); // Returns true if cursor is not visible
RLAPI void EnableCursor(void); // Enables cursor
RLAPI void DisableCursor(void); // Disables cursor
RLAPI bool IsCursorHidden(void); // Check if cursor is not visible
RLAPI void EnableCursor(void); // Enables cursor (unlock cursor)
RLAPI void DisableCursor(void); // Disables cursor (lock cursor)
#endif
RLAPI void ClearBackground(Color color); // Sets Background Color
RLAPI void BeginDrawing(void); // Setup drawing canvas to start drawing
RLAPI void EndDrawing(void); // End canvas drawing and Swap Buffers (Double Buffering)
RLAPI void Begin2dMode(Camera2D camera); // Initialize 2D mode with custom camera
RLAPI void End2dMode(void); // Ends 2D mode custom camera usage
RLAPI void Begin3dMode(Camera camera); // Initializes 3D mode for drawing (Camera setup)
// Drawing-related functions
RLAPI void ClearBackground(Color color); // Set background color (framebuffer clear color)
RLAPI void BeginDrawing(void); // Setup canvas (framebuffer) to start drawing
RLAPI void EndDrawing(void); // End canvas drawing and swap buffers (double buffering)
RLAPI void Begin2dMode(Camera2D camera); // Initialize 2D mode with custom camera (2D)
RLAPI void End2dMode(void); // Ends 2D mode with custom camera
RLAPI void Begin3dMode(Camera camera); // Initializes 3D mode with custom camera (3D)
RLAPI void End3dMode(void); // Ends 3D mode and returns to default 2D orthographic mode
RLAPI void BeginTextureMode(RenderTexture2D target); // Initializes render texture for drawing
RLAPI void EndTextureMode(void); // Ends drawing to render texture
// Screen-space-related functions
RLAPI Ray GetMouseRay(Vector2 mousePosition, Camera camera); // Returns a ray trace from mouse position
RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position from a 3d world space position
RLAPI Vector2 GetWorldToScreen(Vector3 position, Camera camera); // Returns the screen space position for a 3d world space position
RLAPI Matrix GetCameraMatrix(Camera camera); // Returns camera transform matrix (view matrix)
// Timming-related functions
RLAPI void SetTargetFPS(int fps); // Set target FPS (maximum)
RLAPI int GetFPS(void); // Returns current FPS
RLAPI float GetFrameTime(void); // Returns time in seconds for one frame
RLAPI float GetFrameTime(void); // Returns time in seconds for last frame drawn
RLAPI Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value
// Color-related functions
RLAPI int GetHexValue(Color color); // Returns hexadecimal value for a Color
RLAPI float *ColorToFloat(Color color); // Converts Color to float array and normalizes
RLAPI float *VectorToFloat(Vector3 vec); // Converts Vector3 to float array
RLAPI float *MatrixToFloat(Matrix mat); // Converts Matrix to float array
RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included)
RLAPI Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value
RLAPI Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f
RLAPI float *ColorToFloat(Color color); // Converts Color to float array and normalizes
RLAPI void ShowLogo(void); // Activates raylib logo at startup (can be done with flags)
RLAPI void SetConfigFlags(char flags); // Setup some window configuration flags
RLAPI void TraceLog(int logType, const char *text, ...); // Show trace log messages (INFO, WARNING, ERROR, DEBUG)
RLAPI void TakeScreenshot(void); // Takes a screenshot and saves it in the same folder as executable
// Math useful functions (available from raymath.h)
RLAPI float *VectorToFloat(Vector3 vec); // Returns Vector3 as float array
RLAPI float *MatrixToFloat(Matrix mat); // Returns Matrix as float array
RLAPI Vector3 Vector3Zero(void); // Vector with components value 0.0f
RLAPI Vector3 Vector3One(void); // Vector with components value 1.0f
RLAPI Matrix MatrixIdentity(void); // Returns identity matrix
// Misc. functions
RLAPI void ShowLogo(void); // Activate raylib logo at startup (can be done with flags)
RLAPI void SetConfigFlags(char flags); // Setup window configuration flags (view FLAGS)
RLAPI void TraceLog(int logType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
RLAPI void TakeScreenshot(const char *fileName); // Takes a screenshot of current screen (saved a .png)
RLAPI int GetRandomValue(int min, int max); // Returns a random value between min and max (both included)
// Files management functions
RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension
RLAPI bool IsFileDropped(void); // Check if a file have been dropped into window
RLAPI char **GetDroppedFiles(int *count); // Retrieve dropped files into window
RLAPI const char *GetExtension(const char *fileName); // Get file extension
RLAPI const char *GetDirectoryPath(const char *fileName); // Get directory for a given fileName (with path)
RLAPI const char *GetWorkingDirectory(void); // Get current working directory
RLAPI bool ChangeDirectory(const char *dir); // Change working directory, returns true if success
RLAPI bool IsFileDropped(void); // Check if a file has been dropped into window
RLAPI char **GetDroppedFiles(int *count); // Get dropped files names
RLAPI void ClearDroppedFiles(void); // Clear dropped files paths buffer
RLAPI void StorageSaveValue(int position, int value); // Storage save integer value (to defined position)
RLAPI int StorageLoadValue(int position); // Storage load integer value (from defined position)
// Persistent storage management
RLAPI void StorageSaveValue(int position, int value); // Save integer value to storage file (to defined position)
RLAPI int StorageLoadValue(int position); // Load integer value from storage file (from defined position)
//------------------------------------------------------------------------------------
// Input Handling Functions (Module: core)
//------------------------------------------------------------------------------------
// Input-related functions: keyboard
RLAPI bool IsKeyPressed(int key); // Detect if a key has been pressed once
RLAPI bool IsKeyDown(int key); // Detect if a key is being pressed
RLAPI bool IsKeyReleased(int key); // Detect if a key has been released once
@ -729,6 +803,7 @@ RLAPI bool IsKeyUp(int key); // Detect if a key
RLAPI int GetKeyPressed(void); // Get latest key pressed
RLAPI void SetExitKey(int key); // Set a custom key to exit program (default is ESC)
// Input-related functions: gamepads
RLAPI bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available
RLAPI bool IsGamepadName(int gamepad, const char *name); // Check gamepad name (if available)
RLAPI const char *GetGamepadName(int gamepad); // Return gamepad internal name id
@ -740,6 +815,7 @@ RLAPI int GetGamepadButtonPressed(void); // Get the last ga
RLAPI int GetGamepadAxisCount(int gamepad); // Return gamepad axis count for a gamepad
RLAPI float GetGamepadAxisMovement(int gamepad, int axis); // Return axis movement value for a gamepad axis
// Input-related functions: mouse
RLAPI bool IsMouseButtonPressed(int button); // Detect if a mouse button has been pressed once
RLAPI bool IsMouseButtonDown(int button); // Detect if a mouse button is being pressed
RLAPI bool IsMouseButtonReleased(int button); // Detect if a mouse button has been released once
@ -750,6 +826,7 @@ RLAPI Vector2 GetMousePosition(void); // Returns mouse p
RLAPI void SetMousePosition(Vector2 position); // Set mouse position XY
RLAPI int GetMouseWheelMove(void); // Returns mouse wheel movement Y
// Input-related functions: touch
RLAPI int GetTouchX(void); // Returns touch position X for touch point 0 (relative to screen size)
RLAPI int GetTouchY(void); // Returns touch position Y for touch point 0 (relative to screen size)
RLAPI Vector2 GetTouchPosition(int index); // Returns touch position XY for a touch point index (relative to screen size)
@ -783,6 +860,8 @@ RLAPI void SetCameraMoveControls(int frontKey, int backKey,
//------------------------------------------------------------------------------------
// Basic Shapes Drawing Functions (Module: shapes)
//------------------------------------------------------------------------------------
// Basic shapes drawing functions
RLAPI void DrawPixel(int posX, int posY, Color color); // Draw a pixel
RLAPI void DrawPixelV(Vector2 position, Color color); // Draw a pixel (Vector version)
RLAPI void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw a line
@ -796,15 +875,19 @@ RLAPI void DrawCircleLines(int centerX, int centerY, float radius, Color color);
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 DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a vertical-gradient-filled rectangle
RLAPI void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2);// Draw a horizontal-gradient-filled rectangle
RLAPI void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // Draw a gradient-filled rectangle with custom vertex colors
RLAPI void DrawRectangleV(Vector2 position, Vector2 size, Color color); // Draw a color-filled rectangle (Vector version)
RLAPI void DrawRectangleLines(int posX, int posY, int width, int height, Color color); // Draw rectangle outline
RLAPI void DrawRectangleT(int posX, int posY, int width, int height, Color color); // Draw rectangle using text character
RLAPI void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw a color-filled triangle
RLAPI void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color); // Draw triangle outline
RLAPI void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color color); // Draw a regular polygon (Vector version)
RLAPI void DrawPolyEx(Vector2 *points, int numPoints, Color color); // Draw a closed polygon defined by points
RLAPI void DrawPolyExLines(Vector2 *points, int numPoints, Color color); // Draw polygon lines
// Basic shapes collision detection functions
RLAPI bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2); // Check collision between two rectangles
RLAPI bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2); // Check collision between two circles
RLAPI bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec); // Check collision between circle and rectangle
@ -816,6 +899,8 @@ RLAPI bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Ve
//------------------------------------------------------------------------------------
// Texture Loading and Drawing Functions (Module: textures)
//------------------------------------------------------------------------------------
// Image/Texture2D data loading/unloading/saving functions
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
@ -829,6 +914,9 @@ RLAPI void UnloadRenderTexture(RenderTexture2D target);
RLAPI Color *GetImageData(Image image); // Get pixel data from image as a Color struct array
RLAPI Image GetTextureData(Texture2D texture); // Get pixel data from GPU texture and return an Image
RLAPI void UpdateTexture(Texture2D texture, const void *pixels); // Update GPU texture with new data
RLAPI void SaveImageAs(const char *fileName, Image image); // Save image to a PNG file
// Image manipulation functions
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
@ -850,10 +938,23 @@ 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)
// Image generation functions
RLAPI Image GenImageColor(int width, int height, Color color); // Generate image: plain color
RLAPI Image GenImageGradientV(int width, int height, Color top, Color bottom); // Generate image: vertical gradient
RLAPI Image GenImageGradientH(int width, int height, Color left, Color right); // Generate image: horizontal gradient
RLAPI Image GenImageGradientRadial(int width, int height, float density, Color inner, Color outer); // Generate image: radial gradient
RLAPI Image GenImageChecked(int width, int height, int checksX, int checksY, Color col1, Color col2); // Generate image: checked
RLAPI Image GenImageWhiteNoise(int width, int height, float factor); // Generate image: white noise
RLAPI Image GenImagePerlinNoise(int width, int height, float scale); // Generate image: perlin noise
RLAPI Image GenImageCellular(int width, int height, int tileSize); // Generate image: cellular algorithm. Bigger tileSize means bigger cells
// Texture2D configuration functions
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
// Texture2D drawing functions
RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D
RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint); // Draw a Texture2D with position defined as Vector2
RLAPI void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters
@ -864,24 +965,30 @@ RLAPI void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle dest
//------------------------------------------------------------------------------------
// Font Loading and Text Drawing Functions (Module: text)
//------------------------------------------------------------------------------------
// SpriteFont loading/unloading functions
RLAPI SpriteFont GetDefaultFont(void); // Get the default SpriteFont
RLAPI SpriteFont LoadSpriteFont(const char *fileName); // Load SpriteFont from file into GPU memory (VRAM)
RLAPI SpriteFont LoadSpriteFontEx(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load SpriteFont from file with extended parameters
RLAPI void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory (VRAM)
// Text drawing functions
RLAPI void DrawFPS(int posX, int posY); // Shows current FPS
RLAPI void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font)
RLAPI void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, // Draw text using SpriteFont and additional parameters
float fontSize, int spacing, Color tint);
// Text misc. functions
RLAPI int MeasureText(const char *text, int fontSize); // Measure string width for default font
RLAPI Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, float fontSize, int spacing); // Measure string size for SpriteFont
RLAPI void DrawFPS(int posX, int posY); // Shows current FPS on top-left corner
RLAPI const char *FormatText(const char *text, ...); // Formatting of text with variables to 'embed'
RLAPI const char *SubText(const char *text, int position, int length); // Get a piece of a text string
//------------------------------------------------------------------------------------
// Basic 3d Shapes Drawing Functions (Module: models)
//------------------------------------------------------------------------------------
// Basic geometric 3D shapes drawing functions
RLAPI void DrawLine3D(Vector3 startPos, Vector3 endPos, Color color); // Draw a line in 3D world space
RLAPI void DrawCircle3D(Vector3 center, float radius, Vector3 rotationAxis, float rotationAngle, Color color); // Draw a circle in 3D world space
RLAPI void DrawCube(Vector3 position, float width, float height, float length, Color color); // Draw cube
@ -902,19 +1009,33 @@ RLAPI void DrawGizmo(Vector3 position);
//------------------------------------------------------------------------------------
// Model 3d Loading and Drawing Functions (Module: models)
//------------------------------------------------------------------------------------
RLAPI Mesh LoadMesh(const char *fileName); // Load mesh from file
RLAPI Mesh LoadMeshEx(int numVertex, float *vData, float *vtData, float *vnData, Color *cData); // Load mesh from vertex data
RLAPI Model LoadModel(const char *fileName); // Load model from file
RLAPI Model LoadModelFromMesh(Mesh data, bool dynamic); // Load model from mesh data
RLAPI Model LoadHeightmap(Image heightmap, Vector3 size); // Load heightmap model from image data
RLAPI Model LoadCubicmap(Image cubicmap); // Load cubes-based map model from image data
RLAPI void UnloadMesh(Mesh *mesh); // Unload mesh from memory (RAM and/or VRAM)
// Model loading/unloading functions
RLAPI Model LoadModel(const char *fileName); // Load model from files (mesh and material)
RLAPI Model LoadModelFromMesh(Mesh mesh); // Load model from generated mesh
RLAPI void UnloadModel(Model model); // Unload model from memory (RAM and/or VRAM)
// Mesh loading/unloading functions
RLAPI Mesh LoadMesh(const char *fileName); // Load mesh from file
RLAPI void UnloadMesh(Mesh *mesh); // Unload mesh from memory (RAM and/or VRAM)
// Mesh generation functions
RLAPI Mesh GenMeshPlane(float width, float length, int resX, int resZ); // Generate plane mesh (with subdivisions)
RLAPI Mesh GenMeshCube(float width, float height, float length); // Generate cuboid mesh
RLAPI Mesh GenMeshSphere(float radius, int rings, int slices); // Generate sphere mesh (standard sphere)
RLAPI Mesh GenMeshHemiSphere(float radius, int rings, int slices); // Generate half-sphere mesh (no bottom cap)
RLAPI Mesh GenMeshCylinder(float radius, float height, int slices); // Generate cylinder mesh
RLAPI Mesh GenMeshTorus(float radius, float size, int radSeg, int sides); // Generate torus mesh
RLAPI Mesh GenMeshKnot(float radius, float size, int radSeg, int sides); // Generate trefoil knot mesh
RLAPI Mesh GenMeshHeightmap(Image heightmap, Vector3 size); // Generate heightmap mesh from image data
RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize); // Generate cubes-based map mesh from image data
// Material loading/unloading functions
RLAPI Material LoadMaterial(const char *fileName); // Load material from file
RLAPI Material LoadDefaultMaterial(void); // Load default material (uses default models shader)
RLAPI Material LoadMaterialDefault(void); // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)
RLAPI void UnloadMaterial(Material material); // Unload material from GPU memory (VRAM)
// Model drawing functions
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
@ -922,11 +1043,11 @@ RLAPI void DrawModelWires(Model model, Vector3 position, float scale, Color tint
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
// Collision detection functions
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
@ -943,46 +1064,57 @@ RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight);
// Shaders System Functions (Module: rlgl)
// NOTE: This functions are useless when using OpenGL 1.1
//------------------------------------------------------------------------------------
// Shader loading/unloading functions
RLAPI char *LoadText(const char *fileName); // Load chars array from text file
RLAPI Shader LoadShader(char *vsFileName, char *fsFileName); // Load shader from files and bind default locations
RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM)
RLAPI Shader GetDefaultShader(void); // Get default shader
RLAPI Texture2D GetDefaultTexture(void); // Get default texture
RLAPI Shader GetShaderDefault(void); // Get default shader
RLAPI Texture2D GetTextureDefault(void); // Get default texture
// Shader configuration functions
RLAPI int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
RLAPI void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float)
RLAPI void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int)
RLAPI void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4)
RLAPI void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix)
RLAPI void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix)
// Texture maps generation (PBR)
// NOTE: Required shaders should be provided
RLAPI Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size); // Generate cubemap texture from HDR texture
RLAPI Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size); // Generate irradiance texture using cubemap data
RLAPI Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size); // Generate prefilter texture using cubemap data
RLAPI Texture2D GenTextureBRDF(Shader shader, Texture2D cubemap, int size); // Generate BRDF texture using cubemap data
// Shading begin/end functions
RLAPI void BeginShaderMode(Shader shader); // Begin custom shader drawing
RLAPI void EndShaderMode(void); // End custom shader drawing (use default shader)
RLAPI void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied)
RLAPI void EndBlendMode(void); // End blending mode (reset to default: alpha blending)
//------------------------------------------------------------------------------------
// VR experience Functions (Module: rlgl)
// NOTE: This functions are useless when using OpenGL 1.1
//------------------------------------------------------------------------------------
RLAPI void InitVrSimulator(int vrDevice); // Init VR simulator for selected device
// VR control functions
VrDeviceInfo GetVrDeviceInfo(int vrDeviceType); // Get VR device information for some standard devices
void InitVrSimulator(VrDeviceInfo info); // Init VR simulator for selected device parameters
RLAPI void CloseVrSimulator(void); // Close VR simulator for current device
RLAPI bool IsVrSimulatorReady(void); // Detect if VR device is ready
RLAPI bool IsVrSimulatorReady(void); // Detect if VR simulator is ready
RLAPI void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera
RLAPI void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator)
RLAPI void ToggleVrMode(void); // Enable/Disable VR experience
RLAPI void BeginVrDrawing(void); // Begin VR simulator stereo rendering
RLAPI void EndVrDrawing(void); // End VR simulator stereo rendering
//------------------------------------------------------------------------------------
// Audio Loading and Playing Functions (Module: audio)
//------------------------------------------------------------------------------------
// Audio device management functions
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)
// Wave/Sound loading/unloading functions
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
@ -990,6 +1122,8 @@ RLAPI Sound LoadSoundFromWave(Wave wave); // Load so
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
// Wave/Sound management functions
RLAPI void PlaySound(Sound sound); // Play a sound
RLAPI void PauseSound(Sound sound); // Pause a sound
RLAPI void ResumeSound(Sound sound); // Resume a paused sound
@ -1001,6 +1135,8 @@ RLAPI void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels);
RLAPI Wave WaveCopy(Wave wave); // Copy a wave to a new wave
RLAPI void WaveCrop(Wave *wave, int initSample, int finalSample); // Crop a wave to defined samples range
RLAPI float *GetWaveData(Wave wave); // Get samples data from wave as a floats array
// Music management functions
RLAPI Music LoadMusicStream(const char *fileName); // Load music stream from file
RLAPI void UnloadMusicStream(Music music); // Unload music stream
RLAPI void PlayMusicStream(Music music); // Start music playing
@ -1015,8 +1151,8 @@ RLAPI void SetMusicLoopCount(Music music, float count); // Set mus
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,
// AudioStream management functions
RLAPI AudioStream InitAudioStream(unsigned int sampleRate, unsigned int sampleSize,
unsigned int channels); // Init audio stream (to stream raw audio pcm data)
RLAPI void UpdateAudioStream(AudioStream stream, const void *data, int samplesCount); // Update audio stream buffers with data
RLAPI void CloseAudioStream(AudioStream stream); // Close audio stream and free memory

View file

@ -1,6 +1,6 @@
/**********************************************************************************************
*
* raymath v1.0 - Math functions to work with Vector3, Matrix and Quaternions
* raymath v1.1 - Math functions to work with Vector3, Matrix and Quaternions
*
* CONFIGURATION:
*
@ -19,7 +19,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2015 Ramon Santamaria (@raysan5)
* Copyright (c) 2015-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.
@ -124,7 +124,7 @@ RMDEF Vector2 Vector2Zero(void); // Vector with c
RMDEF Vector2 Vector2One(void); // Vector with components value 1.0f
RMDEF Vector2 Vector2Add(Vector2 v1, Vector2 v2); // Add two vectors (v1 + v2)
RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2); // Subtract two vectors (v1 - v2)
RMDEF float Vector2Lenght(Vector2 v); // Calculate vector lenght
RMDEF float Vector2Length(Vector2 v); // Calculate vector length
RMDEF float Vector2DotProduct(Vector2 v1, Vector2 v2); // Calculate two vectors dot product
RMDEF float Vector2Distance(Vector2 v1, Vector2 v2); // Calculate distance between two vectors
RMDEF float Vector2Angle(Vector2 v1, Vector2 v2); // Calculate angle between two vectors in X-axis
@ -136,24 +136,27 @@ RMDEF void Vector2Normalize(Vector2 *v); // Normalize pro
//------------------------------------------------------------------------------------
// Functions Declaration to work with Vector3
//------------------------------------------------------------------------------------
RMDEF Vector3 VectorZero(void); // Vector with components value 0.0f
RMDEF Vector3 VectorOne(void); // Vector with components value 1.0f
RMDEF Vector3 VectorAdd(Vector3 v1, Vector3 v2); // Add two vectors
RMDEF Vector3 VectorSubtract(Vector3 v1, Vector3 v2); // Substract two vectors
RMDEF Vector3 VectorCrossProduct(Vector3 v1, Vector3 v2); // Calculate two vectors cross product
RMDEF Vector3 VectorPerpendicular(Vector3 v); // Calculate one vector perpendicular vector
RMDEF float VectorLength(const Vector3 v); // Calculate vector lenght
RMDEF float VectorDotProduct(Vector3 v1, Vector3 v2); // Calculate two vectors dot product
RMDEF float VectorDistance(Vector3 v1, Vector3 v2); // Calculate distance between two points
RMDEF void VectorScale(Vector3 *v, float scale); // Scale provided vector
RMDEF void VectorNegate(Vector3 *v); // Negate provided vector (invert direction)
RMDEF void VectorNormalize(Vector3 *v); // Normalize provided vector
RMDEF void VectorTransform(Vector3 *v, Matrix mat); // Transforms a Vector3 by a given Matrix
RMDEF Vector3 VectorLerp(Vector3 v1, Vector3 v2, float amount); // Calculate linear interpolation between two vectors
RMDEF Vector3 VectorReflect(Vector3 vector, Vector3 normal); // Calculate reflected vector to normal
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 VectorBarycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c); // Barycenter coords for p in triangle abc
RMDEF Vector3 Vector3Zero(void); // Vector with components value 0.0f
RMDEF Vector3 Vector3One(void); // Vector with components value 1.0f
RMDEF Vector3 Vector3Add(Vector3 v1, Vector3 v2); // Add two vectors
RMDEF Vector3 Vector3Multiply(Vector3 v, float scalar); // Multiply vector by scalar
RMDEF Vector3 Vector3MultiplyV(Vector3 v1, Vector3 v2); // Multiply vector by vector
RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2); // Substract two vectors
RMDEF Vector3 Vector3CrossProduct(Vector3 v1, Vector3 v2); // Calculate two vectors cross product
RMDEF Vector3 Vector3Perpendicular(Vector3 v); // Calculate one vector perpendicular vector
RMDEF float Vector3Length(const Vector3 v); // Calculate vector length
RMDEF float Vector3DotProduct(Vector3 v1, Vector3 v2); // Calculate two vectors dot product
RMDEF float Vector3Distance(Vector3 v1, Vector3 v2); // Calculate distance between two points
RMDEF void Vector3Scale(Vector3 *v, float scale); // Scale provided vector
RMDEF void Vector3Negate(Vector3 *v); // Negate provided vector (invert direction)
RMDEF void Vector3Normalize(Vector3 *v); // Normalize provided vector
RMDEF void Vector3Transform(Vector3 *v, Matrix mat); // Transforms a Vector3 by a given Matrix
RMDEF Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount); // Calculate linear interpolation between two vectors
RMDEF Vector3 Vector3Reflect(Vector3 vector, Vector3 normal); // Calculate reflected vector to normal
RMDEF Vector3 Vector3Min(Vector3 vec1, Vector3 vec2); // Return min value for each pair of components
RMDEF Vector3 Vector3Max(Vector3 vec1, Vector3 vec2); // Return max value for each pair of components
RMDEF Vector3 Vector3Barycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c); // Barycenter coords for p in triangle abc
RMDEF float *Vector3ToFloat(Vector3 vec); // Returns Vector3 as float array
//------------------------------------------------------------------------------------
// Functions Declaration to work with Matrix
@ -177,20 +180,27 @@ RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top,
RMDEF Matrix MatrixPerspective(double fovy, double aspect, double near, double far); // Returns perspective projection matrix
RMDEF Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far); // Returns orthographic projection matrix
RMDEF Matrix MatrixLookAt(Vector3 position, Vector3 target, Vector3 up); // Returns camera look-at matrix (view matrix)
RMDEF float *MatrixToFloat(Matrix mat); // Returns float array of Matrix data
//------------------------------------------------------------------------------------
// Functions Declaration to work with Quaternions
//------------------------------------------------------------------------------------
RMDEF Quaternion QuaternionIdentity(void); // Returns identity quaternion
RMDEF float QuaternionLength(Quaternion quat); // Compute the length of a quaternion
RMDEF void QuaternionNormalize(Quaternion *q); // Normalize provided quaternion
RMDEF void QuaternionInvert(Quaternion *quat); // Invert provided quaternion
RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2); // Calculate two quaternion multiplication
RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float slerp); // Calculates spherical linear interpolation between two quaternions
RMDEF Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount); // Calculate linear interpolation between two quaternions
RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount); // Calculates spherical linear interpolation between two quaternions
RMDEF Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount); // Calculate slerp-optimized interpolation between two quaternions
RMDEF Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to); // Calculate quaternion based on the rotation from one vector to another
RMDEF Quaternion QuaternionFromMatrix(Matrix matrix); // Returns a quaternion for a given rotation matrix
RMDEF Matrix QuaternionToMatrix(Quaternion q); // Returns a matrix for a given quaternion
RMDEF Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle); // Returns rotation quaternion for an angle and axis
RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle); // Returns the rotation angle and axis for a given quaternion
RMDEF void QuaternionTransform(Quaternion *q, Matrix mat); // Transform a quaternion given a transformation matrix
RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle); // Returns the rotation angle and axis for a given quaternion
RMDEF Quaternion QuaternionFromEuler(float roll, float pitch, float yaw); // Returns he quaternion equivalent to Euler angles
RMDEF Vector3 QuaternionToEuler(Quaternion q); // Return the Euler angles equivalent to quaternion (roll, pitch, yaw)
RMDEF void QuaternionTransform(Quaternion *q, Matrix mat); // Transform a quaternion given a transformation matrix
#endif // notdef RAYMATH_EXTERN_INLINE
@ -234,8 +244,8 @@ RMDEF Vector2 Vector2Subtract(Vector2 v1, Vector2 v2)
return (Vector2){ v1.x - v2.x, v1.y - v2.y };
}
// Calculate vector lenght
RMDEF float Vector2Lenght(Vector2 v)
// Calculate vector length
RMDEF float Vector2Length(Vector2 v)
{
return sqrtf((v.x*v.x) + (v.y*v.y));
}
@ -285,7 +295,7 @@ RMDEF void Vector2Divide(Vector2 *v, float div)
// Normalize provided vector
RMDEF void Vector2Normalize(Vector2 *v)
{
Vector2Divide(v, Vector2Lenght(*v));
Vector2Divide(v, Vector2Length(*v));
}
//----------------------------------------------------------------------------------
@ -293,25 +303,47 @@ RMDEF void Vector2Normalize(Vector2 *v)
//----------------------------------------------------------------------------------
// Vector with components value 0.0f
RMDEF Vector3 VectorZero(void) { return (Vector3){ 0.0f, 0.0f, 0.0f }; }
RMDEF Vector3 Vector3Zero(void) { return (Vector3){ 0.0f, 0.0f, 0.0f }; }
// Vector with components value 1.0f
RMDEF Vector3 VectorOne(void) { return (Vector3){ 1.0f, 1.0f, 1.0f }; }
RMDEF Vector3 Vector3One(void) { return (Vector3){ 1.0f, 1.0f, 1.0f }; }
// Add two vectors
RMDEF Vector3 VectorAdd(Vector3 v1, Vector3 v2)
RMDEF Vector3 Vector3Add(Vector3 v1, Vector3 v2)
{
return (Vector3){ v1.x + v2.x, v1.y + v2.y, v1.z + v2.z };
}
// Substract two vectors
RMDEF Vector3 VectorSubtract(Vector3 v1, Vector3 v2)
RMDEF Vector3 Vector3Subtract(Vector3 v1, Vector3 v2)
{
return (Vector3){ v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
}
// Multiply vector by scalar
RMDEF Vector3 Vector3Multiply(Vector3 v, float scalar)
{
v.x *= scalar;
v.y *= scalar;
v.z *= scalar;
return v;
}
// Multiply vector by vector
RMDEF Vector3 Vector3MultiplyV(Vector3 v1, Vector3 v2)
{
Vector3 result;
result.x = v1.x * v2.x;
result.y = v1.y * v2.y;
result.z = v1.z * v2.z;
return result;
}
// Calculate two vectors cross product
RMDEF Vector3 VectorCrossProduct(Vector3 v1, Vector3 v2)
RMDEF Vector3 Vector3CrossProduct(Vector3 v1, Vector3 v2)
{
Vector3 result;
@ -323,7 +355,7 @@ RMDEF Vector3 VectorCrossProduct(Vector3 v1, Vector3 v2)
}
// Calculate one vector perpendicular vector
RMDEF Vector3 VectorPerpendicular(Vector3 v)
RMDEF Vector3 Vector3Perpendicular(Vector3 v)
{
Vector3 result;
@ -341,25 +373,25 @@ RMDEF Vector3 VectorPerpendicular(Vector3 v)
cardinalAxis = (Vector3){0.0f, 0.0f, 1.0f};
}
result = VectorCrossProduct(v, cardinalAxis);
result = Vector3CrossProduct(v, cardinalAxis);
return result;
}
// Calculate vector lenght
RMDEF float VectorLength(const Vector3 v)
// Calculate vector length
RMDEF float Vector3Length(const Vector3 v)
{
return sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
}
// Calculate two vectors dot product
RMDEF float VectorDotProduct(Vector3 v1, Vector3 v2)
RMDEF float Vector3DotProduct(Vector3 v1, Vector3 v2)
{
return (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);
}
// Calculate distance between two vectors
RMDEF float VectorDistance(Vector3 v1, Vector3 v2)
RMDEF float Vector3Distance(Vector3 v1, Vector3 v2)
{
float dx = v2.x - v1.x;
float dy = v2.y - v1.y;
@ -369,7 +401,7 @@ RMDEF float VectorDistance(Vector3 v1, Vector3 v2)
}
// Scale provided vector
RMDEF void VectorScale(Vector3 *v, float scale)
RMDEF void Vector3Scale(Vector3 *v, float scale)
{
v->x *= scale;
v->y *= scale;
@ -377,7 +409,7 @@ RMDEF void VectorScale(Vector3 *v, float scale)
}
// Negate provided vector (invert direction)
RMDEF void VectorNegate(Vector3 *v)
RMDEF void Vector3Negate(Vector3 *v)
{
v->x = -v->x;
v->y = -v->y;
@ -385,11 +417,11 @@ RMDEF void VectorNegate(Vector3 *v)
}
// Normalize provided vector
RMDEF void VectorNormalize(Vector3 *v)
RMDEF void Vector3Normalize(Vector3 *v)
{
float length, ilength;
length = VectorLength(*v);
length = Vector3Length(*v);
if (length == 0.0f) length = 1.0f;
@ -401,8 +433,7 @@ RMDEF void VectorNormalize(Vector3 *v)
}
// Transforms a Vector3 by a given Matrix
// TODO: Review math (matrix transpose required?)
RMDEF void VectorTransform(Vector3 *v, Matrix mat)
RMDEF void Vector3Transform(Vector3 *v, Matrix mat)
{
float x = v->x;
float y = v->y;
@ -414,7 +445,7 @@ RMDEF void VectorTransform(Vector3 *v, Matrix mat)
};
// Calculate linear interpolation between two vectors
RMDEF Vector3 VectorLerp(Vector3 v1, Vector3 v2, float amount)
RMDEF Vector3 Vector3Lerp(Vector3 v1, Vector3 v2, float amount)
{
Vector3 result;
@ -426,7 +457,7 @@ RMDEF Vector3 VectorLerp(Vector3 v1, Vector3 v2, float amount)
}
// Calculate reflected vector to normal
RMDEF Vector3 VectorReflect(Vector3 vector, Vector3 normal)
RMDEF Vector3 Vector3Reflect(Vector3 vector, Vector3 normal)
{
// I is the original vector
// N is the normal of the incident plane
@ -434,7 +465,7 @@ RMDEF Vector3 VectorReflect(Vector3 vector, Vector3 normal)
Vector3 result;
float dotProduct = VectorDotProduct(vector, normal);
float dotProduct = Vector3DotProduct(vector, normal);
result.x = vector.x - (2.0f*normal.x)*dotProduct;
result.y = vector.y - (2.0f*normal.y)*dotProduct;
@ -444,7 +475,7 @@ RMDEF Vector3 VectorReflect(Vector3 vector, Vector3 normal)
}
// Return min value for each pair of components
RMDEF Vector3 VectorMin(Vector3 vec1, Vector3 vec2)
RMDEF Vector3 Vector3Min(Vector3 vec1, Vector3 vec2)
{
Vector3 result;
@ -456,7 +487,7 @@ RMDEF Vector3 VectorMin(Vector3 vec1, Vector3 vec2)
}
// Return max value for each pair of components
RMDEF Vector3 VectorMax(Vector3 vec1, Vector3 vec2)
RMDEF Vector3 Vector3Max(Vector3 vec1, Vector3 vec2)
{
Vector3 result;
@ -469,18 +500,18 @@ RMDEF Vector3 VectorMax(Vector3 vec1, Vector3 vec2)
// 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 VectorBarycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c)
RMDEF Vector3 Vector3Barycenter(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);
Vector3 v0 = Vector3Subtract(b, a);
Vector3 v1 = Vector3Subtract(c, a);
Vector3 v2 = Vector3Subtract(p, a);
float d00 = Vector3DotProduct(v0, v0);
float d01 = Vector3DotProduct(v0, v1);
float d11 = Vector3DotProduct(v1, v1);
float d20 = Vector3DotProduct(v2, v0);
float d21 = Vector3DotProduct(v2, v1);
float denom = d00*d11 - d01*d01;
@ -493,6 +524,18 @@ RMDEF Vector3 VectorBarycenter(Vector3 p, Vector3 a, Vector3 b, Vector3 c)
return result;
}
// Returns Vector3 as float array
RMDEF float *Vector3ToFloat(Vector3 vec)
{
static float buffer[3];
buffer[0] = vec.x;
buffer[1] = vec.y;
buffer[2] = vec.z;
return buffer;
}
//----------------------------------------------------------------------------------
// Module Functions Definition - Matrix math
//----------------------------------------------------------------------------------
@ -683,10 +726,10 @@ RMDEF Matrix MatrixSubstract(Matrix left, Matrix right)
// Returns translation matrix
RMDEF Matrix MatrixTranslate(float x, float y, float z)
{
Matrix result = { 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
x, y, z, 1.0f };
Matrix result = { 1.0f, 0.0f, 0.0f, x,
0.0f, 1.0f, 0.0f, y,
0.0f, 0.0f, 1.0f, z,
0.0f, 0.0f, 0.0f, 1.0f };
return result;
}
@ -811,22 +854,22 @@ RMDEF Matrix MatrixMultiply(Matrix left, Matrix right)
{
Matrix result;
result.m0 = right.m0*left.m0 + right.m1*left.m4 + right.m2*left.m8 + right.m3*left.m12;
result.m1 = right.m0*left.m1 + right.m1*left.m5 + right.m2*left.m9 + right.m3*left.m13;
result.m2 = right.m0*left.m2 + right.m1*left.m6 + right.m2*left.m10 + right.m3*left.m14;
result.m3 = right.m0*left.m3 + right.m1*left.m7 + right.m2*left.m11 + right.m3*left.m15;
result.m4 = right.m4*left.m0 + right.m5*left.m4 + right.m6*left.m8 + right.m7*left.m12;
result.m5 = right.m4*left.m1 + right.m5*left.m5 + right.m6*left.m9 + right.m7*left.m13;
result.m6 = right.m4*left.m2 + right.m5*left.m6 + right.m6*left.m10 + right.m7*left.m14;
result.m7 = right.m4*left.m3 + right.m5*left.m7 + right.m6*left.m11 + right.m7*left.m15;
result.m8 = right.m8*left.m0 + right.m9*left.m4 + right.m10*left.m8 + right.m11*left.m12;
result.m9 = right.m8*left.m1 + right.m9*left.m5 + right.m10*left.m9 + right.m11*left.m13;
result.m10 = right.m8*left.m2 + right.m9*left.m6 + right.m10*left.m10 + right.m11*left.m14;
result.m11 = right.m8*left.m3 + right.m9*left.m7 + right.m10*left.m11 + right.m11*left.m15;
result.m12 = right.m12*left.m0 + right.m13*left.m4 + right.m14*left.m8 + right.m15*left.m12;
result.m13 = right.m12*left.m1 + right.m13*left.m5 + right.m14*left.m9 + right.m15*left.m13;
result.m14 = right.m12*left.m2 + right.m13*left.m6 + right.m14*left.m10 + right.m15*left.m14;
result.m15 = right.m12*left.m3 + right.m13*left.m7 + right.m14*left.m11 + right.m15*left.m15;
result.m0 = left.m0*right.m0 + left.m1*right.m4 + left.m2*right.m8 + left.m3*right.m12;
result.m1 = left.m0*right.m1 + left.m1*right.m5 + left.m2*right.m9 + left.m3*right.m13;
result.m2 = left.m0*right.m2 + left.m1*right.m6 + left.m2*right.m10 + left.m3*right.m14;
result.m3 = left.m0*right.m3 + left.m1*right.m7 + left.m2*right.m11 + left.m3*right.m15;
result.m4 = left.m4*right.m0 + left.m5*right.m4 + left.m6*right.m8 + left.m7*right.m12;
result.m5 = left.m4*right.m1 + left.m5*right.m5 + left.m6*right.m9 + left.m7*right.m13;
result.m6 = left.m4*right.m2 + left.m5*right.m6 + left.m6*right.m10 + left.m7*right.m14;
result.m7 = left.m4*right.m3 + left.m5*right.m7 + left.m6*right.m11 + left.m7*right.m15;
result.m8 = left.m8*right.m0 + left.m9*right.m4 + left.m10*right.m8 + left.m11*right.m12;
result.m9 = left.m8*right.m1 + left.m9*right.m5 + left.m10*right.m9 + left.m11*right.m13;
result.m10 = left.m8*right.m2 + left.m9*right.m6 + left.m10*right.m10 + left.m11*right.m14;
result.m11 = left.m8*right.m3 + left.m9*right.m7 + left.m10*right.m11 + left.m11*right.m15;
result.m12 = left.m12*right.m0 + left.m13*right.m4 + left.m14*right.m8 + left.m15*right.m12;
result.m13 = left.m12*right.m1 + left.m13*right.m5 + left.m14*right.m9 + left.m15*right.m13;
result.m14 = left.m12*right.m2 + left.m13*right.m6 + left.m14*right.m10 + left.m15*right.m14;
result.m15 = left.m12*right.m3 + left.m13*right.m7 + left.m14*right.m11 + left.m15*right.m15;
return result;
}
@ -864,9 +907,10 @@ RMDEF Matrix MatrixFrustum(double left, double right, double bottom, double top,
}
// Returns perspective projection matrix
// NOTE: Angle should be provided in radians
RMDEF Matrix MatrixPerspective(double fovy, double aspect, double near, double far)
{
double top = near*tan(fovy*PI/360.0);
double top = near*tan(fovy*0.5);
double right = top*aspect;
return MatrixFrustum(-right, right, -top, top, near, far);
@ -906,37 +950,70 @@ RMDEF Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up)
{
Matrix result;
Vector3 z = VectorSubtract(eye, target);
VectorNormalize(&z);
Vector3 x = VectorCrossProduct(up, z);
VectorNormalize(&x);
Vector3 y = VectorCrossProduct(z, x);
VectorNormalize(&y);
Vector3 z = Vector3Subtract(eye, target);
Vector3Normalize(&z);
Vector3 x = Vector3CrossProduct(up, z);
Vector3Normalize(&x);
Vector3 y = Vector3CrossProduct(z, x);
Vector3Normalize(&y);
result.m0 = x.x;
result.m1 = x.y;
result.m2 = x.z;
result.m3 = -((x.x*eye.x) + (x.y*eye.y) + (x.z*eye.z));
result.m3 = 0.0f;
result.m4 = y.x;
result.m5 = y.y;
result.m6 = y.z;
result.m7 = -((y.x*eye.x) + (y.y*eye.y) + (y.z*eye.z));
result.m7 = 0.0f;
result.m8 = z.x;
result.m9 = z.y;
result.m10 = z.z;
result.m11 = -((z.x*eye.x) + (z.y*eye.y) + (z.z*eye.z));
result.m12 = 0.0f;
result.m13 = 0.0f;
result.m14 = 0.0f;
result.m11 = 0.0f;
result.m12 = eye.x;
result.m13 = eye.y;
result.m14 = eye.z;
result.m15 = 1.0f;
MatrixInvert(&result);
return result;
}
// Returns float array of matrix data
RMDEF float *MatrixToFloat(Matrix mat)
{
static float buffer[16];
buffer[0] = mat.m0;
buffer[1] = mat.m1;
buffer[2] = mat.m2;
buffer[3] = mat.m3;
buffer[4] = mat.m4;
buffer[5] = mat.m5;
buffer[6] = mat.m6;
buffer[7] = mat.m7;
buffer[8] = mat.m8;
buffer[9] = mat.m9;
buffer[10] = mat.m10;
buffer[11] = mat.m11;
buffer[12] = mat.m12;
buffer[13] = mat.m13;
buffer[14] = mat.m14;
buffer[15] = mat.m15;
return buffer;
}
//----------------------------------------------------------------------------------
// Module Functions Definition - Quaternion math
//----------------------------------------------------------------------------------
// Returns identity quaternion
RMDEF Quaternion QuaternionIdentity(void)
{
return (Quaternion){ 0.0f, 0.0f, 0.0f, 1.0f };
}
// Computes the length of a quaternion
RMDEF float QuaternionLength(Quaternion quat)
{
@ -993,6 +1070,19 @@ RMDEF Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2)
return result;
}
// Calculate linear interpolation between two quaternions
RMDEF Quaternion QuaternionLerp(Quaternion q1, Quaternion q2, float amount)
{
Quaternion result;
result.x = q1.x + amount*(q2.x - q1.x);
result.y = q1.y + amount*(q2.y - q1.y);
result.z = q1.z + amount*(q2.z - q1.z);
result.w = q1.w + amount*(q2.w - q1.w);
return result;
}
// Calculates spherical linear interpolation between two quaternions
RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
{
@ -1001,6 +1091,7 @@ RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
float cosHalfTheta = q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w;
if (fabs(cosHalfTheta) >= 1.0f) result = q1;
else if (cosHalfTheta > 0.95f) result = QuaternionNlerp(q1, q2, amount);
else
{
float halfTheta = acos(cosHalfTheta);
@ -1028,6 +1119,37 @@ RMDEF Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
return result;
}
// Calculate slerp-optimized interpolation between two quaternions
RMDEF Quaternion QuaternionNlerp(Quaternion q1, Quaternion q2, float amount)
{
Quaternion result = QuaternionLerp(q1, q2, amount);
QuaternionNormalize(&result);
return result;
}
// Calculate quaternion based on the rotation from one vector to another
RMDEF Quaternion QuaternionFromVector3ToVector3(Vector3 from, Vector3 to)
{
Quaternion q = { 0 };
float cos2Theta = Vector3DotProduct(from, to);
Vector3 cross = Vector3CrossProduct(from, to);
q.x = cross.x;
q.y = cross.y;
q.z = cross.y;
q.w = 1.0f + cos2Theta; // NOTE: Added QuaternioIdentity()
// Normalize to essentially nlerp the original and identity to 0.5
QuaternionNormalize(&q);
// Above lines are equivalent to:
//Quaternion result = QuaternionNlerp(q, QuaternionIdentity(), 0.5f);
return q;
}
// Returns a quaternion for a given rotation matrix
RMDEF Quaternion QuaternionFromMatrix(Matrix matrix)
{
@ -1094,18 +1216,21 @@ RMDEF Matrix QuaternionToMatrix(Quaternion q)
float x2 = x + x;
float y2 = y + y;
float z2 = z + z;
float length = QuaternionLength(q);
float lengthSquared = length*length;
float xx = x*x2;
float xy = x*y2;
float xz = x*z2;
float xx = x*x2/lengthSquared;
float xy = x*y2/lengthSquared;
float xz = x*z2/lengthSquared;
float yy = y*y2;
float yz = y*z2;
float zz = z*z2;
float yy = y*y2/lengthSquared;
float yz = y*z2/lengthSquared;
float zz = z*z2/lengthSquared;
float wx = w*x2;
float wy = w*y2;
float wz = w*z2;
float wx = w*x2/lengthSquared;
float wy = w*y2/lengthSquared;
float wz = w*z2/lengthSquared;
result.m0 = 1.0f - (yy + zz);
result.m1 = xy - wz;
@ -1133,11 +1258,11 @@ RMDEF Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle)
{
Quaternion result = { 0.0f, 0.0f, 0.0f, 1.0f };
if (VectorLength(axis) != 0.0f)
if (Vector3Length(axis) != 0.0f)
angle *= 0.5f;
VectorNormalize(&axis);
Vector3Normalize(&axis);
float sinres = sinf(angle);
float cosres = cosf(angle);
@ -1180,6 +1305,51 @@ RMDEF void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle
*outAngle = resAngle;
}
// Returns he quaternion equivalent to Euler angles
RMDEF Quaternion QuaternionFromEuler(float roll, float pitch, float yaw)
{
Quaternion q = { 0 };
float x0 = cosf(roll*0.5f);
float x1 = sinf(roll*0.5f);
float y0 = cosf(pitch*0.5f);
float y1 = sinf(pitch*0.5f);
float z0 = cosf(yaw*0.5f);
float z1 = sinf(yaw*0.5f);
q.x = x1*y0*z0 - x0*y1*z1;
q.y = x0*y1*z0 + x1*y0*z1;
q.z = x0*y0*z1 - x1*y1*z0;
q.w = x0*y0*z0 + x1*y1*z1;
return q;
}
// Return the Euler angles equivalent to quaternion (roll, pitch, yaw)
// NOTE: Angles are returned in a Vector3 struct in degrees
RMDEF Vector3 QuaternionToEuler(Quaternion q)
{
Vector3 v = { 0 };
// roll (x-axis rotation)
float x0 = 2.0f*(q.w*q.x + q.y*q.z);
float x1 = 1.0f - 2.0f*(q.x*q.x + q.y*q.y);
v.x = atan2f(x0, x1)*RAD2DEG;
// pitch (y-axis rotation)
float y0 = 2.0f*(q.w*q.y - q.z*q.x);
y0 = y0 > 1.0f ? 1.0f : y0;
y0 = y0 < -1.0f ? -1.0f : y0;
v.y = asinf(y0)*RAD2DEG;
// yaw (z-axis rotation)
float z0 = 2.0f*(q.w*q.z + q.x*q.y);
float z1 = 1.0f - 2.0f*(q.y*q.y + q.z*q.z);
v.z = atan2f(z0, z1)*RAD2DEG;
return v;
}
// Transform a quaternion given a transformation matrix
RMDEF void QuaternionTransform(Quaternion *q, Matrix mat)
{

File diff suppressed because it is too large Load diff

View file

@ -17,7 +17,9 @@
* #define GRAPHICS_API_OPENGL_21
* #define GRAPHICS_API_OPENGL_33
* #define GRAPHICS_API_OPENGL_ES2
* Use selected OpenGL backend
* Use selected OpenGL graphics backend, should be supported by platform
* Those preprocessor defines are only used on rlgl module, if OpenGL version is
* required by any other module, use rlGetVersion() tocheck it
*
* #define RLGL_STANDALONE
* Use rlgl as standalone library (no raylib dependency)
@ -25,7 +27,7 @@
* #define SUPPORT_VR_SIMULATION / SUPPORT_STEREO_RENDERING
* Support VR simulation functionality (stereo rendering)
*
* #define SUPPORT_SHADER_DISTORTION
* #define SUPPORT_DISTORTION_SHADER
* Include stereo rendering distortion shader (shader_distortion.h)
*
* DEPENDENCIES:
@ -35,7 +37,7 @@
*
* LICENSE: zlib/libpng
*
* Copyright (c) 2014-2016 Ramon Santamaria (@raysan5)
* Copyright (c) 2014-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.
@ -57,28 +59,14 @@
#ifndef RLGL_H
#define RLGL_H
//#define RLGL_STANDALONE // NOTE: To use rlgl as standalone lib, just uncomment this line
#ifndef RLGL_STANDALONE
#include "raylib.h" // Required for: Model, Shader, Texture2D
#include "utils.h" // Required for: TraceLog()
#endif
#ifdef RLGL_STANDALONE
#if defined(RLGL_STANDALONE)
#define RAYMATH_STANDALONE
#else
#include "raylib.h" // Required for: Model, Shader, Texture2D, TraceLog()
#endif
#include "raymath.h" // Required for: Vector3, Matrix
// Select desired OpenGL version
// NOTE: Those preprocessor defines are only used on rlgl module,
// if OpenGL version is required by any other module, it uses rlGetVersion()
// Choose opengl version here or just define it at compile time: -DGRAPHICS_API_OPENGL_33
//#define GRAPHICS_API_OPENGL_11 // Only available on PLATFORM_DESKTOP
//#define GRAPHICS_API_OPENGL_33 // Only available on PLATFORM_DESKTOP and RLGL_OCULUS_SUPPORT
//#define GRAPHICS_API_OPENGL_ES2 // Only available on PLATFORM_ANDROID or PLATFORM_RPI or PLATFORM_WEB
// Security check in case no GRAPHICS_API_OPENGL_* defined
#if !defined(GRAPHICS_API_OPENGL_11) && !defined(GRAPHICS_API_OPENGL_21) && !defined(GRAPHICS_API_OPENGL_33) && !defined(GRAPHICS_API_OPENGL_ES2)
#define GRAPHICS_API_OPENGL_11
@ -157,6 +145,56 @@ typedef unsigned char byte;
// Boolean type
typedef enum { false, true } bool;
#endif
// Shader location point type
typedef enum {
LOC_VERTEX_POSITION = 0,
LOC_VERTEX_TEXCOORD01,
LOC_VERTEX_TEXCOORD02,
LOC_VERTEX_NORMAL,
LOC_VERTEX_TANGENT,
LOC_VERTEX_COLOR,
LOC_MATRIX_MVP,
LOC_MATRIX_MODEL,
LOC_MATRIX_VIEW,
LOC_MATRIX_PROJECTION,
LOC_VECTOR_VIEW,
LOC_COLOR_DIFFUSE,
LOC_COLOR_SPECULAR,
LOC_COLOR_AMBIENT,
LOC_MAP_ALBEDO, // LOC_MAP_DIFFUSE
LOC_MAP_METALNESS, // LOC_MAP_SPECULAR
LOC_MAP_NORMAL,
LOC_MAP_ROUGHNESS,
LOC_MAP_OCCUSION,
LOC_MAP_EMISSION,
LOC_MAP_HEIGHT,
LOC_MAP_CUBEMAP,
LOC_MAP_IRRADIANCE,
LOC_MAP_PREFILTER,
LOC_MAP_BRDF
} ShaderLocationIndex;
#define LOC_MAP_DIFFUSE LOC_MAP_ALBEDO
#define LOC_MAP_SPECULAR LOC_MAP_METALNESS
// Material map type
typedef enum {
MAP_ALBEDO = 0, // MAP_DIFFUSE
MAP_METALNESS = 1, // MAP_SPECULAR
MAP_NORMAL = 2,
MAP_ROUGHNESS = 3,
MAP_OCCLUSION,
MAP_EMISSION,
MAP_HEIGHT,
MAP_CUBEMAP, // NOTE: Uses GL_TEXTURE_CUBE_MAP
MAP_IRRADIANCE, // NOTE: Uses GL_TEXTURE_CUBE_MAP
MAP_PREFILTER, // NOTE: Uses GL_TEXTURE_CUBE_MAP
MAP_BRDF
} TexmapIndex;
#define MAP_DIFFUSE MAP_ALBEDO
#define MAP_SPECULAR MAP_METALNESS
// Color type, RGBA (32bit)
typedef struct Color {
@ -165,69 +203,7 @@ typedef unsigned char byte;
unsigned char b;
unsigned char a;
} Color;
// Texture formats (support depends on OpenGL version)
typedef enum {
UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha)
UNCOMPRESSED_GRAY_ALPHA,
UNCOMPRESSED_R5G6B5, // 16 bpp
UNCOMPRESSED_R8G8B8, // 24 bpp
UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha)
UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha)
UNCOMPRESSED_R8G8B8A8, // 32 bpp
COMPRESSED_DXT1_RGB, // 4 bpp (no alpha)
COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha)
COMPRESSED_DXT3_RGBA, // 8 bpp
COMPRESSED_DXT5_RGBA, // 8 bpp
COMPRESSED_ETC1_RGB, // 4 bpp
COMPRESSED_ETC2_RGB, // 4 bpp
COMPRESSED_ETC2_EAC_RGBA, // 8 bpp
COMPRESSED_PVRT_RGB, // 4 bpp
COMPRESSED_PVRT_RGBA, // 4 bpp
COMPRESSED_ASTC_4x4_RGBA, // 8 bpp
COMPRESSED_ASTC_8x8_RGBA // 2 bpp
} TextureFormat;
// Vertex data definning a mesh
typedef struct Mesh {
int vertexCount; // number of vertices stored in arrays
int triangleCount; // number of triangles stored (indexed or not)
float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0)
float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5)
float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4)
unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
unsigned short *indices;// vertex indices (in case vertex data comes indexed)
unsigned int vaoId; // OpenGL Vertex Array Object id
unsigned int vboId[7]; // OpenGL Vertex Buffer Objects id (7 types of vertex data)
} Mesh;
// Shader type (generic shader)
typedef struct Shader {
unsigned int id; // Shader program id
// Vertex attributes locations (default locations)
int vertexLoc; // Vertex attribute location point (default-location = 0)
int texcoordLoc; // Texcoord attribute location point (default-location = 1)
int normalLoc; // Normal attribute location point (default-location = 2)
int colorLoc; // Color attibute location point (default-location = 3)
int tangentLoc; // Tangent attribute location point (default-location = 4)
int texcoord2Loc; // Texcoord2 attribute location point (default-location = 5)
// Uniform locations
int mvpLoc; // ModelView-Projection matrix uniform location point (vertex shader)
int colDiffuseLoc; // Color uniform location point (fragment shader)
int colAmbientLoc; // Ambient color uniform location point (fragment shader)
int colSpecularLoc; // Specular color uniform location point (fragment shader)
// Texture map locations (generic for any kind of map)
int mapTexture0Loc; // Map texture uniform location point (default-texture-unit = 0)
int mapTexture1Loc; // Map texture uniform location point (default-texture-unit = 1)
int mapTexture2Loc; // Map texture uniform location point (default-texture-unit = 2)
} Shader;
// Texture2D type
// NOTE: Data stored in GPU memory
typedef struct Texture2D {
@ -245,19 +221,44 @@ typedef unsigned char byte;
Texture2D depth; // Depth buffer attachment texture
} RenderTexture2D;
// Material type
// Vertex data definning a mesh
typedef struct Mesh {
int vertexCount; // number of vertices stored in arrays
int triangleCount; // number of triangles stored (indexed or not)
float *vertices; // vertex position (XYZ - 3 components per vertex) (shader-location = 0)
float *texcoords; // vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)
float *texcoords2; // vertex second texture coordinates (useful for lightmaps) (shader-location = 5)
float *normals; // vertex normals (XYZ - 3 components per vertex) (shader-location = 2)
float *tangents; // vertex tangents (XYZ - 3 components per vertex) (shader-location = 4)
unsigned char *colors; // vertex colors (RGBA - 4 components per vertex) (shader-location = 3)
unsigned short *indices;// vertex indices (in case vertex data comes indexed)
unsigned int vaoId; // OpenGL Vertex Array Object id
unsigned int vboId[7]; // OpenGL Vertex Buffer Objects id (7 types of vertex data)
} Mesh;
// Shader and material limits
#define MAX_SHADER_LOCATIONS 32
#define MAX_MATERIAL_MAPS 12
// Shader type (generic)
typedef struct Shader {
unsigned int id; // Shader program id
int locs[MAX_SHADER_LOCATIONS]; // Shader locations array
} Shader;
// Material texture map
typedef struct MaterialMap {
Texture2D texture; // Material map texture
Color color; // Material map color
float value; // Material map value
} MaterialMap;
// Material type (generic)
typedef struct Material {
Shader shader; // Standard shader (supports 3 map types: diffuse, normal, specular)
Texture2D texDiffuse; // Diffuse texture
Texture2D texNormal; // Normal texture
Texture2D texSpecular; // Specular texture
Color colDiffuse; // Diffuse color
Color colAmbient; // Ambient color
Color colSpecular; // Specular color
float glossiness; // Glossiness level (Ranges from 0 to 1000)
Shader shader; // Material shader
MaterialMap maps[MAX_MATERIAL_MAPS]; // Material maps
float *params; // Material generic parameters (if required)
} Material;
// Camera type, defines a camera position/orientation in 3d space
@ -267,6 +268,52 @@ typedef unsigned char byte;
Vector3 up; // Camera up vector (rotation over its axis)
float fovy; // Camera field-of-view apperture in Y (degrees)
} Camera;
// Head-Mounted-Display device parameters
typedef struct VrDeviceInfo {
int hResolution; // HMD horizontal resolution in pixels
int vResolution; // HMD vertical resolution in pixels
float hScreenSize; // HMD horizontal size in meters
float vScreenSize; // HMD vertical size in meters
float vScreenCenter; // HMD screen center in meters
float eyeToScreenDistance; // HMD distance between eye and display in meters
float lensSeparationDistance; // HMD lens separation distance in meters
float interpupillaryDistance; // HMD IPD (distance between pupils) in meters
float lensDistortionValues[4]; // HMD lens distortion constant parameters
float chromaAbCorrection[4]; // HMD chromatic aberration correction parameters
} VrDeviceInfo;
// TraceLog message types
typedef enum {
LOG_INFO = 0,
LOG_ERROR,
LOG_WARNING,
LOG_DEBUG,
LOG_OTHER
} TraceLogType;
// Texture formats (support depends on OpenGL version)
typedef enum {
UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha)
UNCOMPRESSED_GRAY_ALPHA,
UNCOMPRESSED_R5G6B5, // 16 bpp
UNCOMPRESSED_R8G8B8, // 24 bpp
UNCOMPRESSED_R5G5B5A1, // 16 bpp (1 bit alpha)
UNCOMPRESSED_R4G4B4A4, // 16 bpp (4 bit alpha)
UNCOMPRESSED_R8G8B8A8, // 32 bpp
UNCOMPRESSED_R32G32B32, // 32 bit per channel (float) - HDR
COMPRESSED_DXT1_RGB, // 4 bpp (no alpha)
COMPRESSED_DXT1_RGBA, // 4 bpp (1 bit alpha)
COMPRESSED_DXT3_RGBA, // 8 bpp
COMPRESSED_DXT5_RGBA, // 8 bpp
COMPRESSED_ETC1_RGB, // 4 bpp
COMPRESSED_ETC2_RGB, // 4 bpp
COMPRESSED_ETC2_EAC_RGBA, // 8 bpp
COMPRESSED_PVRT_RGB, // 4 bpp
COMPRESSED_PVRT_RGBA, // 4 bpp
COMPRESSED_ASTC_4x4_RGBA, // 8 bpp
COMPRESSED_ASTC_8x8_RGBA // 2 bpp
} TextureFormat;
// Texture parameters: filter mode
// NOTE 1: Filtering considers mipmaps if available in the texture
@ -281,25 +328,27 @@ typedef unsigned char byte;
} TextureFilterMode;
// Texture parameters: wrap mode
typedef enum { WRAP_REPEAT = 0, WRAP_CLAMP, WRAP_MIRROR } TextureWrapMode;
typedef enum {
WRAP_REPEAT = 0,
WRAP_CLAMP,
WRAP_MIRROR
} TextureWrapMode;
// Color blending modes (pre-defined)
typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode;
// TraceLog message types
typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
typedef enum {
BLEND_ALPHA = 0,
BLEND_ADDITIVE,
BLEND_MULTIPLIED
} BlendMode;
// VR Head Mounted Display devices
typedef enum {
HMD_DEFAULT_DEVICE = 0,
HMD_OCULUS_RIFT_DK2,
HMD_OCULUS_RIFT_CV1,
HMD_OCULUS_GO,
HMD_VALVE_HTC_VIVE,
HMD_SAMSUNG_GEAR_VR,
HMD_GOOGLE_CARDBOARD,
HMD_SONY_PLAYSTATION_VR,
HMD_RAZER_OSVR,
HMD_FOVE_VR,
HMD_SONY_PSVR
} VrDevice;
#endif
@ -317,7 +366,7 @@ void rlLoadIdentity(void); // Reset current matrix to ident
void rlTranslatef(float x, float y, float z); // Multiply the current matrix by a translation matrix
void rlRotatef(float angleDeg, float x, float y, float z); // Multiply the current matrix by a rotation matrix
void rlScalef(float x, float y, float z); // Multiply the current matrix by a scaling matrix
void rlMultMatrixf(float *mat); // Multiply the current matrix by another matrix
void rlMultMatrixf(float *matf); // Multiply the current matrix by another matrix
void rlFrustum(double left, double right, double bottom, double top, double near, double far);
void rlOrtho(double left, double right, double bottom, double top, double near, double far);
void rlViewport(int x, int y, int width, int height); // Set the viewport area
@ -340,50 +389,48 @@ void rlColor4f(float x, float y, float z, float w); // Define one vertex (color)
// Functions Declaration - OpenGL equivalent functions (common to 1.1, 3.3+, ES2)
// NOTE: This functions are used to completely abstract raylib code from OpenGL layer
//------------------------------------------------------------------------------------
void rlEnableTexture(unsigned int id); // Enable texture usage
void rlDisableTexture(void); // Disable texture usage
void rlEnableTexture(unsigned int id); // Enable texture usage
void rlDisableTexture(void); // Disable texture usage
void rlTextureParameters(unsigned int id, int param, int value); // Set texture parameters (filter, wrap)
void rlEnableRenderTexture(unsigned int id); // Enable render texture (fbo)
void rlDisableRenderTexture(void); // Disable render texture (fbo), return to default framebuffer
void rlEnableDepthTest(void); // Enable depth test
void rlDisableDepthTest(void); // Disable depth test
void rlEnableWireMode(void); // Enable wire mode
void rlDisableWireMode(void); // Disable wire mode
void rlDeleteTextures(unsigned int id); // Delete OpenGL texture from GPU
void rlEnableRenderTexture(unsigned int id); // Enable render texture (fbo)
void rlDisableRenderTexture(void); // Disable render texture (fbo), return to default framebuffer
void rlEnableDepthTest(void); // Enable depth test
void rlDisableDepthTest(void); // Disable depth test
void rlEnableWireMode(void); // Enable wire mode
void rlDisableWireMode(void); // Disable wire mode
void rlDeleteTextures(unsigned int id); // Delete OpenGL texture from GPU
void rlDeleteRenderTextures(RenderTexture2D target); // Delete render textures (fbo) from GPU
void rlDeleteShader(unsigned int id); // Delete OpenGL shader program from GPU
void rlDeleteVertexArrays(unsigned int id); // Unload vertex data (VAO) from GPU memory
void rlDeleteBuffers(unsigned int id); // Unload vertex data (VBO) from GPU memory
void rlClearColor(byte r, byte g, byte b, byte a); // Clear color buffer with color
void rlClearScreenBuffers(void); // Clear used screen buffers (color and depth)
int rlGetVersion(void); // Returns current OpenGL version
void rlDeleteShader(unsigned int id); // Delete OpenGL shader program from GPU
void rlDeleteVertexArrays(unsigned int id); // Unload vertex data (VAO) from GPU memory
void rlDeleteBuffers(unsigned int id); // Unload vertex data (VBO) from GPU memory
void rlClearColor(byte r, byte g, byte b, byte a); // Clear color buffer with color
void rlClearScreenBuffers(void); // Clear used screen buffers (color and depth)
//------------------------------------------------------------------------------------
// Functions Declaration - rlgl functionality
//------------------------------------------------------------------------------------
void rlglInit(int width, int height); // Initialize rlgl (buffers, shaders, textures, states)
void rlglClose(void); // De-init rlgl
void rlglDraw(void); // Draw VAO/VBO
void rlglLoadExtensions(void *loader); // Load OpenGL extensions
void rlglClose(void); // De-inititialize rlgl (buffers, shaders, textures)
void rlglDraw(void); // Update and Draw default buffers (lines, triangles, quads)
unsigned int rlglLoadTexture(void *data, int width, int height, int format, int mipmapCount); // Load texture in GPU
RenderTexture2D rlglLoadRenderTexture(int width, int height); // Load a texture to be used for rendering (fbo with color and depth attachments)
void rlglUpdateTexture(unsigned int id, int width, int height, int format, const void *data); // Update GPU texture with new data
void rlglGenerateMipmaps(Texture2D *texture); // Generate mipmap data for selected texture
int rlGetVersion(void); // Returns current OpenGL version
void rlLoadExtensions(void *loader); // Load OpenGL extensions
Vector3 rlUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates
void rlglLoadMesh(Mesh *mesh, bool dynamic); // Upload vertex data into GPU and provided VAO/VBO ids
void rlglUpdateMesh(Mesh mesh, int buffer, int numVertex); // Update vertex data on GPU (upload new data to one buffer)
void rlglDrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform
void rlglUnloadMesh(Mesh *mesh); // Unload mesh data from CPU and GPU
// Textures data management
unsigned int rlLoadTexture(void *data, int width, int height, int format, int mipmapCount); // Load texture in GPU
void rlUpdateTexture(unsigned int id, int width, int height, int format, const void *data); // Update GPU texture with new data
void rlUnloadTexture(unsigned int id);
void rlGenerateMipmaps(Texture2D *texture); // Generate mipmap data for selected texture
void *rlReadTexturePixels(Texture2D texture); // Read texture pixel data
unsigned char *rlReadScreenPixels(int width, int height); // Read screen pixel data (color buffer)
RenderTexture2D rlLoadRenderTexture(int width, int height); // Load a texture to be used for rendering (fbo with color and depth attachments)
Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view); // Get world coordinates from screen coordinates
unsigned char *rlglReadScreenPixels(int width, int height); // Read screen pixel data (color buffer)
void *rlglReadTexturePixels(Texture2D texture); // Read texture pixel data
// VR functions exposed to core module but not to raylib users
void BeginVrDrawing(void); // Begin VR drawing configuration
void EndVrDrawing(void); // End VR drawing process (and desktop mirror)
// Vertex data management
void rlLoadMesh(Mesh *mesh, bool dynamic); // Upload vertex data into GPU and provided VAO/VBO ids
void rlUpdateMesh(Mesh mesh, int buffer, int numVertex); // Update vertex data on GPU (upload new data to one buffer)
void rlDrawMesh(Mesh mesh, Material material, Matrix transform); // Draw a 3d mesh with material and transform
void rlUnloadMesh(Mesh *mesh); // Unload mesh data from CPU and GPU
// NOTE: There is a set of shader related functions that are available to end user,
// to avoid creating function wrappers through core module, they have been directly declared in raylib.h
@ -393,35 +440,43 @@ void EndVrDrawing(void); // End VR drawing process (and deskt
// Shaders System Functions (Module: rlgl)
// NOTE: This functions are useless when using OpenGL 1.1
//------------------------------------------------------------------------------------
Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations
void UnloadShader(Shader shader); // Unload a custom shader from memory
Shader LoadShader(char *vsFileName, char *fsFileName); // Load a custom shader and bind default locations
void UnloadShader(Shader shader); // Unload a custom shader from memory
Shader GetDefaultShader(void); // Get default shader
Shader GetStandardShader(void); // Get default shader
Texture2D GetDefaultTexture(void); // Get default texture
Shader GetShaderDefault(void); // Get default shader
Texture2D GetTextureDefault(void); // Get default texture
// Shader configuration functions
int GetShaderLocation(Shader shader, const char *uniformName); // Get shader uniform location
void SetShaderValue(Shader shader, int uniformLoc, float *value, int size); // Set shader uniform value (float)
void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size); // Set shader uniform value (int)
void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat); // Set shader uniform value (matrix 4x4)
void SetMatrixProjection(Matrix proj); // Set a custom projection matrix (replaces internal projection matrix)
void SetMatrixModelview(Matrix view); // Set a custom modelview matrix (replaces internal modelview matrix)
void BeginShaderMode(Shader shader); // Begin custom shader drawing
void EndShaderMode(void); // End custom shader drawing (use default shader)
void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied)
void EndBlendMode(void); // End blending mode (reset to default: alpha blending)
// Texture maps generation (PBR)
// NOTE: Required shaders should be provided
Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size); // Generate cubemap texture from HDR texture
Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size); // Generate irradiance texture using cubemap data
Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size); // Generate prefilter texture using cubemap data
Texture2D GenTextureBRDF(Shader shader, Texture2D cubemap, int size); // Generate BRDF texture using cubemap data
void TraceLog(int msgType, const char *text, ...);
float *MatrixToFloat(Matrix mat);
// Shading and blending
void BeginShaderMode(Shader shader); // Begin custom shader drawing
void EndShaderMode(void); // End custom shader drawing (use default shader)
void BeginBlendMode(int mode); // Begin blending mode (alpha, additive, multiplied)
void EndBlendMode(void); // End blending mode (reset to default: alpha blending)
void InitVrSimulator(int vrDevice); // Init VR simulator for selected device
void CloseVrSimulator(void); // Close VR simulator for current device
void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera
void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator)
void BeginVrDrawing(void); // Begin VR stereo rendering
void EndVrDrawing(void); // End VR stereo rendering
// VR simulator functionality
VrDeviceInfo GetVrDeviceInfo(int vrDeviceType); // Get VR device information for some standard devices
void InitVrSimulator(VrDeviceInfo info); // Init VR simulator for selected device parameters
void CloseVrSimulator(void); // Close VR simulator for current device
void UpdateVrTracking(Camera *camera); // Update VR tracking (position and orientation) and camera
void ToggleVrMode(void); // Enable/Disable VR experience (device or simulator)
void BeginVrDrawing(void); // Begin VR stereo rendering
void EndVrDrawing(void); // End VR stereo rendering
void TraceLog(int msgType, const char *text, ...); // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
#endif
#ifdef __cplusplus

View file

@ -34,6 +34,14 @@
*
**********************************************************************************************/
/*
References:
RIFF file-format: http://www.johnloomis.org/cpe102/asgn/asgn1/riff.html
ZIP file-format: https://en.wikipedia.org/wiki/Zip_(file_format)
http://www.onicos.com/staff/iz/formats/zip.html
XNB file-format: http://xbox.create.msdn.com/en-US/sample/xnb_format
*/
#ifndef RRES_H
#define RRES_H
@ -75,6 +83,9 @@
void *data; // Resource data pointer (4 byte)
} RRESData;
// RRES type (pointer to RRESData array)
typedef struct RRESData *RRES; // Resource pointer
// RRESData type
typedef enum {
RRES_TYPE_RAW = 0,
@ -83,12 +94,25 @@
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_FONT_CHARDATA, // CharInfo { int value, recX, recY, recWidth, recHeight, offsetX, offsetY, xAdvance }
RRES_TYPE_DIRECTORY
} RRESDataType;
// RRES type (pointer to RRESData array)
typedef struct RRESData *RRES;
// Parameters information depending on resource type
// RRES_TYPE_RAW params: <custom>
// RRES_TYPE_IMAGE params: width, height, mipmaps, format
// RRES_TYPE_WAVE params: sampleCount, sampleRate, sampleSize, channels
// RRES_TYPE_VERTEX params: vertexCount, vertexType, vertexFormat // Use masks instead?
// RRES_TYPE_TEXT params: charsCount, cultureCode
// RRES_TYPE_FONT_IMAGE params: width, height, format, mipmaps;
// RRES_TYPE_FONT_CHARDATA params: charsCount, baseSize
// RRES_TYPE_DIRECTORY params: fileCount, directoryCount
// SpriteFont = RRES_TYPE_FONT_IMAGE chunk + RRES_TYPE_FONT_DATA chunk
// Mesh = multiple RRES_TYPE_VERTEX chunks
#endif
//----------------------------------------------------------------------------------
@ -103,6 +127,54 @@
RRESDEF RRES LoadResource(const char *fileName, int rresId);
RRESDEF void UnloadResource(RRES rres);
/*
QUESTION: How to load each type of data from RRES ?
rres->type == RRES_TYPE_RAW
unsigned char data = (unsigned char *)rres[0]->data;
rres->type == RRES_TYPE_IMAGE
Image image;
image.data = rres[0]->data; // Be careful, duplicate pointer
image.width = rres[0]->param1;
image.height = rres[0]->param2;
image.mipmaps = rres[0]->param3;
image.format = rres[0]->format;
rres->type == RRES_TYPE_WAVE
Wave wave;
wave.data = rres[0]->data;
wave.sampleCount = rres[0]->param1;
wave.sampleRate = rres[0]->param2;
wave.sampleSize = rres[0]->param3;
wave.channels = rres[0]->param4;
rres->type == RRES_TYPE_VERTEX (multiple parts)
Mesh mesh;
mesh.vertexCount = rres[0]->param1;
mesh.vertices = (float *)rres[0]->data;
mesh.texcoords = (float *)rres[1]->data;
mesh.normals = (float *)rres[2]->data;
mesh.tangents = (float *)rres[3]->data;
mesh.tangents = (unsigned char *)rres[4]->data;
rres->type == RRES_TYPE_TEXT
unsigned char *text = (unsigned char *)rres->data;
Shader shader = LoadShaderText(text, rres->param1); Shader LoadShaderText(const char *shdrText, int length);
rres->type == RRES_TYPE_FONT_IMAGE (multiple parts)
rres->type == RRES_TYPE_FONT_CHARDATA
SpriteFont font;
font.texture = LoadTextureFromImage(image); // rres[0]
font.chars = (CharInfo *)rres[1]->data;
font.charsCount = rres[1]->param1;
font.baseSize = rres[1]->param2;
rres->type == RRES_TYPE_DIRECTORY
unsigned char *fileNames = (unsigned char *)rres[0]->data; // fileNames separed by \n
int filesCount = rres[0]->param1;
*/
#endif // RRES_H
@ -169,6 +241,7 @@ typedef enum {
// gzip, zopfli, lzo, zstd // Other compression algorythms...
} RRESCompressionType;
// Encryption types
typedef enum {
RRES_CRYPTO_NONE = 0, // No data encryption
RRES_CRYPTO_XOR, // XOR (128 bit) encryption
@ -179,6 +252,7 @@ typedef enum {
// twofish, RC5, RC6 // Other encryption algorythm...
} RRESEncryptionType;
// Image/Texture data type
typedef enum {
RRES_IM_UNCOMP_GRAYSCALE = 1, // 8 bit per pixel (no alpha)
RRES_IM_UNCOMP_GRAY_ALPHA, // 16 bpp (2 channels)
@ -201,6 +275,7 @@ typedef enum {
//...
} RRESImageFormat;
// Vertex data type
typedef enum {
RRES_VERT_POSITION,
RRES_VERT_TEXCOORD1,
@ -214,6 +289,7 @@ typedef enum {
//...
} RRESVertexType;
// Vertex data format type
typedef enum {
RRES_VERT_BYTE,
RRES_VERT_SHORT,
@ -252,7 +328,7 @@ RRESDEF RRES LoadResource(const char *fileName, int rresId)
FILE *rresFile = fopen(fileName, "rb");
if (rresFile == NULL) TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", fileName);
if (rresFile == NULL) TraceLog(LOG_WARNING, "[%s] rRES raylib resource file could not be opened", fileName);
else
{
// Read rres file info header
@ -266,7 +342,7 @@ RRESDEF RRES LoadResource(const char *fileName, int rresId)
// 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);
TraceLog(LOG_WARNING, "[%s] This is not a valid raylib resource file", fileName);
}
else
{
@ -275,10 +351,10 @@ RRESDEF RRES LoadResource(const char *fileName, int rresId)
// Read resource info and parameters
fread(&infoHeader, sizeof(RRESInfoHeader), 1, rresFile);
rres = (RRES)malloc(sizeof(RRESData)*infoHeader.partsCount);
if (infoHeader.id == rresId)
{
rres = (RRES)malloc(sizeof(RRESData)*infoHeader.partsCount);
// Load all required resources parts
for (int k = 0; k < infoHeader.partsCount; k++)
{
@ -305,7 +381,7 @@ RRESDEF RRES LoadResource(const char *fileName, int rresId)
}
else rres[k].data = data;
if (rres[k].data != NULL) TraceLog(INFO, "[%s][ID %i] Resource data loaded successfully", fileName, (int)infoHeader.id);
if (rres[k].data != NULL) TraceLog(LOG_INFO, "[%s][ID %i] Resource data loaded successfully", fileName, (int)infoHeader.id);
// Read next part
fread(&infoHeader, sizeof(RRESInfoHeader), 1, rresFile);
@ -318,7 +394,7 @@ RRESDEF RRES LoadResource(const char *fileName, int rresId)
}
}
if (rres[0].data == NULL) TraceLog(WARNING, "[%s][ID %i] Requested resource could not be found", fileName, (int)rresId);
if (rres[0].data == NULL) TraceLog(LOG_WARNING, "[%s][ID %i] Requested resource could not be found", fileName, (int)rresId);
}
fclose(rresFile);
@ -327,8 +403,11 @@ RRESDEF RRES LoadResource(const char *fileName, int rresId)
return rres;
}
// Unload resource data
RRESDEF void UnloadResource(RRES rres)
{
// TODO: When you load resource... how many parts conform it? depends on type? --> Not clear...
if (rres[0].data != NULL) free(rres[0].data);
}
@ -349,7 +428,7 @@ static void *DecompressData(const unsigned char *data, unsigned long compSize, i
// Check correct memory allocation
if (uncompData == NULL)
{
TraceLog(WARNING, "Out of memory while decompressing data");
TraceLog(LOG_WARNING, "Out of memory while decompressing data");
}
else
{
@ -358,18 +437,18 @@ static void *DecompressData(const unsigned char *data, unsigned long compSize, i
if (tempUncompSize == -1)
{
TraceLog(WARNING, "Data decompression failed");
TraceLog(LOG_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(LOG_WARNING, "Expected uncompressed size do not match, data may be corrupted");
TraceLog(LOG_WARNING, " -- Expected uncompressed size: %i", uncompSize);
TraceLog(LOG_WARNING, " -- Returned uncompressed size: %i", tempUncompSize);
}
TraceLog(INFO, "Data decompressed successfully from %u bytes to %u bytes", (mz_uint32)compSize, (mz_uint32)tempUncompSize);
TraceLog(LOG_INFO, "Data decompressed successfully from %u bytes to %u bytes", (mz_uint32)compSize, (mz_uint32)tempUncompSize);
}
return uncompData;
@ -377,61 +456,28 @@ static void *DecompressData(const unsigned char *data, unsigned long compSize, i
// 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
// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
void TraceLog(int logType, const char *text, ...)
{
va_list args;
int traceDebugMsgs = 0;
#ifdef DO_NOT_TRACE_DEBUG_MSGS
traceDebugMsgs = 0;
#endif
va_start(args, text);
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;
case LOG_DEBUG: 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);
vfprintf(stdout, text, args);
fprintf(stdout, "\n");
fprintf(stdout, "\n");
}
va_end(args);
if (msgType == ERROR) exit(1); // If ERROR message, exit program
if (msgType == LOG_ERROR) exit(1);
}
#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
*/
#endif // RRES_IMPLEMENTATION

View file

@ -20,12 +20,12 @@ static const char vDistortionShaderStr[] =
"out vec2 fragTexCoord; \n"
"out vec4 fragColor; \n"
#endif
"uniform mat4 mvpMatrix; \n"
"uniform mat4 mvp; \n"
"void main() \n"
"{ \n"
" fragTexCoord = vertexTexCoord; \n"
" fragColor = vertexColor; \n"
" gl_Position = mvpMatrix*vec4(vertexPosition, 1.0); \n"
" gl_Position = mvp*vec4(vertexPosition, 1.0); \n"
"} \n";
// Fragment shader definition to embed, no external file required

View file

@ -13,17 +13,55 @@ type VrDevice int32
// Head Mounted Display devices
const (
HmdDefaultDevice VrDevice = C.HMD_DEFAULT_DEVICE
HmdOculusRiftDk2 VrDevice = C.HMD_OCULUS_RIFT_DK2
HmdOculusRiftCv1 VrDevice = C.HMD_OCULUS_RIFT_CV1
HmdValveHtcVive VrDevice = C.HMD_VALVE_HTC_VIVE
HmdSamsungGearVr VrDevice = C.HMD_SAMSUNG_GEAR_VR
HmdGoogleCardboard VrDevice = C.HMD_GOOGLE_CARDBOARD
HmdSonyPlaystationVr VrDevice = C.HMD_SONY_PLAYSTATION_VR
HmdRazerOsvr VrDevice = C.HMD_RAZER_OSVR
HmdFoveVr VrDevice = C.HMD_FOVE_VR
HmdDefaultDevice VrDevice = iota
HmdOculusRiftDk2
HmdOculusRiftCv1
HmdOculusGo
HmdValveHtcVive
HmdSonyPsvr
)
// VrDeviceInfo - Head-Mounted-Display device parameters
type VrDeviceInfo struct {
// HMD horizontal resolution in pixels
hResolution int
// HMD vertical resolution in pixels
vResolution int
// HMD horizontal size in meters
hScreenSize float32
// HMD vertical size in meters
vScreenSize float32
// HMD screen center in meters
vScreenCenter float32
// HMD distance between eye and display in meters
eyeToScreenDistance float32
// HMD lens separation distance in meters
lensSeparationDistance float32
// HMD IPD (distance between pupils) in meters
interpupillaryDistance float32
// HMD lens distortion constant parameters
lensDistortionValues [4]float32
// HMD chromatic aberration correction parameters
chromaAbCorrection [4]float32
}
func (v *VrDeviceInfo) cptr() *C.VrDeviceInfo {
return (*C.VrDeviceInfo)(unsafe.Pointer(v))
}
// NewVrDeviceInfo - Returns new VrDeviceInfo
func NewVrDeviceInfo(hResolution, vResolution int, hScreenSize, vScreenSize, vScreenCenter, eyeToScreenDistance,
lensSeparationDistance, interpupillaryDistance float32, lensDistortionValues, chromaAbCorrection [4]float32) VrDeviceInfo {
return VrDeviceInfo{hResolution, vResolution, hScreenSize, vScreenSize, vScreenCenter, eyeToScreenDistance,
lensSeparationDistance, interpupillaryDistance, lensDistortionValues, chromaAbCorrection}
}
// NewVrDeviceInfoFromPointer - Returns new VrDeviceInfo from pointer
func NewVrDeviceInfoFromPointer(ptr unsafe.Pointer) VrDeviceInfo {
return *(*VrDeviceInfo)(ptr)
}
// BlendMode type
type BlendMode int32
@ -38,32 +76,8 @@ const (
type Shader struct {
// Shader program id
ID uint32
// Vertex attribute location point (default-location = 0)
VertexLoc int32
// Texcoord attribute location point (default-location = 1)
TexcoordLoc int32
// Texcoord2 attribute location point (default-location = 5)
Texcoord2Loc int32
// Normal attribute location point (default-location = 2)
NormalLoc int32
// Tangent attribute location point (default-location = 4)
TangentLoc int32
// Color attibute location point (default-location = 3)
ColorLoc int32
// ModelView-Projection matrix uniform location point (vertex shader)
MvpLoc int32
// Diffuse color uniform location point (fragment shader)
ColDiffuseLoc int32
// Ambient color uniform location point (fragment shader)
ColAmbientLoc int32
// Specular color uniform location point (fragment shader)
ColSpecularLoc int32
// Map texture uniform location point (default-texture-unit = 0)
MapTexture0Loc int32
// Map texture uniform location point (default-texture-unit = 1)
MapTexture1Loc int32
// Map texture uniform location point (default-texture-unit = 2)
MapTexture2Loc int32
// Shader locations array
Locs [MaxShaderLocations]int32
}
func (s *Shader) cptr() *C.Shader {
@ -71,8 +85,8 @@ func (s *Shader) cptr() *C.Shader {
}
// NewShader - Returns new Shader
func NewShader(id uint32, vertexLoc, texcoordLoc, texcoord2Loc, normalLoc, tangentLoc, colorLoc, mvpLoc, colDiffuseLoc, colAmbientLoc, colSpecularLoc, mapTexture0Loc, mapTexture1Loc, mapTexture2Loc int32) Shader {
return Shader{id, vertexLoc, texcoordLoc, texcoord2Loc, normalLoc, tangentLoc, colorLoc, mvpLoc, colDiffuseLoc, colAmbientLoc, colSpecularLoc, mapTexture0Loc, mapTexture1Loc, mapTexture2Loc}
func NewShader(id uint32, locs [MaxShaderLocations]int32) Shader {
return Shader{id, locs}
}
// NewShaderFromPointer - Returns new Shader from pointer
@ -98,16 +112,16 @@ func UnloadShader(shader Shader) {
C.UnloadShader(*cshader)
}
// GetDefaultShader - Get default shader
func GetDefaultShader() Shader {
ret := C.GetDefaultShader()
// GetShaderDefault - Get default shader
func GetShaderDefault() Shader {
ret := C.GetShaderDefault()
v := NewShaderFromPointer(unsafe.Pointer(&ret))
return v
}
// GetDefaultTexture - Get default texture
func GetDefaultTexture() *Texture2D {
ret := C.GetDefaultTexture()
// GetTextureDefault - Get default texture
func GetTextureDefault() *Texture2D {
ret := C.GetTextureDefault()
v := NewTexture2DFromPointer(unsafe.Pointer(&ret))
return &v
}
@ -117,6 +131,7 @@ func GetShaderLocation(shader Shader, uniformName string) int32 {
cshader := shader.cptr()
cuniformName := C.CString(uniformName)
defer C.free(unsafe.Pointer(cuniformName))
ret := C.GetShaderLocation(*cshader, cuniformName)
v := (int32)(ret)
return v
@ -160,6 +175,50 @@ func SetMatrixModelview(view Matrix) {
C.SetMatrixModelview(*cview)
}
// GenTextureCubemap - Generate cubemap texture from HDR texture
func GenTextureCubemap(shader Shader, skyHDR Texture2D, size int) Texture2D {
cshader := shader.cptr()
cskyHDR := skyHDR.cptr()
csize := (C.int)(size)
ret := C.GenTextureCubemap(*cshader, *cskyHDR, csize)
v := NewTexture2DFromPointer(unsafe.Pointer(&ret))
return v
}
// GenTextureIrradiance - Generate irradiance texture using cubemap data
func GenTextureIrradiance(shader Shader, cubemap Texture2D, size int) Texture2D {
cshader := shader.cptr()
ccubemap := cubemap.cptr()
csize := (C.int)(size)
ret := C.GenTextureIrradiance(*cshader, *ccubemap, csize)
v := NewTexture2DFromPointer(unsafe.Pointer(&ret))
return v
}
// GenTexturePrefilter - Generate prefilter texture using cubemap data
func GenTexturePrefilter(shader Shader, cubemap Texture2D, size int) Texture2D {
cshader := shader.cptr()
ccubemap := cubemap.cptr()
csize := (C.int)(size)
ret := C.GenTexturePrefilter(*cshader, *ccubemap, csize)
v := NewTexture2DFromPointer(unsafe.Pointer(&ret))
return v
}
// GenTextureBRDF - Generate BRDF texture using cubemap data
func GenTextureBRDF(shader Shader, cubemap Texture2D, size int) Texture2D {
cshader := shader.cptr()
ccubemap := cubemap.cptr()
csize := (C.int)(size)
ret := C.GenTextureBRDF(*cshader, *ccubemap, csize)
v := NewTexture2DFromPointer(unsafe.Pointer(&ret))
return v
}
// BeginShaderMode - Begin custom shader drawing
func BeginShaderMode(shader Shader) {
cshader := shader.cptr()
@ -182,10 +241,18 @@ func EndBlendMode() {
C.EndBlendMode()
}
// GetVrDeviceInfo - Get VR device information for some standard devices
func GetVrDeviceInfo(vrDevice VrDevice) VrDeviceInfo {
cvrDevice := (C.int)(vrDevice)
ret := C.GetVrDeviceInfo(cvrDevice)
v := NewVrDeviceInfoFromPointer(unsafe.Pointer(&ret))
return v
}
// InitVrSimulator - Init VR simulator for selected device
func InitVrSimulator(vdDevice VrDevice) {
cvdDevice := (C.int)(vdDevice)
C.InitVrSimulator(cvdDevice)
func InitVrSimulator(vrDeviceInfo VrDeviceInfo) {
cvrDeviceInfo := vrDeviceInfo.cptr()
C.InitVrSimulator(*cvrDeviceInfo)
}
// CloseVrSimulator - Close VR simulator for current device

View file

@ -119,11 +119,11 @@ void DrawLineEx(Vector2 startPos, Vector2 endPos, float thick, Color color)
float d = sqrtf(dx*dx + dy*dy);
float angle = asinf(dy/d);
rlEnableTexture(GetDefaultTexture().id);
rlEnableTexture(GetTextureDefault().id);
rlPushMatrix();
rlTranslatef((float)startPos.x, (float)startPos.y, 0);
rlRotatef(-RAD2DEG*angle, 0, 0, 1);
rlRotatef(RAD2DEG*angle, 0, 0, 1);
rlTranslatef(0, -thick/2.0f, 0);
rlBegin(RL_QUADS);
@ -203,7 +203,7 @@ void DrawCircleV(Vector2 center, float radius, Color color)
}
else if ((rlGetVersion() == OPENGL_21) || (rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20))
{
rlEnableTexture(GetDefaultTexture().id); // Default white texture
rlEnableTexture(GetTextureDefault().id); // Default white texture
rlBegin(RL_QUADS);
for (int i = 0; i < 360; i += 20)
@ -253,7 +253,7 @@ void DrawRectangleRec(Rectangle rec, Color color)
void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color)
{
rlEnableTexture(GetDefaultTexture().id);
rlEnableTexture(GetTextureDefault().id);
rlPushMatrix();
rlTranslatef((float)rec.x, (float)rec.y, 0);
@ -274,19 +274,66 @@ void DrawRectanglePro(Rectangle rec, Vector2 origin, float rotation, Color color
rlDisableTexture();
}
// Draw a gradient-filled rectangle
// Draw a vertical-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)
void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2)
{
rlBegin(RL_TRIANGLES);
rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX, posY);
rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX, posY + height);
rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX + width, posY + height);
DrawRectangleGradientEx((Rectangle){ posX, posY, width, height }, color1, color2, color2, color1);
}
rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX, posY);
rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX + width, posY + height);
rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX + width, posY);
// Draw a horizontal-gradient-filled rectangle
// NOTE: Gradient goes from bottom (color1) to top (color2)
void DrawRectangleGradientH(int posX, int posY, int width, int height, Color color1, Color color2)
{
DrawRectangleGradientEx((Rectangle){ posX, posY, width, height }, color1, color1, color2, color2);
}
// Draw a gradient-filled rectangle
// NOTE: Colors refer to corners, starting at top-lef corner and counter-clockwise
void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4)
{
rlEnableTexture(GetTextureDefault().id); // Default white texture
rlBegin(RL_QUADS);
rlNormal3f(0.0f, 0.0f, 1.0f);
rlColor4ub(col1.r, col1.g, col1.b, col1.a);
rlTexCoord2f(0.0f, 0.0f);
rlVertex2f(rec.x, rec.y);
rlColor4ub(col2.r, col2.g, col2.b, col2.a);
rlTexCoord2f(0.0f, 1.0f);
rlVertex2f(rec.x, rec.y + rec.height);
rlColor4ub(col3.r, col3.g, col3.b, col3.a);
rlTexCoord2f(1.0f, 1.0f);
rlVertex2f(rec.x + rec.width, rec.y + rec.height);
rlColor4ub(col4.r, col4.g, col4.b, col4.a);
rlTexCoord2f(1.0f, 0.0f);
rlVertex2f(rec.x + rec.width, rec.y);
rlEnd();
// Draw rectangle using font texture white character
/*
rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width,
(float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height);
rlVertex2f(rec.x, rec.y);
rlTexCoord2f((float)GetDefaultFont().chars[95].rec.x/GetDefaultFont().texture.width,
(float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height);
rlVertex2f(rec.x, rec.y + rec.height);
rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width,
(float)(GetDefaultFont().chars[95].rec.y + GetDefaultFont().chars[95].rec.height)/GetDefaultFont().texture.height);
rlVertex2f(rec.x + rec.width, rec.y + rec.height);
rlTexCoord2f((float)(GetDefaultFont().chars[95].rec.x + GetDefaultFont().chars[95].rec.width)/GetDefaultFont().texture.width,
(float)GetDefaultFont().chars[95].rec.y/GetDefaultFont().texture.height);
rlVertex2f(rec.x + rec.width, rec.y);
*/
rlDisableTexture();
}
// Draw a color-filled rectangle (Vector version)
@ -309,7 +356,7 @@ void DrawRectangleV(Vector2 position, Vector2 size, Color color)
}
else if ((rlGetVersion() == OPENGL_21) || (rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20))
{
rlEnableTexture(GetDefaultTexture().id); // Default white texture
rlEnableTexture(GetTextureDefault().id); // Default white texture
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
@ -362,6 +409,14 @@ void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
}
}
// Draw rectangle using text character (char: 127)
// NOTE: Useful to avoid changing to default white texture
void DrawRectangleT(int posX, int posY, int width, int height, Color color)
{
DrawTexturePro(GetDefaultFont().texture, GetDefaultFont().chars[95].rec,
(Rectangle){ posX, posY, width, height }, (Vector2){ 0, 0 }, 0.0f, color);
}
// Draw a triangle
void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
{
@ -376,7 +431,7 @@ void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
}
else if ((rlGetVersion() == OPENGL_21) || (rlGetVersion() == OPENGL_33) || (rlGetVersion() == OPENGL_ES_20))
{
rlEnableTexture(GetDefaultTexture().id); // Default white texture
rlEnableTexture(GetTextureDefault().id); // Default white texture
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
@ -627,6 +682,8 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
// NOTE: Required for DrawLineBezier()
static float EaseCubicInOut(float t, float b, float c, float d)
{
if ((t/=d/2) < 1) return (c/2*t*t*t + b);
return (c/2*((t-=2)*t*t + 2) + b);
}
if ((t /= 0.5*d) < 1)
return 0.5*c*t*t*t + b;
t -= 2;
return 0.5*c*(t*t*t + 2) + b;
}

View file

@ -8,7 +8,7 @@ import "C"
import "unsafe"
// DrawPixel - Draw a pixel
func DrawPixel(posX int32, posY int32, color Color) {
func DrawPixel(posX, posY int32, color Color) {
cposX := (C.int)(posX)
cposY := (C.int)(posY)
ccolor := color.cptr()
@ -23,7 +23,7 @@ func DrawPixelV(position Vector2, color Color) {
}
// DrawLine - Draw a line
func DrawLine(startPosX int32, startPosY int32, endPosX int32, endPosY int32, color Color) {
func DrawLine(startPosX, startPosY, endPosX, endPosY int32, color Color) {
cstartPosX := (C.int)(startPosX)
cstartPosY := (C.int)(startPosY)
cendPosX := (C.int)(endPosX)
@ -33,7 +33,7 @@ func DrawLine(startPosX int32, startPosY int32, endPosX int32, endPosY int32, co
}
// DrawLineV - Draw a line (Vector version)
func DrawLineV(startPos Vector2, endPos Vector2, color Color) {
func DrawLineV(startPos, endPos Vector2, color Color) {
cstartPos := startPos.cptr()
cendPos := endPos.cptr()
ccolor := color.cptr()
@ -41,7 +41,7 @@ func DrawLineV(startPos Vector2, endPos Vector2, color Color) {
}
// DrawLineEx - Draw a line defining thickness
func DrawLineEx(startPos Vector2, endPos Vector2, thick float32, color Color) {
func DrawLineEx(startPos, endPos Vector2, thick float32, color Color) {
cstartPos := startPos.cptr()
cendPos := endPos.cptr()
cthick := (C.float)(thick)
@ -50,7 +50,7 @@ func DrawLineEx(startPos Vector2, endPos Vector2, thick float32, color Color) {
}
// DrawLineBezier - Draw a line using cubic-bezier curves in-out
func DrawLineBezier(startPos Vector2, endPos Vector2, thick float32, color Color) {
func DrawLineBezier(startPos, endPos Vector2, thick float32, color Color) {
cstartPos := startPos.cptr()
cendPos := endPos.cptr()
cthick := (C.float)(thick)
@ -59,7 +59,7 @@ func DrawLineBezier(startPos Vector2, endPos Vector2, thick float32, color Color
}
// DrawCircle - Draw a color-filled circle
func DrawCircle(centerX int32, centerY int32, radius float32, color Color) {
func DrawCircle(centerX, centerY int32, radius float32, color Color) {
ccenterX := (C.int)(centerX)
ccenterY := (C.int)(centerY)
cradius := (C.float)(radius)
@ -68,7 +68,7 @@ func DrawCircle(centerX int32, centerY int32, radius float32, color Color) {
}
// DrawCircleGradient - Draw a gradient-filled circle
func DrawCircleGradient(centerX int32, centerY int32, radius float32, color1 Color, color2 Color) {
func DrawCircleGradient(centerX, centerY int32, radius float32, color1, color2 Color) {
ccenterX := (C.int)(centerX)
ccenterY := (C.int)(centerY)
cradius := (C.float)(radius)
@ -86,7 +86,7 @@ func DrawCircleV(center Vector2, radius float32, color Color) {
}
// DrawCircleLines - Draw circle outline
func DrawCircleLines(centerX int32, centerY int32, radius float32, color Color) {
func DrawCircleLines(centerX, centerY int32, radius float32, color Color) {
ccenterX := (C.int)(centerX)
ccenterY := (C.int)(centerY)
cradius := (C.float)(radius)
@ -95,7 +95,7 @@ func DrawCircleLines(centerX int32, centerY int32, radius float32, color Color)
}
// DrawRectangle - Draw a color-filled rectangle
func DrawRectangle(posX int32, posY int32, width int32, height int32, color Color) {
func DrawRectangle(posX, posY, width, height int32, color Color) {
cposX := (C.int)(posX)
cposY := (C.int)(posY)
cwidth := (C.int)(width)
@ -120,15 +120,36 @@ func DrawRectanglePro(rec Rectangle, origin Vector2, rotation float32, color Col
C.DrawRectanglePro(*crec, *corigin, crotation, *ccolor)
}
// DrawRectangleGradient - Draw a gradient-filled rectangle
func DrawRectangleGradient(posX int32, posY int32, width int32, height int32, color1 Color, color2 Color) {
// DrawRectangleGradientV - Draw a vertical-gradient-filled rectangle
func DrawRectangleGradientV(posX, posY, width, height int32, color1, color2 Color) {
cposX := (C.int)(posX)
cposY := (C.int)(posY)
cwidth := (C.int)(width)
cheight := (C.int)(height)
ccolor1 := color1.cptr()
ccolor2 := color2.cptr()
C.DrawRectangleGradient(cposX, cposY, cwidth, cheight, *ccolor1, *ccolor2)
C.DrawRectangleGradientV(cposX, cposY, cwidth, cheight, *ccolor1, *ccolor2)
}
// DrawRectangleGradientH - Draw a horizontal-gradient-filled rectangle
func DrawRectangleGradientH(posX, posY, width, height int32, color1, color2 Color) {
cposX := (C.int)(posX)
cposY := (C.int)(posY)
cwidth := (C.int)(width)
cheight := (C.int)(height)
ccolor1 := color1.cptr()
ccolor2 := color2.cptr()
C.DrawRectangleGradientH(cposX, cposY, cwidth, cheight, *ccolor1, *ccolor2)
}
// DrawRectangleGradientEx - Draw a gradient-filled rectangle with custom vertex colors
func DrawRectangleGradientEx(rec Rectangle, color1, color2, color3, color4 Color) {
crec := rec.cptr()
ccolor1 := color1.cptr()
ccolor2 := color2.cptr()
ccolor3 := color3.cptr()
ccolor4 := color4.cptr()
C.DrawRectangleGradientEx(*crec, *ccolor1, *ccolor2, *ccolor3, *ccolor4)
}
// DrawRectangleV - Draw a color-filled rectangle (Vector version)
@ -140,7 +161,7 @@ func DrawRectangleV(position Vector2, size Vector2, color Color) {
}
// DrawRectangleLines - Draw rectangle outline
func DrawRectangleLines(posX int32, posY int32, width int32, height int32, color Color) {
func DrawRectangleLines(posX, posY, width, height int32, color Color) {
cposX := (C.int)(posX)
cposY := (C.int)(posY)
cwidth := (C.int)(width)
@ -149,8 +170,18 @@ func DrawRectangleLines(posX int32, posY int32, width int32, height int32, color
C.DrawRectangleLines(cposX, cposY, cwidth, cheight, *ccolor)
}
// DrawRectangleT - Draw rectangle using text character
func DrawRectangleT(posX, posY, width, height int32, color Color) {
cposX := (C.int)(posX)
cposY := (C.int)(posY)
cwidth := (C.int)(width)
cheight := (C.int)(height)
ccolor := color.cptr()
C.DrawRectangleT(cposX, cposY, cwidth, cheight, *ccolor)
}
// DrawTriangle - Draw a color-filled triangle
func DrawTriangle(v1 Vector2, v2 Vector2, v3 Vector2, color Color) {
func DrawTriangle(v1, v2, v3 Vector2, color Color) {
cv1 := v1.cptr()
cv2 := v2.cptr()
cv3 := v3.cptr()
@ -159,7 +190,7 @@ func DrawTriangle(v1 Vector2, v2 Vector2, v3 Vector2, color Color) {
}
// DrawTriangleLines - Draw triangle outline
func DrawTriangleLines(v1 Vector2, v2 Vector2, v3 Vector2, color Color) {
func DrawTriangleLines(v1, v2, v3 Vector2, color Color) {
cv1 := v1.cptr()
cv2 := v2.cptr()
cv3 := v3.cptr()
@ -168,7 +199,7 @@ func DrawTriangleLines(v1 Vector2, v2 Vector2, v3 Vector2, color Color) {
}
// DrawPoly - Draw a regular polygon (Vector version)
func DrawPoly(center Vector2, sides int32, radius float32, rotation float32, color Color) {
func DrawPoly(center Vector2, sides int32, radius, rotation float32, color Color) {
ccenter := center.cptr()
csides := (C.int)(sides)
cradius := (C.float)(radius)
@ -194,7 +225,7 @@ func DrawPolyExLines(points []Vector2, numPoints int32, color Color) {
}
// CheckCollisionRecs - Check collision between two rectangles
func CheckCollisionRecs(rec1 Rectangle, rec2 Rectangle) bool {
func CheckCollisionRecs(rec1, rec2 Rectangle) bool {
crec1 := rec1.cptr()
crec2 := rec2.cptr()
ret := C.CheckCollisionRecs(*crec1, *crec2)
@ -224,7 +255,7 @@ func CheckCollisionCircleRec(center Vector2, radius float32, rec Rectangle) bool
}
// GetCollisionRec - Get collision rectangle for two rectangles collision
func GetCollisionRec(rec1 Rectangle, rec2 Rectangle) Rectangle {
func GetCollisionRec(rec1, rec2 Rectangle) Rectangle {
crec1 := rec1.cptr()
crec2 := rec2.cptr()
ret := C.GetCollisionRec(*crec1, *crec2)
@ -252,7 +283,7 @@ func CheckCollisionPointCircle(point Vector2, center Vector2, radius float32) bo
}
// CheckCollisionPointTriangle - Check if point is inside a triangle
func CheckCollisionPointTriangle(point Vector2, p1 Vector2, p2 Vector2, p3 Vector2) bool {
func CheckCollisionPointTriangle(point, p1, p2, p3 Vector2) bool {
cpoint := point.cptr()
cp1 := p1.cptr()
cp2 := p2.cptr()

View file

@ -139,10 +139,10 @@ extern void LoadDefaultFont(void)
0x04000404, 0x4100203c, 0x00000000, 0x00000800, 0xf7df7df0, 0x514bef85, 0xbefbefbe, 0x04513bef, 0x14414500, 0x494a2885, 0xa28a28aa, 0x04510820,
0xf44145f0, 0x474a289d, 0xa28a28aa, 0x04510be0, 0x14414510, 0x494a2884, 0xa28a28aa, 0x02910a00, 0xf7df7df0, 0xd14a2f85, 0xbefbe8aa, 0x011f7be0,
0x00000000, 0x00400804, 0x20080000, 0x00000000, 0x00000000, 0x00600f84, 0x20080000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0xac000000, 0x00000f01, 0x00000000, 0x00000000, 0x24000000, 0x00000901, 0x00000000, 0x06000000, 0x24000000, 0x00000901, 0x00000000, 0x09108000,
0x24fa28a2, 0x00000901, 0x00000000, 0x013e0000, 0x2242252a, 0x00000952, 0x00000000, 0x038a8000, 0x2422222a, 0x00000929, 0x00000000, 0x010a8000,
0x2412252a, 0x00000901, 0x00000000, 0x010a8000, 0x24fbe8be, 0x00000901, 0x00000000, 0x0ebe8000, 0xac020000, 0x00000f01, 0x00000000, 0x00048000,
0x0003e000, 0x00000000, 0x00000000, 0x00008000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000038, 0x8443b80e, 0x00203a03,
0xac000000, 0x00000f01, 0x00000000, 0x00000000, 0x24000000, 0x00000f01, 0x00000000, 0x06000000, 0x24000000, 0x00000f01, 0x00000000, 0x09108000,
0x24fa28a2, 0x00000f01, 0x00000000, 0x013e0000, 0x2242252a, 0x00000f52, 0x00000000, 0x038a8000, 0x2422222a, 0x00000f29, 0x00000000, 0x010a8000,
0x2412252a, 0x00000f01, 0x00000000, 0x010a8000, 0x24fbe8be, 0x00000f01, 0x00000000, 0x0ebe8000, 0xac020000, 0x00000f01, 0x00000000, 0x00048000,
0x0003e000, 0x00000f00, 0x00000000, 0x00008000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000038, 0x8443b80e, 0x00203a03,
0x02bea080, 0xf0000020, 0xc452208a, 0x04202b02, 0xf8029122, 0x07f0003b, 0xe44b388e, 0x02203a02, 0x081e8a1c, 0x0411e92a, 0xf4420be0, 0x01248202,
0xe8140414, 0x05d104ba, 0xe7c3b880, 0x00893a0a, 0x283c0e1c, 0x04500902, 0xc4400080, 0x00448002, 0xe8208422, 0x04500002, 0x80400000, 0x05200002,
0x083e8e00, 0x04100002, 0x804003e0, 0x07000042, 0xf8008400, 0x07f00003, 0x80400000, 0x04000022, 0x00000000, 0x00000000, 0x80400000, 0x04000002,
@ -255,8 +255,8 @@ extern void LoadDefaultFont(void)
}
defaultFont.baseSize = defaultFont.chars[0].rec.height;
TraceLog(INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id);
TraceLog(LOG_INFO, "[TEX ID %i] Default font loaded successfully", defaultFont.texture.id);
}
// Unload raylib default font
@ -330,7 +330,7 @@ SpriteFont LoadSpriteFont(const char *fileName)
if (spriteFont.texture.id == 0)
{
TraceLog(WARNING, "[%s] SpriteFont could not be loaded, using default font", fileName);
TraceLog(LOG_WARNING, "[%s] SpriteFont could not be loaded, using default font", fileName);
spriteFont = GetDefaultFont();
}
else SetTextureFilter(spriteFont.texture, FILTER_POINT); // By default we set point filter (best performance)
@ -364,7 +364,7 @@ SpriteFont LoadSpriteFontEx(const char *fileName, int fontSize, int charsCount,
if (spriteFont.texture.id == 0)
{
TraceLog(WARNING, "[%s] SpriteFont could not be generated, using default font", fileName);
TraceLog(LOG_WARNING, "[%s] SpriteFont could not be generated, using default font", fileName);
spriteFont = GetDefaultFont();
}
@ -380,7 +380,7 @@ void UnloadSpriteFont(SpriteFont spriteFont)
UnloadTexture(spriteFont.texture);
free(spriteFont.chars);
TraceLog(DEBUG, "Unloaded sprite font data");
TraceLog(LOG_DEBUG, "Unloaded sprite font data");
}
}
@ -443,7 +443,7 @@ void DrawTextEx(SpriteFont spriteFont, const char *text, Vector2 position, float
index = GetCharIndex(spriteFont, (int)letter + 64);
i++;
}
else index = GetCharIndex(spriteFont, (int)text[i]);
else index = GetCharIndex(spriteFont, (unsigned char)text[i]);
DrawTexturePro(spriteFont.texture, spriteFont.chars[index].rec,
(Rectangle){ position.x + textOffsetX + spriteFont.chars[index].offsetX*scaleFactor,
@ -632,6 +632,7 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar)
{
if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break;
}
if (!COLOR_EQUAL(pixels[y*image.width + x], key)) break;
}
@ -677,7 +678,7 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar)
xPosToRead = charSpacing;
}
TraceLog(DEBUG, "SpriteFont data parsed correctly from image");
TraceLog(LOG_DEBUG, "SpriteFont data parsed correctly from image");
// NOTE: We need to remove key color borders from image to avoid weird
// artifacts on texture scaling when using FILTER_BILINEAR or FILTER_TRILINEAR
@ -713,7 +714,7 @@ static SpriteFont LoadImageFont(Image image, Color key, int firstChar)
spriteFont.baseSize = spriteFont.chars[0].rec.height;
TraceLog(INFO, "Image file loaded correctly as SpriteFont");
TraceLog(LOG_INFO, "Image file loaded correctly as SpriteFont");
return spriteFont;
}
@ -743,7 +744,7 @@ static SpriteFont LoadBMFont(const char *fileName)
if (fntFile == NULL)
{
TraceLog(WARNING, "[%s] FNT file could not be opened", fileName);
TraceLog(LOG_WARNING, "[%s] FNT file could not be opened", fileName);
return font;
}
@ -756,20 +757,20 @@ static SpriteFont LoadBMFont(const char *fileName)
searchPoint = strstr(buffer, "lineHeight");
sscanf(searchPoint, "lineHeight=%i base=%i scaleW=%i scaleH=%i", &fontSize, &base, &texWidth, &texHeight);
TraceLog(DEBUG, "[%s] Font size: %i", fileName, fontSize);
TraceLog(DEBUG, "[%s] Font texture scale: %ix%i", fileName, texWidth, texHeight);
TraceLog(LOG_DEBUG, "[%s] Font size: %i", fileName, fontSize);
TraceLog(LOG_DEBUG, "[%s] Font texture scale: %ix%i", fileName, texWidth, texHeight);
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
searchPoint = strstr(buffer, "file");
sscanf(searchPoint, "file=\"%128[^\"]\"", texFileName);
TraceLog(DEBUG, "[%s] Font texture filename: %s", fileName, texFileName);
TraceLog(LOG_DEBUG, "[%s] Font texture filename: %s", fileName, texFileName);
fgets(buffer, MAX_BUFFER_SIZE, fntFile);
searchPoint = strstr(buffer, "count");
sscanf(searchPoint, "count=%i", &charsCount);
TraceLog(DEBUG, "[%s] Font num chars: %i", fileName, charsCount);
TraceLog(LOG_DEBUG, "[%s] Font num chars: %i", fileName, charsCount);
// Compose correct path using route of .fnt file (fileName) and texFileName
char *texPath = NULL;
@ -785,7 +786,7 @@ static SpriteFont LoadBMFont(const char *fileName)
strncat(texPath, fileName, strlen(fileName) - strlen(lastSlash) + 1);
strncat(texPath, texFileName, strlen(texFileName));
TraceLog(DEBUG, "[%s] Font texture loading path: %s", fileName, texPath);
TraceLog(LOG_DEBUG, "[%s] Font texture loading path: %s", fileName, texPath);
Image imFont = LoadImage(texPath);
@ -832,7 +833,7 @@ static SpriteFont LoadBMFont(const char *fileName)
UnloadSpriteFont(font);
font = GetDefaultFont();
}
else TraceLog(INFO, "[%s] SpriteFont loaded successfully", fileName);
else TraceLog(LOG_INFO, "[%s] SpriteFont loaded successfully", fileName);
return font;
}
@ -853,7 +854,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, in
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);
TraceLog(LOG_INFO, "TTF spritefont loading: Predicted texture size: %ix%i", textureSize, textureSize);
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!
@ -865,22 +866,34 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, in
if (ttfFile == NULL)
{
TraceLog(WARNING, "[%s] TTF file could not be opened", fileName);
TraceLog(LOG_WARNING, "[%s] TTF file could not be opened", fileName);
return font;
}
// NOTE: We try reading up to 16 MB of elements of 1 byte
fread(ttfBuffer, 1, MAX_TTF_SIZE*1024*1024, ttfFile);
// Find font baseline (vertical origin of the font)
// NOTE: This value is required because y-offset depends on it!
stbtt_fontinfo fontInfo;
int ascent, baseline;
float scale;
if (fontChars[0] != 32) TraceLog(WARNING, "TTF spritefont loading: first character is not SPACE(32) character");
stbtt_InitFont(&fontInfo, ttfBuffer, 0);
scale = stbtt_ScaleForPixelHeight(&fontInfo, fontSize);
stbtt_GetFontVMetrics(&fontInfo, &ascent, 0, 0);
baseline = (int)(ascent*scale);
if (fontChars[0] != 32) TraceLog(LOG_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], 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");
//if (result > 0) TraceLog(LOG_INFO, "TTF spritefont loading: first unused row of generated bitmap: %i", result);
if (result < 0) TraceLog(LOG_WARNING, "TTF spritefont loading: Not all the characters fit in the font");
free(ttfBuffer);
@ -923,7 +936,7 @@ static SpriteFont LoadTTF(const char *fileName, int fontSize, int charsCount, in
font.chars[i].rec.height = (int)charData[i].y1 - (int)charData[i].y0;
font.chars[i].offsetX = charData[i].xoff;
font.chars[i].offsetY = charData[i].yoff;
font.chars[i].offsetY = baseline + charData[i].yoff;
font.chars[i].advanceX = (int)charData[i].xadvance;
}

File diff suppressed because it is too large Load diff

View file

@ -174,7 +174,7 @@ func LoadImage(fileName string) *Image {
}
// LoadImageEx - Load image data from Color array data (RGBA - 32bit)
func LoadImageEx(pixels []Color, width int32, height int32) *Image {
func LoadImageEx(pixels []Color, width, height int32) *Image {
cpixels := pixels[0].cptr()
cwidth := (C.int)(width)
cheight := (C.int)(height)
@ -184,7 +184,7 @@ func LoadImageEx(pixels []Color, width int32, height int32) *Image {
}
// LoadImagePro - Load image from raw data with parameters
func LoadImagePro(data []byte, width int32, height int32, format TextureFormat) *Image {
func LoadImagePro(data []byte, width, height int32, format TextureFormat) *Image {
cdata := unsafe.Pointer(&data[0])
cwidth := (C.int)(width)
cheight := (C.int)(height)
@ -195,7 +195,7 @@ func LoadImagePro(data []byte, width int32, height int32, format TextureFormat)
}
// LoadImageRaw - Load image data from RAW file
func LoadImageRaw(fileName string, width int32, height int32, format TextureFormat, headerSize int32) *Image {
func LoadImageRaw(fileName string, width, height int32, format TextureFormat, headerSize int32) *Image {
cfileName := C.CString(fileName)
defer C.free(unsafe.Pointer(cfileName))
cwidth := (C.int)(width)
@ -225,7 +225,7 @@ func LoadTextureFromImage(image *Image) Texture2D {
}
// LoadRenderTexture - Load a texture to be used for rendering
func LoadRenderTexture(width int32, height int32) RenderTexture2D {
func LoadRenderTexture(width, height int32) RenderTexture2D {
cwidth := (C.int)(width)
cheight := (C.int)(height)
ret := C.LoadRenderTexture(cwidth, cheight)
@ -273,6 +273,15 @@ func UpdateTexture(texture Texture2D, pixels unsafe.Pointer) {
C.UpdateTexture(*ctexture, cpixels)
}
// SaveImageAs - Save image to a PNG file
func SaveImageAs(name string, image Image) {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))
cimage := image.cptr()
C.SaveImageAs(cname, *cimage)
}
// ImageToPOT - Convert image to POT (power-of-two)
func ImageToPOT(image *Image, fillColor Color) {
cimage := image.cptr()
@ -288,14 +297,14 @@ func ImageFormat(image *Image, newFormat int32) {
}
// ImageAlphaMask - Apply alpha mask to image
func ImageAlphaMask(image *Image, alphaMask *Image) {
func ImageAlphaMask(image, alphaMask *Image) {
cimage := image.cptr()
calphaMask := alphaMask.cptr()
C.ImageAlphaMask(cimage, *calphaMask)
}
// ImageDither - Dither image data to 16bpp or lower (Floyd-Steinberg dithering)
func ImageDither(image *Image, rBpp int32, gBpp int32, bBpp int32, aBpp int32) {
func ImageDither(image *Image, rBpp, gBpp, bBpp, aBpp int32) {
cimage := image.cptr()
crBpp := (C.int)(rBpp)
cgBpp := (C.int)(gBpp)
@ -320,7 +329,7 @@ func ImageCrop(image *Image, crop Rectangle) {
}
// ImageResize - Resize an image (bilinear filtering)
func ImageResize(image *Image, newWidth int32, newHeight int32) {
func ImageResize(image *Image, newWidth, newHeight int32) {
cimage := image.cptr()
cnewWidth := (C.int)(newWidth)
cnewHeight := (C.int)(newHeight)
@ -328,7 +337,7 @@ func ImageResize(image *Image, newWidth int32, newHeight int32) {
}
// ImageResizeNN - Resize an image (Nearest-Neighbor scaling algorithm)
func ImageResizeNN(image *Image, newWidth int32, newHeight int32) {
func ImageResizeNN(image *Image, newWidth, newHeight int32) {
cimage := image.cptr()
cnewWidth := (C.int)(newWidth)
cnewHeight := (C.int)(newHeight)
@ -360,7 +369,7 @@ func ImageTextEx(font SpriteFont, text string, fontSize float32, spacing int32,
}
// ImageDraw - Draw a source image within a destination image
func ImageDraw(dst *Image, src *Image, srcRec Rectangle, dstRec Rectangle) {
func ImageDraw(dst, src *Image, srcRec, dstRec Rectangle) {
cdst := dst.cptr()
csrc := src.cptr()
csrcRec := srcRec.cptr()
@ -437,6 +446,101 @@ func ImageColorBrightness(image *Image, brightness int32) {
C.ImageColorBrightness(cimage, cbrightness)
}
// GenImageColor - Generate image: plain color
func GenImageColor(width, height int, color Color) *Image {
cwidth := (C.int)(width)
cheight := (C.int)(height)
ccolor := color.cptr()
ret := C.GenImageColor(cwidth, cheight, *ccolor)
v := NewImageFromPointer(unsafe.Pointer(&ret))
return v
}
// GenImageGradientV - Generate image: vertical gradient
func GenImageGradientV(width, height int, top, bottom Color) *Image {
cwidth := (C.int)(width)
cheight := (C.int)(height)
ctop := top.cptr()
cbottom := bottom.cptr()
ret := C.GenImageGradientV(cwidth, cheight, *ctop, *cbottom)
v := NewImageFromPointer(unsafe.Pointer(&ret))
return v
}
// GenImageGradientH - Generate image: horizontal gradient
func GenImageGradientH(width, height int, left, right Color) *Image {
cwidth := (C.int)(width)
cheight := (C.int)(height)
cleft := left.cptr()
cright := right.cptr()
ret := C.GenImageGradientH(cwidth, cheight, *cleft, *cright)
v := NewImageFromPointer(unsafe.Pointer(&ret))
return v
}
// GenImageGradientRadial - Generate image: radial gradient
func GenImageGradientRadial(width, height int, density float32, inner, outer Color) *Image {
cwidth := (C.int)(width)
cheight := (C.int)(height)
cdensity := (C.float)(density)
cinner := inner.cptr()
couter := outer.cptr()
ret := C.GenImageGradientRadial(cwidth, cheight, cdensity, *cinner, *couter)
v := NewImageFromPointer(unsafe.Pointer(&ret))
return v
}
// GenImageChecked - Generate image: checked
func GenImageChecked(width, height, checksX, checksY int, col1, col2 Color) *Image {
cwidth := (C.int)(width)
cheight := (C.int)(height)
cchecksX := (C.int)(checksX)
cchecksY := (C.int)(checksY)
ccol1 := col1.cptr()
ccol2 := col2.cptr()
ret := C.GenImageChecked(cwidth, cheight, cchecksX, cchecksY, *ccol1, *ccol2)
v := NewImageFromPointer(unsafe.Pointer(&ret))
return v
}
// GenImageWhiteNoise - Generate image: white noise
func GenImageWhiteNoise(width, height int, factor float32) *Image {
cwidth := (C.int)(width)
cheight := (C.int)(height)
cfactor := (C.float)(factor)
ret := C.GenImageWhiteNoise(cwidth, cheight, cfactor)
v := NewImageFromPointer(unsafe.Pointer(&ret))
return v
}
// GenImagePerlinNoise - Generate image: perlin noise
func GenImagePerlinNoise(width, height int, scale float32) *Image {
cwidth := (C.int)(width)
cheight := (C.int)(height)
cscale := (C.float)(scale)
ret := C.GenImagePerlinNoise(cwidth, cheight, cscale)
v := NewImageFromPointer(unsafe.Pointer(&ret))
return v
}
// GenImageCellular - Generate image: cellular algorithm. Bigger tileSize means bigger cells
func GenImageCellular(width, height, tileSize int) *Image {
cwidth := (C.int)(width)
cheight := (C.int)(height)
ctileSize := (C.int)(tileSize)
ret := C.GenImageCellular(cwidth, cheight, ctileSize)
v := NewImageFromPointer(unsafe.Pointer(&ret))
return v
}
// GenTextureMipmaps - Generate GPU mipmaps for a texture
func GenTextureMipmaps(texture *Texture2D) {
ctexture := texture.cptr()
@ -475,7 +579,7 @@ func DrawTextureV(texture Texture2D, position Vector2, tint Color) {
}
// DrawTextureEx - Draw a Texture2D with extended parameters
func DrawTextureEx(texture Texture2D, position Vector2, rotation float32, scale float32, tint Color) {
func DrawTextureEx(texture Texture2D, position Vector2, rotation, scale float32, tint Color) {
ctexture := texture.cptr()
cposition := position.cptr()
crotation := (C.float)(rotation)
@ -494,7 +598,7 @@ func DrawTextureRec(texture Texture2D, sourceRec Rectangle, position Vector2, ti
}
// DrawTexturePro - Draw a part of a texture defined by a rectangle with 'pro' parameters
func DrawTexturePro(texture Texture2D, sourceRec Rectangle, destRec Rectangle, origin Vector2, rotation float32, tint Color) {
func DrawTexturePro(texture Texture2D, sourceRec, destRec Rectangle, origin Vector2, rotation float32, tint Color) {
ctexture := texture.cptr()
csourceRec := sourceRec.cptr()
cdestRec := destRec.cptr()

View file

@ -14,10 +14,10 @@
*
* #define SUPPORT_TRACELOG
* Show TraceLog() output messages
* NOTE: By default DEBUG traces not shown
* NOTE: By default LOG_DEBUG traces not shown
*
* #define SUPPORT_TRACELOG_DEBUG
* Show TraceLog() DEBUG messages
* Show TraceLog() LOG_DEBUG messages
*
* DEPENDENCIES:
* stb_image_write - BMP/PNG writting functions
@ -45,8 +45,9 @@
**********************************************************************************************/
#define SUPPORT_TRACELOG // Output tracelog messages
//#define SUPPORT_TRACELOG_DEBUG // Avoid DEBUG messages tracing
//#define SUPPORT_TRACELOG_DEBUG // Avoid LOG_DEBUG messages tracing
#include "raylib.h" // WARNING: Required for: LogType enum
#include "utils.h"
#if defined(PLATFORM_ANDROID)
@ -89,7 +90,7 @@ static int android_close(void *cookie);
// Module Functions Definition - Utilities
//----------------------------------------------------------------------------------
// Output trace log messages
// Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG)
void TraceLog(int msgType, const char *text, ...)
{
#if defined(SUPPORT_TRACELOG)
@ -102,10 +103,10 @@ void TraceLog(int msgType, const char *text, ...)
switch(msgType)
{
case INFO: strcpy(buffer, "INFO: "); break;
case ERROR: strcpy(buffer, "ERROR: "); break;
case WARNING: strcpy(buffer, "WARNING: "); break;
case DEBUG: strcpy(buffer, "DEBUG: "); break;
case LOG_INFO: strcpy(buffer, "INFO: "); break;
case LOG_ERROR: strcpy(buffer, "ERROR: "); break;
case LOG_WARNING: strcpy(buffer, "WARNING: "); break;
case LOG_DEBUG: strcpy(buffer, "DEBUG: "); break;
default: break;
}
@ -118,19 +119,19 @@ void TraceLog(int msgType, const char *text, ...)
#if defined(PLATFORM_ANDROID)
switch(msgType)
{
case INFO: __android_log_vprint(ANDROID_LOG_INFO, "raylib", buffer, args); break;
case ERROR: __android_log_vprint(ANDROID_LOG_ERROR, "raylib", buffer, args); break;
case WARNING: __android_log_vprint(ANDROID_LOG_WARN, "raylib", buffer, args); break;
case DEBUG: if (traceDebugMsgs) __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", buffer, args); break;
case LOG_INFO: __android_log_vprint(ANDROID_LOG_INFO, "raylib", buffer, args); break;
case LOG_ERROR: __android_log_vprint(ANDROID_LOG_ERROR, "raylib", buffer, args); break;
case LOG_WARNING: __android_log_vprint(ANDROID_LOG_WARN, "raylib", buffer, args); break;
case LOG_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);
if ((msgType != LOG_DEBUG) || ((msgType == LOG_DEBUG) && (traceDebugMsgs))) vprintf(buffer, args);
#endif
va_end(args);
if (msgType == ERROR) exit(1); // If ERROR message, exit program
if (msgType == LOG_ERROR) exit(1); // If LOG_ERROR message, exit program
#endif // SUPPORT_TRACELOG
}
@ -195,7 +196,7 @@ static int android_read(void *cookie, char *buf, int size)
static int android_write(void *cookie, const char *buf, int size)
{
TraceLog(ERROR, "Can't provide write access to the APK");
TraceLog(LOG_ERROR, "Can't provide write access to the APK");
return EACCES;
}