Removed useless spaces

This commit is contained in:
raysan5 2014-09-03 16:51:28 +02:00
parent 222995c32e
commit d2b98fbb5c
13 changed files with 1288 additions and 1288 deletions

View file

@ -3,21 +3,21 @@
* raylib.audio * raylib.audio
* *
* Basic functions to manage Audio: InitAudioDevice, LoadAudioFiles, PlayAudioFiles * Basic functions to manage Audio: InitAudioDevice, LoadAudioFiles, PlayAudioFiles
* *
* Uses external lib: * Uses external lib:
* OpenAL - Audio device management lib * OpenAL - Audio device management lib
* stb_vorbis - Ogg audio files loading * stb_vorbis - Ogg audio files loading
* *
* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) * Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
* *
* Permission is granted to anyone to use this software for any purpose, including commercial * Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions: * applications, and to alter it and redistribute it freely, subject to the following restrictions:
* *
* 1. The origin of this software must not be misrepresented; you must not claim that you * 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment * wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required. * in the product documentation would be appreciated but is not required.
* *
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
@ -54,16 +54,16 @@
// NOTE: Anything longer than ~10 seconds should be streamed... // NOTE: Anything longer than ~10 seconds should be streamed...
typedef struct Music { typedef struct Music {
stb_vorbis *stream; stb_vorbis *stream;
ALuint buffers[MUSIC_STREAM_BUFFERS]; ALuint buffers[MUSIC_STREAM_BUFFERS];
ALuint source; ALuint source;
ALenum format; ALenum format;
int channels; int channels;
int sampleRate; int sampleRate;
int totalSamplesLeft; int totalSamplesLeft;
bool loop; bool loop;
} Music; } Music;
// Wave file data // Wave file data
@ -72,7 +72,7 @@ typedef struct Wave {
unsigned int dataSize; // Data size in bytes unsigned int dataSize; // Data size in bytes
unsigned int sampleRate; unsigned int sampleRate;
short bitsPerSample; short bitsPerSample;
short channels; short channels;
} Wave; } Wave;
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
@ -102,22 +102,22 @@ void InitAudioDevice()
{ {
// Open and initialize a device with default settings // Open and initialize a device with default settings
ALCdevice *device = alcOpenDevice(NULL); ALCdevice *device = alcOpenDevice(NULL);
if(!device) TraceLog(ERROR, "Could not open audio device"); if(!device) TraceLog(ERROR, "Could not open audio device");
ALCcontext *context = alcCreateContext(device, NULL); ALCcontext *context = alcCreateContext(device, NULL);
if(context == NULL || alcMakeContextCurrent(context) == ALC_FALSE) if(context == NULL || alcMakeContextCurrent(context) == ALC_FALSE)
{ {
if(context != NULL) alcDestroyContext(context); if(context != NULL) alcDestroyContext(context);
alcCloseDevice(device); alcCloseDevice(device);
TraceLog(ERROR, "Could not setup audio context"); TraceLog(ERROR, "Could not setup audio context");
} }
TraceLog(INFO, "Audio device and context initialized successfully: %s\n", alcGetString(device, ALC_DEVICE_SPECIFIER)); TraceLog(INFO, "Audio device and context initialized successfully: %s\n", alcGetString(device, ALC_DEVICE_SPECIFIER));
// Listener definition (just for 2D) // Listener definition (just for 2D)
alListener3f(AL_POSITION, 0, 0, 0); alListener3f(AL_POSITION, 0, 0, 0);
alListener3f(AL_VELOCITY, 0, 0, 0); alListener3f(AL_VELOCITY, 0, 0, 0);
@ -131,7 +131,7 @@ void CloseAudioDevice()
ALCdevice *device; ALCdevice *device;
ALCcontext *context = alcGetCurrentContext(); ALCcontext *context = alcGetCurrentContext();
if (context == NULL) TraceLog(WARNING, "Could not get current audio context for closing"); if (context == NULL) TraceLog(WARNING, "Could not get current audio context for closing");
device = alcGetContextsDevice(context); device = alcGetContextsDevice(context);
@ -150,41 +150,41 @@ Sound LoadSound(char *fileName)
{ {
Sound sound; Sound sound;
Wave wave; Wave wave;
// NOTE: The entire file is loaded to memory to play it all at once (no-streaming) // NOTE: The entire file is loaded to memory to play it all at once (no-streaming)
// Audio file loading // Audio file loading
// NOTE: Buffer space is allocated inside function, Wave must be freed // NOTE: Buffer space is allocated inside function, Wave must be freed
if (strcmp(GetExtension(fileName),"wav") == 0) wave = LoadWAV(fileName); if (strcmp(GetExtension(fileName),"wav") == 0) wave = LoadWAV(fileName);
else if (strcmp(GetExtension(fileName),"ogg") == 0) wave = LoadOGG(fileName); else if (strcmp(GetExtension(fileName),"ogg") == 0) wave = LoadOGG(fileName);
else TraceLog(WARNING, "[%s] Sound extension not recognized, it can't be loaded", fileName); else TraceLog(WARNING, "[%s] Sound extension not recognized, it can't be loaded", fileName);
if (wave.data != NULL) if (wave.data != NULL)
{ {
ALenum format = 0; ALenum format = 0;
// The OpenAL format is worked out by looking at the number of channels and the bits per sample // The OpenAL format is worked out by looking at the number of channels and the bits per sample
if (wave.channels == 1) if (wave.channels == 1)
{ {
if (wave.bitsPerSample == 8 ) format = AL_FORMAT_MONO8; if (wave.bitsPerSample == 8 ) format = AL_FORMAT_MONO8;
else if (wave.bitsPerSample == 16) format = AL_FORMAT_MONO16; else if (wave.bitsPerSample == 16) format = AL_FORMAT_MONO16;
} }
else if (wave.channels == 2) else if (wave.channels == 2)
{ {
if (wave.bitsPerSample == 8 ) format = AL_FORMAT_STEREO8; if (wave.bitsPerSample == 8 ) format = AL_FORMAT_STEREO8;
else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16; else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16;
} }
// Create an audio source // Create an audio source
ALuint source; ALuint source;
alGenSources(1, &source); // Generate pointer to audio source alGenSources(1, &source); // Generate pointer to audio source
alSourcef(source, AL_PITCH, 1); alSourcef(source, AL_PITCH, 1);
alSourcef(source, AL_GAIN, 1); alSourcef(source, AL_GAIN, 1);
alSource3f(source, AL_POSITION, 0, 0, 0); alSource3f(source, AL_POSITION, 0, 0, 0);
alSource3f(source, AL_VELOCITY, 0, 0, 0); alSource3f(source, AL_VELOCITY, 0, 0, 0);
alSourcei(source, AL_LOOPING, AL_FALSE); alSourcei(source, AL_LOOPING, AL_FALSE);
// Convert loaded data to OpenAL buffer // Convert loaded data to OpenAL buffer
//---------------------------------------- //----------------------------------------
ALuint buffer; ALuint buffer;
@ -195,17 +195,17 @@ Sound LoadSound(char *fileName)
// Attach sound buffer to source // Attach sound buffer to source
alSourcei(source, AL_BUFFER, buffer); alSourcei(source, AL_BUFFER, buffer);
// Unallocate WAV data // Unallocate WAV data
UnloadWave(wave); UnloadWave(wave);
TraceLog(INFO, "[%s] Sound file loaded successfully", fileName); TraceLog(INFO, "[%s] Sound file loaded successfully", fileName);
TraceLog(INFO, "[%s] Sample rate: %i - Channels: %i", fileName, wave.sampleRate, wave.channels); TraceLog(INFO, "[%s] Sample rate: %i - Channels: %i", fileName, wave.sampleRate, wave.channels);
sound.source = source; sound.source = source;
sound.buffer = buffer; sound.buffer = buffer;
} }
return sound; return sound;
} }
@ -220,9 +220,9 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
unsigned char version; // rRES file version and subversion unsigned char version; // rRES file version and subversion
char useless; // rRES header reserved data char useless; // rRES header reserved data
short numRes; short numRes;
ResInfoHeader infoHeader; ResInfoHeader infoHeader;
FILE *rresFile = fopen(rresName, "rb"); FILE *rresFile = fopen(rresName, "rb");
if (!rresFile) TraceLog(WARNING, "[%s] Could not open raylib resource file", rresName); if (!rresFile) TraceLog(WARNING, "[%s] Could not open raylib resource file", rresName);
@ -235,7 +235,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
fread(&id[3], sizeof(char), 1, rresFile); fread(&id[3], sizeof(char), 1, rresFile);
fread(&version, sizeof(char), 1, rresFile); fread(&version, sizeof(char), 1, rresFile);
fread(&useless, sizeof(char), 1, rresFile); fread(&useless, sizeof(char), 1, rresFile);
if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S')) if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S'))
{ {
TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName); TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName);
@ -244,11 +244,11 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
{ {
// Read number of resources embedded // Read number of resources embedded
fread(&numRes, sizeof(short), 1, rresFile); fread(&numRes, sizeof(short), 1, rresFile);
for (int i = 0; i < numRes; i++) for (int i = 0; i < numRes; i++)
{ {
fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile); fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile);
if (infoHeader.id == resId) if (infoHeader.id == resId)
{ {
found = true; found = true;
@ -258,56 +258,56 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
{ {
// TODO: Check data compression type // TODO: Check data compression type
// NOTE: We suppose compression type 2 (DEFLATE - default) // NOTE: We suppose compression type 2 (DEFLATE - default)
// Reading SOUND parameters // Reading SOUND parameters
Wave wave; Wave wave;
short sampleRate, bps; short sampleRate, bps;
char channels, reserved; char channels, reserved;
fread(&sampleRate, sizeof(short), 1, rresFile); // Sample rate (frequency) fread(&sampleRate, sizeof(short), 1, rresFile); // Sample rate (frequency)
fread(&bps, sizeof(short), 1, rresFile); // Bits per sample fread(&bps, sizeof(short), 1, rresFile); // Bits per sample
fread(&channels, 1, 1, rresFile); // Channels (1 - mono, 2 - stereo) fread(&channels, 1, 1, rresFile); // Channels (1 - mono, 2 - stereo)
fread(&reserved, 1, 1, rresFile); // <reserved> fread(&reserved, 1, 1, rresFile); // <reserved>
wave.sampleRate = sampleRate; wave.sampleRate = sampleRate;
wave.dataSize = infoHeader.srcSize; wave.dataSize = infoHeader.srcSize;
wave.bitsPerSample = bps; wave.bitsPerSample = bps;
wave.channels = (short)channels; wave.channels = (short)channels;
unsigned char *data = malloc(infoHeader.size); unsigned char *data = malloc(infoHeader.size);
fread(data, infoHeader.size, 1, rresFile); fread(data, infoHeader.size, 1, rresFile);
wave.data = DecompressData(data, infoHeader.size, infoHeader.srcSize); wave.data = DecompressData(data, infoHeader.size, infoHeader.srcSize);
free(data); free(data);
// Convert wave to Sound (OpenAL) // Convert wave to Sound (OpenAL)
ALenum format = 0; ALenum format = 0;
// The OpenAL format is worked out by looking at the number of channels and the bits per sample // The OpenAL format is worked out by looking at the number of channels and the bits per sample
if (wave.channels == 1) if (wave.channels == 1)
{ {
if (wave.bitsPerSample == 8 ) format = AL_FORMAT_MONO8; if (wave.bitsPerSample == 8 ) format = AL_FORMAT_MONO8;
else if (wave.bitsPerSample == 16) format = AL_FORMAT_MONO16; else if (wave.bitsPerSample == 16) format = AL_FORMAT_MONO16;
} }
else if (wave.channels == 2) else if (wave.channels == 2)
{ {
if (wave.bitsPerSample == 8 ) format = AL_FORMAT_STEREO8; if (wave.bitsPerSample == 8 ) format = AL_FORMAT_STEREO8;
else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16; else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16;
} }
// Create an audio source // Create an audio source
ALuint source; ALuint source;
alGenSources(1, &source); // Generate pointer to audio source alGenSources(1, &source); // Generate pointer to audio source
alSourcef(source, AL_PITCH, 1); alSourcef(source, AL_PITCH, 1);
alSourcef(source, AL_GAIN, 1); alSourcef(source, AL_GAIN, 1);
alSource3f(source, AL_POSITION, 0, 0, 0); alSource3f(source, AL_POSITION, 0, 0, 0);
alSource3f(source, AL_VELOCITY, 0, 0, 0); alSource3f(source, AL_VELOCITY, 0, 0, 0);
alSourcei(source, AL_LOOPING, AL_FALSE); alSourcei(source, AL_LOOPING, AL_FALSE);
// Convert loaded data to OpenAL buffer // Convert loaded data to OpenAL buffer
//---------------------------------------- //----------------------------------------
ALuint buffer; ALuint buffer;
@ -318,12 +318,12 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
// Attach sound buffer to source // Attach sound buffer to source
alSourcei(source, AL_BUFFER, buffer); alSourcei(source, AL_BUFFER, buffer);
// Unallocate WAV data // Unallocate WAV data
UnloadWave(wave); UnloadWave(wave);
TraceLog(INFO, "[%s] Sound loaded successfully from resource, sample rate: %i", rresName, (int)sampleRate); TraceLog(INFO, "[%s] Sound loaded successfully from resource, sample rate: %i", rresName, (int)sampleRate);
sound.source = source; sound.source = source;
sound.buffer = buffer; sound.buffer = buffer;
} }
@ -344,18 +344,18 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
case 4: break; // RAW: No parameters case 4: break; // RAW: No parameters
default: break; default: break;
} }
// Jump DATA to read next infoHeader // Jump DATA to read next infoHeader
fseek(rresFile, infoHeader.size, SEEK_CUR); fseek(rresFile, infoHeader.size, SEEK_CUR);
} }
} }
} }
fclose(rresFile); fclose(rresFile);
} }
if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId); if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId);
return sound; return sound;
} }
@ -370,7 +370,7 @@ void UnloadSound(Sound sound)
void PlaySound(Sound sound) void PlaySound(Sound sound)
{ {
alSourcePlay(sound.source); // Play the sound alSourcePlay(sound.source); // Play the sound
//TraceLog(INFO, "Playing sound"); //TraceLog(INFO, "Playing sound");
// Find the current position of the sound being played // Find the current position of the sound being played
@ -380,7 +380,7 @@ void PlaySound(Sound sound)
// //
//int sampleRate; //int sampleRate;
//alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate); // AL_CHANNELS, AL_BITS (bps) //alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate); // AL_CHANNELS, AL_BITS (bps)
//float seconds = (float)byteOffset / sampleRate; // Number of seconds since the beginning of the sound //float seconds = (float)byteOffset / sampleRate; // Number of seconds since the beginning of the sound
//or //or
//float result; //float result;
@ -404,10 +404,10 @@ bool SoundIsPlaying(Sound sound)
{ {
bool playing = false; bool playing = false;
ALint state; ALint state;
alGetSourcei(sound.source, AL_SOURCE_STATE, &state); alGetSourcei(sound.source, AL_SOURCE_STATE, &state);
if (state == AL_PLAYING) playing = true; if (state == AL_PLAYING) playing = true;
return playing; return playing;
} }
@ -434,49 +434,49 @@ void PlayMusicStream(char *fileName)
{ {
// Stop current music, clean buffers, unload current stream // Stop current music, clean buffers, unload current stream
StopMusicStream(); StopMusicStream();
// Open audio stream // Open audio stream
currentMusic.stream = stb_vorbis_open_filename(fileName, NULL, NULL); currentMusic.stream = stb_vorbis_open_filename(fileName, NULL, NULL);
if (currentMusic.stream == NULL) TraceLog(WARNING, "[%s] Could not open ogg audio file", fileName); if (currentMusic.stream == NULL) TraceLog(WARNING, "[%s] Could not open ogg audio file", fileName);
else else
{ {
// Get file info // Get file info
stb_vorbis_info info = stb_vorbis_get_info(currentMusic.stream); stb_vorbis_info info = stb_vorbis_get_info(currentMusic.stream);
currentMusic.channels = info.channels; currentMusic.channels = info.channels;
currentMusic.sampleRate = info.sample_rate; currentMusic.sampleRate = info.sample_rate;
TraceLog(INFO, "[%s] Ogg sample rate: %i", fileName, info.sample_rate); TraceLog(INFO, "[%s] Ogg sample rate: %i", fileName, info.sample_rate);
TraceLog(INFO, "[%s] Ogg channels: %i", fileName, info.channels); TraceLog(INFO, "[%s] Ogg channels: %i", fileName, info.channels);
TraceLog(INFO, "[%s] Temp memory required: %i", fileName, info.temp_memory_required); TraceLog(INFO, "[%s] Temp memory required: %i", fileName, info.temp_memory_required);
if (info.channels == 2) currentMusic.format = AL_FORMAT_STEREO16; if (info.channels == 2) currentMusic.format = AL_FORMAT_STEREO16;
else currentMusic.format = AL_FORMAT_MONO16; else currentMusic.format = AL_FORMAT_MONO16;
currentMusic.loop = true; // We loop by default currentMusic.loop = true; // We loop by default
musicEnabled = true; musicEnabled = true;
// Create an audio source // Create an audio source
alGenSources(1, &currentMusic.source); // Generate pointer to audio source alGenSources(1, &currentMusic.source); // Generate pointer to audio source
alSourcef(currentMusic.source, AL_PITCH, 1); alSourcef(currentMusic.source, AL_PITCH, 1);
alSourcef(currentMusic.source, AL_GAIN, 1); alSourcef(currentMusic.source, AL_GAIN, 1);
alSource3f(currentMusic.source, AL_POSITION, 0, 0, 0); alSource3f(currentMusic.source, AL_POSITION, 0, 0, 0);
alSource3f(currentMusic.source, AL_VELOCITY, 0, 0, 0); alSource3f(currentMusic.source, AL_VELOCITY, 0, 0, 0);
//alSourcei(currentMusic.source, AL_LOOPING, AL_TRUE); // ERROR: Buffers do not queue! //alSourcei(currentMusic.source, AL_LOOPING, AL_TRUE); // ERROR: Buffers do not queue!
// Generate two OpenAL buffers // Generate two OpenAL buffers
alGenBuffers(2, currentMusic.buffers); alGenBuffers(2, currentMusic.buffers);
// Fill buffers with music... // Fill buffers with music...
BufferMusicStream(currentMusic.buffers[0]); BufferMusicStream(currentMusic.buffers[0]);
BufferMusicStream(currentMusic.buffers[1]); BufferMusicStream(currentMusic.buffers[1]);
// Queue buffers and start playing // Queue buffers and start playing
alSourceQueueBuffers(currentMusic.source, 2, currentMusic.buffers); alSourceQueueBuffers(currentMusic.source, 2, currentMusic.buffers);
alSourcePlay(currentMusic.source); alSourcePlay(currentMusic.source);
// NOTE: Regularly, we must check if a buffer has been processed and refill it: MusicStreamUpdate() // NOTE: Regularly, we must check if a buffer has been processed and refill it: MusicStreamUpdate()
currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels; currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels;
@ -491,15 +491,15 @@ void StopMusicStream()
if (musicEnabled) if (musicEnabled)
{ {
alSourceStop(currentMusic.source); alSourceStop(currentMusic.source);
EmptyMusicStream(); // Empty music buffers EmptyMusicStream(); // Empty music buffers
alDeleteSources(1, &currentMusic.source); alDeleteSources(1, &currentMusic.source);
alDeleteBuffers(2, currentMusic.buffers); alDeleteBuffers(2, currentMusic.buffers);
stb_vorbis_close(currentMusic.stream); stb_vorbis_close(currentMusic.stream);
} }
musicEnabled = false; musicEnabled = false;
} }
@ -514,9 +514,9 @@ void PauseMusicStream()
bool MusicIsPlaying() bool MusicIsPlaying()
{ {
ALenum state; ALenum state;
alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state); alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
return (state == AL_PLAYING); return (state == AL_PLAYING);
} }
@ -530,7 +530,7 @@ void SetMusicVolume(float volume)
float GetMusicTimeLength() float GetMusicTimeLength()
{ {
float totalSeconds = stb_vorbis_stream_length_in_seconds(currentMusic.stream); float totalSeconds = stb_vorbis_stream_length_in_seconds(currentMusic.stream);
return totalSeconds; return totalSeconds;
} }
@ -538,11 +538,11 @@ float GetMusicTimeLength()
float GetMusicTimePlayed() float GetMusicTimePlayed()
{ {
int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels; int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels;
int samplesPlayed = totalSamples - currentMusic.totalSamplesLeft; int samplesPlayed = totalSamples - currentMusic.totalSamplesLeft;
float secondsPlayed = (float)samplesPlayed / (currentMusic.sampleRate * currentMusic.channels); float secondsPlayed = (float)samplesPlayed / (currentMusic.sampleRate * currentMusic.channels);
return secondsPlayed; return secondsPlayed;
} }
@ -553,30 +553,30 @@ float GetMusicTimePlayed()
// Fill music buffers with new data from music stream // Fill music buffers with new data from music stream
static bool BufferMusicStream(ALuint buffer) static bool BufferMusicStream(ALuint buffer)
{ {
short pcm[MUSIC_BUFFER_SIZE]; short pcm[MUSIC_BUFFER_SIZE];
int size = 0; // Total size of data steamed (in bytes) int size = 0; // Total size of data steamed (in bytes)
int streamedBytes = 0; // Bytes of data obtained in one samples get int streamedBytes = 0; // Bytes of data obtained in one samples get
bool active = true; // We can get more data from stream (not finished) bool active = true; // We can get more data from stream (not finished)
if (musicEnabled) if (musicEnabled)
{ {
while (size < MUSIC_BUFFER_SIZE) while (size < MUSIC_BUFFER_SIZE)
{ {
streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic.stream, currentMusic.channels, pcm + size, MUSIC_BUFFER_SIZE - size); streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic.stream, currentMusic.channels, pcm + size, MUSIC_BUFFER_SIZE - size);
if (streamedBytes > 0) size += (streamedBytes*currentMusic.channels); if (streamedBytes > 0) size += (streamedBytes*currentMusic.channels);
else break; else break;
} }
TraceLog(DEBUG, "Streaming music data to buffer. Bytes streamed: %i", size); TraceLog(DEBUG, "Streaming music data to buffer. Bytes streamed: %i", size);
} }
if (size > 0) if (size > 0)
{ {
alBufferData(buffer, currentMusic.format, pcm, size*sizeof(short), currentMusic.sampleRate); alBufferData(buffer, currentMusic.format, pcm, size*sizeof(short), currentMusic.sampleRate);
currentMusic.totalSamplesLeft -= size; currentMusic.totalSamplesLeft -= size;
} }
else else
@ -585,21 +585,21 @@ static bool BufferMusicStream(ALuint buffer)
TraceLog(WARNING, "No more data obtained from stream"); TraceLog(WARNING, "No more data obtained from stream");
} }
return active; return active;
} }
// Empty music buffers // Empty music buffers
static void EmptyMusicStream() static void EmptyMusicStream()
{ {
ALuint buffer = 0; ALuint buffer = 0;
int queued = 0; int queued = 0;
alGetSourcei(currentMusic.source, AL_BUFFERS_QUEUED, &queued); alGetSourcei(currentMusic.source, AL_BUFFERS_QUEUED, &queued);
while(queued > 0) while(queued > 0)
{ {
alSourceUnqueueBuffers(currentMusic.source, 1, &buffer); alSourceUnqueueBuffers(currentMusic.source, 1, &buffer);
queued--; queued--;
} }
} }
@ -610,12 +610,12 @@ extern void UpdateMusicStream()
ALuint buffer = 0; ALuint buffer = 0;
ALint processed = 0; ALint processed = 0;
bool active = true; bool active = true;
if (musicEnabled) if (musicEnabled)
{ {
// Get the number of already processed buffers (if any) // Get the number of already processed buffers (if any)
alGetSourcei(currentMusic.source, AL_BUFFERS_PROCESSED, &processed); alGetSourcei(currentMusic.source, AL_BUFFERS_PROCESSED, &processed);
while (processed > 0) while (processed > 0)
{ {
// Recover processed buffer for refill // Recover processed buffer for refill
@ -623,32 +623,32 @@ extern void UpdateMusicStream()
// Refill buffer // Refill buffer
active = BufferMusicStream(buffer); active = BufferMusicStream(buffer);
// If no more data to stream, restart music (if loop) // If no more data to stream, restart music (if loop)
if ((!active) && (currentMusic.loop)) if ((!active) && (currentMusic.loop))
{ {
if (currentMusic.loop) if (currentMusic.loop)
{ {
stb_vorbis_seek_start(currentMusic.stream); stb_vorbis_seek_start(currentMusic.stream);
currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels; currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels;
active = BufferMusicStream(buffer); active = BufferMusicStream(buffer);
} }
} }
// Add refilled buffer to queue again... don't let the music stop! // Add refilled buffer to queue again... don't let the music stop!
alSourceQueueBuffers(currentMusic.source, 1, &buffer); alSourceQueueBuffers(currentMusic.source, 1, &buffer);
if(alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Ogg playing, error buffering data..."); if(alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Ogg playing, error buffering data...");
processed--; processed--;
} }
ALenum state; ALenum state;
alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state); alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic.source); if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic.source);
if (!active) StopMusicStream(); if (!active) StopMusicStream();
} }
} }
@ -678,16 +678,16 @@ static Wave LoadWAV(const char *fileName)
char subChunkID[4]; char subChunkID[4];
long subChunkSize; long subChunkSize;
} WaveData; } WaveData;
RiffHeader riffHeader; RiffHeader riffHeader;
WaveFormat waveFormat; WaveFormat waveFormat;
WaveData waveData; WaveData waveData;
Wave wave; Wave wave;
FILE *wavFile; FILE *wavFile;
wavFile = fopen(fileName, "rb"); wavFile = fopen(fileName, "rb");
if (!wavFile) if (!wavFile)
{ {
TraceLog(WARNING, "[%s] Could not open WAV file", fileName); TraceLog(WARNING, "[%s] Could not open WAV file", fileName);
@ -696,7 +696,7 @@ static Wave LoadWAV(const char *fileName)
{ {
// Read in the first chunk into the struct // Read in the first chunk into the struct
fread(&riffHeader, sizeof(RiffHeader), 1, wavFile); fread(&riffHeader, sizeof(RiffHeader), 1, wavFile);
// Check for RIFF and WAVE tags // Check for RIFF and WAVE tags
if (((riffHeader.chunkID[0] != 'R') || (riffHeader.chunkID[1] != 'I') || (riffHeader.chunkID[2] != 'F') || (riffHeader.chunkID[3] != 'F')) || if (((riffHeader.chunkID[0] != 'R') || (riffHeader.chunkID[1] != 'I') || (riffHeader.chunkID[2] != 'F') || (riffHeader.chunkID[3] != 'F')) ||
((riffHeader.format[0] != 'W') || (riffHeader.format[1] != 'A') || (riffHeader.format[2] != 'V') || (riffHeader.format[3] != 'E'))) ((riffHeader.format[0] != 'W') || (riffHeader.format[1] != 'A') || (riffHeader.format[2] != 'V') || (riffHeader.format[3] != 'E')))
@ -707,7 +707,7 @@ static Wave LoadWAV(const char *fileName)
{ {
// Read in the 2nd chunk for the wave info // Read in the 2nd chunk for the wave info
fread(&waveFormat, sizeof(WaveFormat), 1, wavFile); fread(&waveFormat, sizeof(WaveFormat), 1, wavFile);
// Check for fmt tag // Check for fmt tag
if ((waveFormat.subChunkID[0] != 'f') || (waveFormat.subChunkID[1] != 'm') || if ((waveFormat.subChunkID[0] != 'f') || (waveFormat.subChunkID[1] != 'm') ||
(waveFormat.subChunkID[2] != 't') || (waveFormat.subChunkID[3] != ' ')) (waveFormat.subChunkID[2] != 't') || (waveFormat.subChunkID[3] != ' '))
@ -718,10 +718,10 @@ static Wave LoadWAV(const char *fileName)
{ {
// Check for extra parameters; // Check for extra parameters;
if (waveFormat.subChunkSize > 16) fseek(wavFile, sizeof(short), SEEK_CUR); if (waveFormat.subChunkSize > 16) fseek(wavFile, sizeof(short), SEEK_CUR);
// Read in the the last byte of data before the sound file // Read in the the last byte of data before the sound file
fread(&waveData, sizeof(WaveData), 1, wavFile); fread(&waveData, sizeof(WaveData), 1, wavFile);
// Check for data tag // Check for data tag
if ((waveData.subChunkID[0] != 'd') || (waveData.subChunkID[1] != 'a') || if ((waveData.subChunkID[0] != 'd') || (waveData.subChunkID[1] != 'a') ||
(waveData.subChunkID[2] != 't') || (waveData.subChunkID[3] != 'a')) (waveData.subChunkID[2] != 't') || (waveData.subChunkID[3] != 'a'))
@ -731,17 +731,17 @@ static Wave LoadWAV(const char *fileName)
else else
{ {
// Allocate memory for data // Allocate memory for data
wave.data = (unsigned char *)malloc(sizeof(unsigned char) * waveData.subChunkSize); wave.data = (unsigned char *)malloc(sizeof(unsigned char) * waveData.subChunkSize);
// Read in the sound data into the soundData variable // Read in the sound data into the soundData variable
fread(wave.data, waveData.subChunkSize, 1, wavFile); fread(wave.data, waveData.subChunkSize, 1, wavFile);
// Now we set the variables that we need later // Now we set the variables that we need later
wave.dataSize = waveData.subChunkSize; wave.dataSize = waveData.subChunkSize;
wave.sampleRate = waveFormat.sampleRate; wave.sampleRate = waveFormat.sampleRate;
wave.channels = waveFormat.numChannels; wave.channels = waveFormat.numChannels;
wave.bitsPerSample = waveFormat.bitsPerSample; wave.bitsPerSample = waveFormat.bitsPerSample;
TraceLog(INFO, "[%s] Wave file loaded successfully", fileName); TraceLog(INFO, "[%s] Wave file loaded successfully", fileName);
} }
} }
@ -749,7 +749,7 @@ static Wave LoadWAV(const char *fileName)
fclose(wavFile); fclose(wavFile);
} }
return wave; return wave;
} }
@ -757,42 +757,42 @@ static Wave LoadWAV(const char *fileName)
static Wave LoadOGG(char *fileName) static Wave LoadOGG(char *fileName)
{ {
Wave wave; Wave wave;
stb_vorbis *oggFile = stb_vorbis_open_filename(fileName, NULL, NULL); stb_vorbis *oggFile = stb_vorbis_open_filename(fileName, NULL, NULL);
stb_vorbis_info info = stb_vorbis_get_info(oggFile); stb_vorbis_info info = stb_vorbis_get_info(oggFile);
wave.sampleRate = info.sample_rate; wave.sampleRate = info.sample_rate;
wave.bitsPerSample = 16; wave.bitsPerSample = 16;
wave.channels = info.channels; wave.channels = info.channels;
TraceLog(DEBUG, "[%s] Ogg sample rate: %i", fileName, info.sample_rate); TraceLog(DEBUG, "[%s] Ogg sample rate: %i", fileName, info.sample_rate);
TraceLog(DEBUG, "[%s] Ogg channels: %i", fileName, info.channels); TraceLog(DEBUG, "[%s] Ogg channels: %i", fileName, info.channels);
int totalSamplesLength = (stb_vorbis_stream_length_in_samples(oggFile) * info.channels); int totalSamplesLength = (stb_vorbis_stream_length_in_samples(oggFile) * info.channels);
wave.dataSize = totalSamplesLength*sizeof(short); // Size must be in bytes wave.dataSize = totalSamplesLength*sizeof(short); // Size must be in bytes
TraceLog(DEBUG, "[%s] Samples length: %i", fileName, totalSamplesLength); TraceLog(DEBUG, "[%s] Samples length: %i", fileName, totalSamplesLength);
float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile); float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile);
TraceLog(DEBUG, "[%s] Total seconds: %f", fileName, totalSeconds); TraceLog(DEBUG, "[%s] Total seconds: %f", fileName, totalSeconds);
if (totalSeconds > 10) TraceLog(WARNING, "[%s] Ogg audio lenght is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds); if (totalSeconds > 10) TraceLog(WARNING, "[%s] Ogg audio lenght is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds);
int totalSamples = totalSeconds*info.sample_rate*info.channels; int totalSamples = totalSeconds*info.sample_rate*info.channels;
TraceLog(DEBUG, "[%s] Total samples calculated: %i", fileName, totalSamples); TraceLog(DEBUG, "[%s] Total samples calculated: %i", fileName, totalSamples);
//short *data //short *data
wave.data = malloc(sizeof(short)*totalSamplesLength); wave.data = malloc(sizeof(short)*totalSamplesLength);
int samplesObtained = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, wave.data, totalSamplesLength); int samplesObtained = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, wave.data, totalSamplesLength);
TraceLog(DEBUG, "[%s] Samples obtained: %i", fileName, samplesObtained); TraceLog(DEBUG, "[%s] Samples obtained: %i", fileName, samplesObtained);
stb_vorbis_close(oggFile); stb_vorbis_close(oggFile);
return wave; return wave;
} }

View file

@ -3,20 +3,20 @@
* raylib.core * raylib.core
* *
* Basic functions to manage Windows, OpenGL context and Input * Basic functions to manage Windows, OpenGL context and Input
* *
* Uses external lib: * Uses external lib:
* GLFW3 - Window, context and Input management (static lib version) * GLFW3 - Window, context and Input management (static lib version)
* *
* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) * Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
* *
* Permission is granted to anyone to use this software for any purpose, including commercial * Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions: * applications, and to alter it and redistribute it freely, subject to the following restrictions:
* *
* 1. The origin of this software must not be misrepresented; you must not claim that you * 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment * wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required. * in the product documentation would be appreciated but is not required.
* *
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
@ -121,11 +121,11 @@ void InitWindow(int width, int height, const char *title)
void InitWindowEx(int width, int height, const char* title, bool resizable, const char *cursorImage) void InitWindowEx(int width, int height, const char* title, bool resizable, const char *cursorImage)
{ {
glfwSetErrorCallback(ErrorCallback); glfwSetErrorCallback(ErrorCallback);
if (!glfwInit()) TraceLog(ERROR, "Failed to initialize GLFW"); if (!glfwInit()) TraceLog(ERROR, "Failed to initialize GLFW");
//glfwDefaultWindowHints() // Set default windows hints //glfwDefaultWindowHints() // Set default windows hints
if (!resizable) glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable if (!resizable) glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable
#ifdef USE_OPENGL_33 #ifdef USE_OPENGL_33
@ -137,20 +137,20 @@ void InitWindowEx(int width, int height, const char* title, bool resizable, cons
#endif #endif
window = glfwCreateWindow(width, height, title, NULL, NULL); window = glfwCreateWindow(width, height, title, NULL, NULL);
windowWidth = width; windowWidth = width;
windowHeight = height; windowHeight = height;
windowTitle = title; windowTitle = title;
if (!window) if (!window)
{ {
glfwTerminate(); glfwTerminate();
TraceLog(ERROR, "Failed to initialize Window"); TraceLog(ERROR, "Failed to initialize Window");
} }
glfwSetWindowSizeCallback(window, WindowSizeCallback); glfwSetWindowSizeCallback(window, WindowSizeCallback);
glfwSetCursorEnterCallback(window, CursorEnterCallback); glfwSetCursorEnterCallback(window, CursorEnterCallback);
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, KeyCallback); glfwSetKeyCallback(window, KeyCallback);
glfwSetScrollCallback(window, ScrollCallback); glfwSetScrollCallback(window, ScrollCallback);
@ -158,29 +158,29 @@ void InitWindowEx(int width, int height, const char* title, bool resizable, cons
// If not set, swap interval uses GPU v-sync configuration // If not set, swap interval uses GPU v-sync configuration
// Framerate can be setup using SetTargetFPS() // Framerate can be setup using SetTargetFPS()
//------------------------------------------------------ //------------------------------------------------------
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
rlglInit(); // Init rlgl rlglInit(); // Init rlgl
#endif #endif
//------------------------------------------------------ //------------------------------------------------------
int fbWidth, fbHeight; int fbWidth, fbHeight;
glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window
//------------------------------------------------------ //------------------------------------------------------
rlglInitGraphicsDevice(fbWidth, fbHeight); rlglInitGraphicsDevice(fbWidth, fbHeight);
//------------------------------------------------------ //------------------------------------------------------
previousTime = glfwGetTime(); previousTime = glfwGetTime();
LoadDefaultFont(); // NOTE: External function (defined in module: text) LoadDefaultFont(); // NOTE: External function (defined in module: text)
if (cursorImage != NULL) SetCustomCursor(cursorImage); if (cursorImage != NULL) SetCustomCursor(cursorImage);
srand(time(NULL)); // Initialize random seed srand(time(NULL)); // Initialize random seed
ClearBackground(RAYWHITE); // Default background color for raylib games :P ClearBackground(RAYWHITE); // Default background color for raylib games :P
// raylib logo appearing animation // raylib logo appearing animation
if (showLogo) if (showLogo)
{ {
@ -193,7 +193,7 @@ void InitWindowEx(int width, int height, const char* title, bool resizable, cons
void CloseWindow() void CloseWindow()
{ {
UnloadDefaultFont(); UnloadDefaultFont();
//------------------------------------------------------ //------------------------------------------------------
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
rlglClose(); // De-init rlgl rlglClose(); // De-init rlgl
@ -208,9 +208,9 @@ void CloseWindow()
void SetCustomCursor(const char *cursorImage) void SetCustomCursor(const char *cursorImage)
{ {
if (customCursor) UnloadTexture(cursor); if (customCursor) UnloadTexture(cursor);
cursor = LoadTexture(cursorImage); cursor = LoadTexture(cursorImage);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
customCursor = true; customCursor = true;
} }
@ -231,14 +231,14 @@ bool WindowShouldClose()
// Fullscreen toggle (by default F11) // Fullscreen toggle (by default F11)
void ToggleFullscreen() void ToggleFullscreen()
{ {
if (glfwGetKey(window, GLFW_KEY_F11)) if (glfwGetKey(window, GLFW_KEY_F11))
{ {
fullscreen = !fullscreen; // Toggle fullscreen flag fullscreen = !fullscreen; // Toggle fullscreen flag
UnloadDefaultFont(); UnloadDefaultFont();
glfwDestroyWindow(window); // Destroy the current window (we will recreate it!) glfwDestroyWindow(window); // Destroy the current window (we will recreate it!)
// TODO: WARNING! All loaded resources are lost, we loose Context! // TODO: WARNING! All loaded resources are lost, we loose Context!
// NOTE: Window aspect ratio is always windowWidth / windowHeight // NOTE: Window aspect ratio is always windowWidth / windowHeight
@ -248,7 +248,7 @@ void ToggleFullscreen()
//const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor()); //const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
//windowWidth = mode->width; //windowWidth = mode->width;
//windowHeight = mode->height; //windowHeight = mode->height;
window = glfwCreateWindow(windowWidth, windowHeight, windowTitle, glfwGetPrimaryMonitor(), NULL); // Fullscreen mode window = glfwCreateWindow(windowWidth, windowHeight, windowTitle, glfwGetPrimaryMonitor(), NULL); // Fullscreen mode
} }
else window = glfwCreateWindow(windowWidth, windowHeight, windowTitle, NULL, NULL); else window = glfwCreateWindow(windowWidth, windowHeight, windowTitle, NULL, NULL);
@ -258,7 +258,7 @@ void ToggleFullscreen()
glfwTerminate(); glfwTerminate();
TraceLog(ERROR, "Failed to initialize Window when switching fullscreen mode"); TraceLog(ERROR, "Failed to initialize Window when switching fullscreen mode");
} }
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, KeyCallback); glfwSetKeyCallback(window, KeyCallback);
@ -266,7 +266,7 @@ void ToggleFullscreen()
glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window
rlglInitGraphicsDevice(fbWidth, fbHeight); rlglInitGraphicsDevice(fbWidth, fbHeight);
LoadDefaultFont(); LoadDefaultFont();
} }
} }
@ -275,9 +275,9 @@ void ToggleFullscreen()
void ClearBackground(Color color) void ClearBackground(Color color)
{ {
if ((color.r != background.r) || (color.g != background.g) || (color.b != background.b) || (color.a != background.a)) if ((color.r != background.r) || (color.g != background.g) || (color.b != background.b) || (color.a != background.a))
{ {
rlClearColor(color.r, color.g, color.b, color.a); rlClearColor(color.r, color.g, color.b, color.a);
background = color; background = color;
} }
} }
@ -290,7 +290,7 @@ void BeginDrawing()
previousTime = currentTime; previousTime = currentTime;
rlClearScreenBuffers(); rlClearScreenBuffers();
rlLoadIdentity(); // Reset current matrix (MODELVIEW) rlLoadIdentity(); // Reset current matrix (MODELVIEW)
//#ifdef USE_OPENGL_11 //#ifdef USE_OPENGL_11
@ -309,18 +309,18 @@ void EndDrawing()
rlglDraw(); // Draw Buffers rlglDraw(); // Draw Buffers
#endif #endif
//------------------------------------------------------ //------------------------------------------------------
glfwSwapBuffers(window); // Swap back and front buffers glfwSwapBuffers(window); // Swap back and front buffers
glfwPollEvents(); // Register keyboard/mouse events glfwPollEvents(); // Register keyboard/mouse events
UpdateMusicStream(); // NOTE: Function checks if music is enabled UpdateMusicStream(); // NOTE: Function checks if music is enabled
currentTime = glfwGetTime(); currentTime = glfwGetTime();
drawTime = currentTime - previousTime; drawTime = currentTime - previousTime;
previousTime = currentTime; previousTime = currentTime;
frameTime = updateTime + drawTime; frameTime = updateTime + drawTime;
double extraTime = 0; double extraTime = 0;
while (frameTime < targetTime) while (frameTime < targetTime)
@ -343,20 +343,20 @@ void Begin3dMode(Camera camera)
//------------------------------------------------------ //------------------------------------------------------
rlMatrixMode(RL_PROJECTION); // Switch to projection matrix rlMatrixMode(RL_PROJECTION); // Switch to projection matrix
rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection
rlLoadIdentity(); // Reset current matrix (PROJECTION) rlLoadIdentity(); // Reset current matrix (PROJECTION)
// Setup perspective projection // Setup perspective projection
float aspect = (GLfloat)windowWidth/(GLfloat)windowHeight; float aspect = (GLfloat)windowWidth/(GLfloat)windowHeight;
double top = 0.1f*tan(45.0f*PI / 360.0); double top = 0.1f*tan(45.0f*PI / 360.0);
double right = top*aspect; double right = top*aspect;
rlFrustum(-right, right, -top, top, 0.1f, 100.0f); rlFrustum(-right, right, -top, top, 0.1f, 100.0f);
rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix
rlLoadIdentity(); // Reset current matrix (MODELVIEW) rlLoadIdentity(); // Reset current matrix (MODELVIEW)
// Setup Camera view // Setup Camera view
Matrix matLookAt = MatrixLookAt(camera.position, camera.target, camera.up); Matrix matLookAt = MatrixLookAt(camera.position, camera.target, camera.up);
rlMultMatrixf(GetMatrixVector(matLookAt)); // Multiply MODELVIEW matrix by view matrix (camera) rlMultMatrixf(GetMatrixVector(matLookAt)); // Multiply MODELVIEW matrix by view matrix (camera)
@ -373,10 +373,10 @@ void End3dMode()
rlMatrixMode(RL_PROJECTION); // Switch to projection matrix rlMatrixMode(RL_PROJECTION); // Switch to projection matrix
rlPopMatrix(); // Restore previous matrix (PROJECTION) from matrix stack rlPopMatrix(); // Restore previous matrix (PROJECTION) from matrix stack
rlMatrixMode(RL_MODELVIEW); // Get back to modelview matrix rlMatrixMode(RL_MODELVIEW); // Get back to modelview matrix
rlLoadIdentity(); // Reset current matrix (MODELVIEW) rlLoadIdentity(); // Reset current matrix (MODELVIEW)
//rlTranslatef(0.375, 0.375, 0); // HACK to ensure pixel-perfect drawing on OpenGL (after exiting 3D mode) //rlTranslatef(0.375, 0.375, 0); // HACK to ensure pixel-perfect drawing on OpenGL (after exiting 3D mode)
} }
@ -384,7 +384,7 @@ void End3dMode()
void SetTargetFPS(int fps) void SetTargetFPS(int fps)
{ {
targetTime = 1 / (float)fps; targetTime = 1 / (float)fps;
TraceLog(INFO, "Target time per frame: %02.03f milliseconds", (float)targetTime*1000); TraceLog(INFO, "Target time per frame: %02.03f milliseconds", (float)targetTime*1000);
} }
@ -401,7 +401,7 @@ float GetFrameTime()
// so we round it before before passing around to be used // so we round it before before passing around to be used
// NOTE: There are still problems with high framerates (>500fps) // NOTE: There are still problems with high framerates (>500fps)
double roundedFrameTime = round(frameTime*10000) / 10000; double roundedFrameTime = round(frameTime*10000) / 10000;
return (float)roundedFrameTime; // Time in seconds to run a frame return (float)roundedFrameTime; // Time in seconds to run a frame
} }
@ -414,7 +414,7 @@ Color GetColor(int hexValue)
color.g = (unsigned char)(hexValue >> 16) & 0xFF; color.g = (unsigned char)(hexValue >> 16) & 0xFF;
color.b = (unsigned char)(hexValue >> 8) & 0xFF; color.b = (unsigned char)(hexValue >> 8) & 0xFF;
color.a = (unsigned char)hexValue & 0xFF; color.a = (unsigned char)hexValue & 0xFF;
return color; return color;
} }
@ -458,7 +458,7 @@ void ShowLogo()
// Detect if a key has been pressed once // Detect if a key has been pressed once
bool IsKeyPressed(int key) bool IsKeyPressed(int key)
{ {
bool pressed = false; bool pressed = false;
currentKeyState[key] = IsKeyDown(key); currentKeyState[key] = IsKeyDown(key);
@ -469,7 +469,7 @@ bool IsKeyPressed(int key)
previousKeyState[key] = currentKeyState[key]; previousKeyState[key] = currentKeyState[key];
} }
else pressed = false; else pressed = false;
return pressed; return pressed;
} }
@ -482,9 +482,9 @@ bool IsKeyDown(int key)
// Detect if a key has been released once // Detect if a key has been released once
bool IsKeyReleased(int key) bool IsKeyReleased(int key)
{ {
bool released = false; bool released = false;
currentKeyState[key] = IsKeyUp(key); currentKeyState[key] = IsKeyUp(key);
if (currentKeyState[key] != previousKeyState[key]) if (currentKeyState[key] != previousKeyState[key])
@ -493,7 +493,7 @@ bool IsKeyReleased(int key)
previousKeyState[key] = currentKeyState[key]; previousKeyState[key] = currentKeyState[key];
} }
else released = false; else released = false;
return released; return released;
} }
@ -517,7 +517,7 @@ bool IsMouseButtonPressed(int button)
previousMouseState[button] = currentMouseState[button]; previousMouseState[button] = currentMouseState[button];
} }
else pressed = false; else pressed = false;
return pressed; return pressed;
} }
@ -541,7 +541,7 @@ bool IsMouseButtonReleased(int button)
previousMouseState[button] = currentMouseState[button]; previousMouseState[button] = currentMouseState[button];
} }
else released = false; else released = false;
return released; return released;
} }
@ -557,7 +557,7 @@ int GetMouseX()
{ {
double mouseX; double mouseX;
double mouseY; double mouseY;
glfwGetCursorPos(window, &mouseX, &mouseY); glfwGetCursorPos(window, &mouseX, &mouseY);
return (int)mouseX; return (int)mouseX;
@ -568,7 +568,7 @@ int GetMouseY()
{ {
double mouseX; double mouseX;
double mouseY; double mouseY;
glfwGetCursorPos(window, &mouseX, &mouseY); glfwGetCursorPos(window, &mouseX, &mouseY);
return (int)mouseY; return (int)mouseY;
@ -579,9 +579,9 @@ Vector2 GetMousePosition()
{ {
double mouseX; double mouseX;
double mouseY; double mouseY;
glfwGetCursorPos(window, &mouseX, &mouseY); glfwGetCursorPos(window, &mouseX, &mouseY);
Vector2 position = { (float)mouseX, (float)mouseY }; Vector2 position = { (float)mouseX, (float)mouseY };
return position; return position;
@ -593,7 +593,7 @@ int GetMouseWheelMove()
previousMouseWheelY = currentMouseWheelY; previousMouseWheelY = currentMouseWheelY;
currentMouseWheelY = 0; currentMouseWheelY = 0;
return previousMouseWheelY; return previousMouseWheelY;
} }
@ -601,7 +601,7 @@ int GetMouseWheelMove()
bool IsGamepadAvailable(int gamepad) bool IsGamepadAvailable(int gamepad)
{ {
int result = glfwJoystickPresent(gamepad); int result = glfwJoystickPresent(gamepad);
if (result == 1) return true; if (result == 1) return true;
else return false; else return false;
} }
@ -610,20 +610,20 @@ bool IsGamepadAvailable(int gamepad)
Vector2 GetGamepadMovement(int gamepad) Vector2 GetGamepadMovement(int gamepad)
{ {
Vector2 vec = { 0, 0 }; Vector2 vec = { 0, 0 };
const float *axes; const float *axes;
int axisCount; int axisCount;
axes = glfwGetJoystickAxes(gamepad, &axisCount); axes = glfwGetJoystickAxes(gamepad, &axisCount);
if (axisCount >= 2) if (axisCount >= 2)
{ {
vec.x = axes[0]; // Left joystick X vec.x = axes[0]; // Left joystick X
vec.y = axes[1]; // Left joystick Y vec.y = axes[1]; // Left joystick Y
//vec.x = axes[2]; // Right joystick X //vec.x = axes[2]; // Right joystick X
//vec.x = axes[3]; // Right joystick Y //vec.x = axes[3]; // Right joystick Y
} }
return vec; return vec;
} }
@ -641,7 +641,7 @@ bool IsGamepadButtonPressed(int gamepad, int button)
previousGamepadState[button] = currentGamepadState[button]; previousGamepadState[button] = currentGamepadState[button];
} }
else pressed = false; else pressed = false;
return pressed; return pressed;
} }
@ -649,9 +649,9 @@ bool IsGamepadButtonDown(int gamepad, int button)
{ {
const unsigned char* buttons; const unsigned char* buttons;
int buttonsCount; int buttonsCount;
buttons = glfwGetJoystickButtons(gamepad, &buttonsCount); buttons = glfwGetJoystickButtons(gamepad, &buttonsCount);
if ((buttons != NULL) && (buttons[button] == GLFW_PRESS)) if ((buttons != NULL) && (buttons[button] == GLFW_PRESS))
{ {
return true; return true;
@ -672,7 +672,7 @@ bool IsGamepadButtonReleased(int gamepad, int button)
previousGamepadState[button] = currentGamepadState[button]; previousGamepadState[button] = currentGamepadState[button];
} }
else released = false; else released = false;
return released; return released;
} }
@ -680,9 +680,9 @@ bool IsGamepadButtonUp(int gamepad, int button)
{ {
const unsigned char* buttons; const unsigned char* buttons;
int buttonsCount; int buttonsCount;
buttons = glfwGetJoystickButtons(gamepad, &buttonsCount); buttons = glfwGetJoystickButtons(gamepad, &buttonsCount);
if ((buttons != NULL) && (buttons[button] == GLFW_RELEASE)) if ((buttons != NULL) && (buttons[button] == GLFW_RELEASE))
{ {
return true; return true;
@ -712,7 +712,7 @@ static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, i
if (key == exitKey && action == GLFW_PRESS) if (key == exitKey && action == GLFW_PRESS)
{ {
glfwSetWindowShouldClose(window, GL_TRUE); glfwSetWindowShouldClose(window, GL_TRUE);
// NOTE: Before closing window, while loop must be left! // NOTE: Before closing window, while loop must be left!
} }
else if (key == GLFW_KEY_F11 && action == GLFW_PRESS) else if (key == GLFW_KEY_F11 && action == GLFW_PRESS)
@ -739,11 +739,11 @@ static void WindowSizeCallback(GLFWwindow* window, int width, int height)
// If window is resized, graphics device is re-initialized (but only ortho mode) // If window is resized, graphics device is re-initialized (but only ortho mode)
rlglInitGraphicsDevice(fbWidth, fbHeight); rlglInitGraphicsDevice(fbWidth, fbHeight);
// Window size must be updated to be used on 3D mode to get new aspect ratio (Begin3dMode()) // Window size must be updated to be used on 3D mode to get new aspect ratio (Begin3dMode())
windowWidth = fbWidth; windowWidth = fbWidth;
windowHeight = fbHeight; windowHeight = fbHeight;
// Background must be also re-cleared // Background must be also re-cleared
rlClearColor(background.r, background.g, background.b, background.a); rlClearColor(background.r, background.g, background.b, background.a);
} }
@ -767,7 +767,7 @@ static void TakeScreenshot()
free(imgData); free(imgData);
shotNum++; shotNum++;
TraceLog(INFO, "[%s] Screenshot taken!", buffer); TraceLog(INFO, "[%s] Screenshot taken!", buffer);
} }
@ -775,20 +775,20 @@ static void LogoAnimation()
{ {
int logoPositionX = windowWidth/2 - 128; int logoPositionX = windowWidth/2 - 128;
int logoPositionY = windowHeight/2 - 128; int logoPositionY = windowHeight/2 - 128;
int framesCounter = 0; int framesCounter = 0;
int lettersCount = 0; int lettersCount = 0;
int topSideRecWidth = 16; int topSideRecWidth = 16;
int leftSideRecHeight = 16; int leftSideRecHeight = 16;
int bottomSideRecWidth = 16; int bottomSideRecWidth = 16;
int rightSideRecHeight = 16; int rightSideRecHeight = 16;
char raylib[8] = " "; // raylib text array, max 8 letters char raylib[8] = " "; // raylib text array, max 8 letters
int state = 0; // Tracking animation states (State Machine) int state = 0; // Tracking animation states (State Machine)
float alpha = 1.0; // Useful for fading float alpha = 1.0; // Useful for fading
while (!WindowShouldClose() && (state != 4)) // Detect window close button or ESC key while (!WindowShouldClose() && (state != 4)) // Detect window close button or ESC key
{ {
// Update // Update
@ -796,9 +796,9 @@ static void LogoAnimation()
if (state == 0) // State 0: Small box blinking if (state == 0) // State 0: Small box blinking
{ {
framesCounter++; framesCounter++;
if (framesCounter == 84) if (framesCounter == 84)
{ {
state = 1; state = 1;
framesCounter = 0; // Reset counter... will be used later... framesCounter = 0; // Reset counter... will be used later...
} }
@ -807,26 +807,26 @@ static void LogoAnimation()
{ {
topSideRecWidth += 4; topSideRecWidth += 4;
leftSideRecHeight += 4; leftSideRecHeight += 4;
if (topSideRecWidth == 256) state = 2; if (topSideRecWidth == 256) state = 2;
} }
else if (state == 2) // State 2: Bottom and right bars growing else if (state == 2) // State 2: Bottom and right bars growing
{ {
bottomSideRecWidth += 4; bottomSideRecWidth += 4;
rightSideRecHeight += 4; rightSideRecHeight += 4;
if (bottomSideRecWidth == 256) state = 3; if (bottomSideRecWidth == 256) state = 3;
} }
else if (state == 3) // State 3: Letters appearing (one by one) else if (state == 3) // State 3: Letters appearing (one by one)
{ {
framesCounter++; framesCounter++;
if (framesCounter/12) // Every 12 frames, one more letter! if (framesCounter/12) // Every 12 frames, one more letter!
{ {
lettersCount++; lettersCount++;
framesCounter = 0; framesCounter = 0;
} }
switch (lettersCount) switch (lettersCount)
{ {
case 1: raylib[0] = 'r'; break; case 1: raylib[0] = 'r'; break;
@ -837,11 +837,11 @@ static void LogoAnimation()
case 6: raylib[5] = 'b'; break; case 6: raylib[5] = 'b'; break;
default: break; default: break;
} }
if (lettersCount >= 10) // When all letters have appeared, just fade out everything if (lettersCount >= 10) // When all letters have appeared, just fade out everything
{ {
alpha -= 0.02; alpha -= 0.02;
if (alpha <= 0) if (alpha <= 0)
{ {
alpha = 0; alpha = 0;
@ -850,11 +850,11 @@ static void LogoAnimation()
} }
} }
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Draw // Draw
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
BeginDrawing(); BeginDrawing();
if (state == 0) if (state == 0)
{ {
if ((framesCounter/12)%2) DrawRectangle(logoPositionX, logoPositionY, 16, 16, BLACK); if ((framesCounter/12)%2) DrawRectangle(logoPositionX, logoPositionY, 16, 16, BLACK);
@ -868,7 +868,7 @@ static void LogoAnimation()
{ {
DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK); DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK);
DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK); DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK);
DrawRectangle(logoPositionX + 240, logoPositionY, 16, rightSideRecHeight, BLACK); DrawRectangle(logoPositionX + 240, logoPositionY, 16, rightSideRecHeight, BLACK);
DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, BLACK); DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, BLACK);
} }
@ -876,15 +876,15 @@ static void LogoAnimation()
{ {
DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, Fade(BLACK, alpha)); DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, Fade(BLACK, alpha));
DrawRectangle(logoPositionX, logoPositionY + 16, 16, leftSideRecHeight - 32, Fade(BLACK, alpha)); DrawRectangle(logoPositionX, logoPositionY + 16, 16, leftSideRecHeight - 32, Fade(BLACK, alpha));
DrawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, Fade(BLACK, alpha)); DrawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, Fade(BLACK, alpha));
DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, Fade(BLACK, alpha)); DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, Fade(BLACK, alpha));
DrawRectangle(windowWidth/2 - 112, windowHeight/2 - 112, 224, 224, Fade(RAYWHITE, alpha)); DrawRectangle(windowWidth/2 - 112, windowHeight/2 - 112, 224, 224, Fade(RAYWHITE, alpha));
DrawText(raylib, windowWidth/2 - 44, windowHeight/2 + 48, 50, Fade(BLACK, alpha)); DrawText(raylib, windowWidth/2 - 44, windowHeight/2 + 48, 50, Fade(BLACK, alpha));
} }
EndDrawing(); EndDrawing();
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
} }

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
/********************************************************************************************* /*********************************************************************************************
* *
* raylib 1.1 (www.raylib.com) * raylib 1.1 (www.raylib.com)
* *
* A simple and easy-to-use library to learn videogames programming * A simple and easy-to-use library to learn videogames programming
* *
* Features: * Features:
@ -14,7 +14,7 @@
* Basic 3d support for Shapes, Models, Heightmaps and Billboards * Basic 3d support for Shapes, Models, Heightmaps and Billboards
* Powerful math module for Vector and Matrix operations [raymath] * Powerful math module for Vector and Matrix operations [raymath]
* Audio loading and playing with streaming support * Audio loading and playing with streaming support
* *
* Used external libs: * Used external libs:
* GLFW3 (www.glfw.org) for window/context management and input * GLFW3 (www.glfw.org) for window/context management and input
* GLEW for OpenGL extensions loading (3.3+ and ES2) * GLEW for OpenGL extensions loading (3.3+ and ES2)
@ -33,19 +33,19 @@
* *
* -- LICENSE (raylib v1.1, April 2014) -- * -- LICENSE (raylib v1.1, April 2014) --
* *
* raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software: * BSD-like license that allows static linking with closed source software:
* *
* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) * Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
* *
* Permission is granted to anyone to use this software for any purpose, including commercial * Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions: * applications, and to alter it and redistribute it freely, subject to the following restrictions:
* *
* 1. The origin of this software must not be misrepresented; you must not claim that you * 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment * wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required. * in the product documentation would be appreciated but is not required.
* *
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
@ -354,7 +354,7 @@ void DrawTextureV(Texture2D texture, Vector2 position, Color tint);
void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters
void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle
void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, // Draw a part of a texture defined by a rectangle with 'pro' parameters void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, // Draw a part of a texture defined by a rectangle with 'pro' parameters
float rotation, Color tint); float rotation, Color tint);
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Font Loading and Text Drawing Functions (Module: text) // Font Loading and Text Drawing Functions (Module: text)
@ -406,7 +406,7 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotation, Vector3 scale,
void DrawModelWires(Model model, Vector3 position, float scale, Color color); // Draw a model wires (with texture if set) void DrawModelWires(Model model, Vector3 position, float scale, Color color); // Draw a model wires (with texture if set)
void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint); // Draw a billboard texture
void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec
//------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------
// Audio Loading and Playing Functions (Module: audio) // Audio Loading and Playing Functions (Module: audio)

View file

@ -5,15 +5,15 @@
* Some useful functions to work with Vector3, Matrix and Quaternions * Some useful functions to work with Vector3, Matrix and Quaternions
* *
* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) * Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
* *
* Permission is granted to anyone to use this software for any purpose, including commercial * Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions: * applications, and to alter it and redistribute it freely, subject to the following restrictions:
* *
* 1. The origin of this software must not be misrepresented; you must not claim that you * 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment * wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required. * in the product documentation would be appreciated but is not required.
* *
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
@ -51,7 +51,7 @@ Vector3 VectorAdd(Vector3 v1, Vector3 v2)
result.x = v1.x + v2.x; result.x = v1.x + v2.x;
result.y = v1.y + v2.y; result.y = v1.y + v2.y;
result.z = v1.z + v2.z; result.z = v1.z + v2.z;
return result; return result;
} }
@ -63,7 +63,7 @@ Vector3 VectorSubtract(Vector3 v1, Vector3 v2)
result.x = v1.x - v2.x; result.x = v1.x - v2.x;
result.y = v1.y - v2.y; result.y = v1.y - v2.y;
result.z = v1.z - v2.z; result.z = v1.z - v2.z;
return result; return result;
} }
@ -75,7 +75,7 @@ Vector3 VectorCrossProduct(Vector3 v1, Vector3 v2)
result.x = v1.y*v2.z - v1.z*v2.y; result.x = v1.y*v2.z - v1.z*v2.y;
result.y = v1.z*v2.x - v1.x*v2.z; result.y = v1.z*v2.x - v1.x*v2.z;
result.z = v1.x*v2.y - v1.y*v2.x; result.z = v1.x*v2.y - v1.y*v2.x;
return result; return result;
} }
@ -83,23 +83,23 @@ Vector3 VectorCrossProduct(Vector3 v1, Vector3 v2)
Vector3 VectorPerpendicular(Vector3 v) Vector3 VectorPerpendicular(Vector3 v)
{ {
Vector3 result; Vector3 result;
float min = fabs(v.x); float min = fabs(v.x);
Vector3 cardinalAxis = {1.0, 0.0, 0.0}; Vector3 cardinalAxis = {1.0, 0.0, 0.0};
if (fabs(v.y) < min) if (fabs(v.y) < min)
{ {
min = fabs(v.y); min = fabs(v.y);
cardinalAxis = (Vector3){0.0, 1.0, 0.0}; cardinalAxis = (Vector3){0.0, 1.0, 0.0};
} }
if(fabs(v.z) < min) if(fabs(v.z) < min)
{ {
cardinalAxis = (Vector3){0.0, 0.0, 1.0}; cardinalAxis = (Vector3){0.0, 0.0, 1.0};
} }
result = VectorCrossProduct(v, cardinalAxis); result = VectorCrossProduct(v, cardinalAxis);
return result; return result;
} }
@ -107,9 +107,9 @@ Vector3 VectorPerpendicular(Vector3 v)
float VectorDotProduct(Vector3 v1, Vector3 v2) float VectorDotProduct(Vector3 v1, Vector3 v2)
{ {
float result; float result;
result = v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; result = v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
return result; return result;
} }
@ -117,9 +117,9 @@ float VectorDotProduct(Vector3 v1, Vector3 v2)
float VectorLength(const Vector3 v) float VectorLength(const Vector3 v)
{ {
float length; float length;
length = sqrt(v.x*v.x + v.y*v.y + v.z*v.z); length = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
return length; return length;
} }
@ -145,11 +145,11 @@ void VectorNormalize(Vector3 *v)
float length, ilength; float length, ilength;
length = VectorLength(*v); length = VectorLength(*v);
if (length == 0) length = 1; if (length == 0) length = 1;
ilength = 1.0/length; ilength = 1.0/length;
v->x *= ilength; v->x *= ilength;
v->y *= ilength; v->y *= ilength;
v->z *= ilength; v->z *= ilength;
@ -159,13 +159,13 @@ void VectorNormalize(Vector3 *v)
float VectorDistance(Vector3 v1, Vector3 v2) float VectorDistance(Vector3 v1, Vector3 v2)
{ {
float result; float result;
float dx = v2.x - v1.x; float dx = v2.x - v1.x;
float dy = v2.y - v1.y; float dy = v2.y - v1.y;
float dz = v2.z - v1.z; float dz = v2.z - v1.z;
result = sqrt(dx*dx + dy*dy + dz*dz); result = sqrt(dx*dx + dy*dy + dz*dz);
return result; return result;
} }
@ -173,7 +173,7 @@ float VectorDistance(Vector3 v1, Vector3 v2)
Vector3 VectorLerp(Vector3 v1, Vector3 v2, float amount) Vector3 VectorLerp(Vector3 v1, Vector3 v2, float amount)
{ {
Vector3 result; Vector3 result;
result.x = v1.x + amount * (v2.x - v1.x); result.x = v1.x + amount * (v2.x - v1.x);
result.y = v1.y + amount * (v2.y - v1.y); result.y = v1.y + amount * (v2.y - v1.y);
result.z = v1.z + amount * (v2.z - v1.z); result.z = v1.z + amount * (v2.z - v1.z);
@ -187,11 +187,11 @@ Vector3 VectorReflect(Vector3 vector, Vector3 normal)
// I is the original vector // I is the original vector
// N is the normal of the incident plane // N is the normal of the incident plane
// R = I - (2 * N * ( DotProduct[ I,N] )) // R = I - (2 * N * ( DotProduct[ I,N] ))
Vector3 result; Vector3 result;
float dotProduct = VectorDotProduct(vector, normal); float dotProduct = VectorDotProduct(vector, normal);
result.x = vector.x - (2.0 * normal.x) * dotProduct; result.x = vector.x - (2.0 * normal.x) * dotProduct;
result.y = vector.y - (2.0 * normal.y) * dotProduct; result.y = vector.y - (2.0 * normal.y) * dotProduct;
result.z = vector.z - (2.0 * normal.z) * dotProduct; result.z = vector.z - (2.0 * normal.z) * dotProduct;
@ -203,11 +203,11 @@ Vector3 VectorReflect(Vector3 vector, Vector3 normal)
void VectorTransform(Vector3 *v, Matrix mat) void VectorTransform(Vector3 *v, Matrix mat)
{ {
float x = v->x; float x = v->x;
float y = v->y; float y = v->y;
float z = v->z; float z = v->z;
//MatrixTranspose(&mat); //MatrixTranspose(&mat);
v->x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12; v->x = mat.m0*x + mat.m4*y + mat.m8*z + mat.m12;
v->y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13; v->y = mat.m1*x + mat.m5*y + mat.m9*z + mat.m13;
v->z = mat.m2*x + mat.m6*y + mat.m10*z + mat.m14; v->z = mat.m2*x + mat.m6*y + mat.m10*z + mat.m14;
@ -217,7 +217,7 @@ void VectorTransform(Vector3 *v, Matrix mat)
Vector3 VectorZero() Vector3 VectorZero()
{ {
Vector3 zero = { 0.0, 0.0, 0.0 }; Vector3 zero = { 0.0, 0.0, 0.0 };
return zero; return zero;
} }
@ -229,7 +229,7 @@ Vector3 VectorZero()
float *GetMatrixVector(Matrix mat) float *GetMatrixVector(Matrix mat)
{ {
static float vector[16]; static float vector[16];
vector[0] = mat.m0; vector[0] = mat.m0;
vector[1] = mat.m4; vector[1] = mat.m4;
vector[2] = mat.m8; vector[2] = mat.m8;
@ -246,7 +246,7 @@ float *GetMatrixVector(Matrix mat)
vector[13] = mat.m7; vector[13] = mat.m7;
vector[14] = mat.m11; vector[14] = mat.m11;
vector[15] = mat.m15; vector[15] = mat.m15;
return vector; return vector;
} }
@ -267,7 +267,7 @@ float MatrixDeterminant(Matrix mat)
a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 + a30*a11*a02*a23 - a10*a31*a02*a23 - a30*a01*a12*a23 + a00*a31*a12*a23 +
a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 + a10*a01*a32*a23 - a00*a11*a32*a23 - a20*a11*a02*a33 + a10*a21*a02*a33 +
a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33; a20*a01*a12*a33 - a00*a21*a12*a33 - a10*a01*a22*a33 + a00*a11*a22*a33;
return result; return result;
} }
@ -298,7 +298,7 @@ void MatrixTranspose(Matrix *mat)
temp.m13 = mat->m7; temp.m13 = mat->m7;
temp.m14 = mat->m11; temp.m14 = mat->m11;
temp.m15 = mat->m15; temp.m15 = mat->m15;
*mat = temp; *mat = temp;
} }
@ -306,13 +306,13 @@ void MatrixTranspose(Matrix *mat)
void MatrixInvert(Matrix *mat) void MatrixInvert(Matrix *mat)
{ {
Matrix temp; Matrix temp;
// Cache the matrix values (speed optimization) // Cache the matrix values (speed optimization)
float a00 = mat->m0, a01 = mat->m1, a02 = mat->m2, a03 = mat->m3; float a00 = mat->m0, a01 = mat->m1, a02 = mat->m2, a03 = mat->m3;
float a10 = mat->m4, a11 = mat->m5, a12 = mat->m6, a13 = mat->m7; float a10 = mat->m4, a11 = mat->m5, a12 = mat->m6, a13 = mat->m7;
float a20 = mat->m8, a21 = mat->m9, a22 = mat->m10, a23 = mat->m11; float a20 = mat->m8, a21 = mat->m9, a22 = mat->m10, a23 = mat->m11;
float a30 = mat->m12, a31 = mat->m13, a32 = mat->m14, a33 = mat->m15; float a30 = mat->m12, a31 = mat->m13, a32 = mat->m14, a33 = mat->m15;
float b00 = a00*a11 - a01*a10; float b00 = a00*a11 - a01*a10;
float b01 = a00*a12 - a02*a10; float b01 = a00*a12 - a02*a10;
float b02 = a00*a13 - a03*a10; float b02 = a00*a13 - a03*a10;
@ -325,12 +325,12 @@ void MatrixInvert(Matrix *mat)
float b09 = a21*a32 - a22*a31; float b09 = a21*a32 - a22*a31;
float b10 = a21*a33 - a23*a31; float b10 = a21*a33 - a23*a31;
float b11 = a22*a33 - a23*a32; float b11 = a22*a33 - a23*a32;
// Calculate the invert determinant (inlined to avoid double-caching) // Calculate the invert determinant (inlined to avoid double-caching)
float invDet = 1/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06); float invDet = 1/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
printf("%f\n", invDet); printf("%f\n", invDet);
temp.m0 = (a11*b11 - a12*b10 + a13*b09)*invDet; temp.m0 = (a11*b11 - a12*b10 + a13*b09)*invDet;
temp.m1 = (-a01*b11 + a02*b10 - a03*b09)*invDet; temp.m1 = (-a01*b11 + a02*b10 - a03*b09)*invDet;
temp.m2 = (a31*b05 - a32*b04 + a33*b03)*invDet; temp.m2 = (a31*b05 - a32*b04 + a33*b03)*invDet;
@ -347,9 +347,9 @@ void MatrixInvert(Matrix *mat)
temp.m13 = (a00*b09 - a01*b07 + a02*b06)*invDet; temp.m13 = (a00*b09 - a01*b07 + a02*b06)*invDet;
temp.m14 = (-a30*b03 + a31*b01 - a32*b00)*invDet; temp.m14 = (-a30*b03 + a31*b01 - a32*b00)*invDet;
temp.m15 = (a20*b03 - a21*b01 + a22*b00)*invDet; temp.m15 = (a20*b03 - a21*b01 + a22*b00)*invDet;
PrintMatrix(temp); PrintMatrix(temp);
*mat = temp; *mat = temp;
} }
@ -357,7 +357,7 @@ void MatrixInvert(Matrix *mat)
void MatrixNormalize(Matrix *mat) void MatrixNormalize(Matrix *mat)
{ {
float det = MatrixDeterminant(*mat); float det = MatrixDeterminant(*mat);
mat->m0 /= det; mat->m0 /= det;
mat->m1 /= det; mat->m1 /= det;
mat->m2 /= det; mat->m2 /= det;
@ -388,7 +388,7 @@ Matrix MatrixIdentity()
Matrix MatrixAdd(Matrix left, Matrix right) Matrix MatrixAdd(Matrix left, Matrix right)
{ {
Matrix result = MatrixIdentity(); Matrix result = MatrixIdentity();
result.m0 = left.m0 + right.m0; result.m0 = left.m0 + right.m0;
result.m1 = left.m1 + right.m1; result.m1 = left.m1 + right.m1;
result.m2 = left.m2 + right.m2; result.m2 = left.m2 + right.m2;
@ -413,7 +413,7 @@ Matrix MatrixAdd(Matrix left, Matrix right)
Matrix MatrixSubstract(Matrix left, Matrix right) Matrix MatrixSubstract(Matrix left, Matrix right)
{ {
Matrix result = MatrixIdentity(); Matrix result = MatrixIdentity();
result.m0 = left.m0 - right.m0; result.m0 = left.m0 - right.m0;
result.m1 = left.m1 - right.m1; result.m1 = left.m1 - right.m1;
result.m2 = left.m2 - right.m2; result.m2 = left.m2 - right.m2;
@ -444,36 +444,36 @@ Matrix MatrixTranslate(float x, float y, float z)
0, 1, 0, 0 0, 1, 0, 0
0, 0, 1, 0 0, 0, 1, 0
x, y, z, 1 x, y, z, 1
Is the correct Translation Matrix. Why? Opengl Uses column-major matrix ordering. Is the correct Translation Matrix. Why? Opengl Uses column-major matrix ordering.
Which is the Transpose of the Matrix you initially presented, which is in row-major ordering. Which is the Transpose of the Matrix you initially presented, which is in row-major ordering.
Row major is used in most math text-books and also DirectX, so it is a common Row major is used in most math text-books and also DirectX, so it is a common
point of confusion for those new to OpenGL. point of confusion for those new to OpenGL.
* matrix notation used in opengl documentation does not describe in-memory layout for OpenGL matrices * matrix notation used in opengl documentation does not describe in-memory layout for OpenGL matrices
Translation matrix should be laid out in memory like this: Translation matrix should be laid out in memory like this:
{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, trabsX, transY, transZ, 1 } { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, trabsX, transY, transZ, 1 }
9.005 Are OpenGL matrices column-major or row-major? 9.005 Are OpenGL matrices column-major or row-major?
For programming purposes, OpenGL matrices are 16-value arrays with base vectors laid out For programming purposes, OpenGL matrices are 16-value arrays with base vectors laid out
contiguously in memory. The translation components occupy the 13th, 14th, and 15th elements contiguously in memory. The translation components occupy the 13th, 14th, and 15th elements
of the 16-element matrix, where indices are numbered from 1 to 16 as described in section of the 16-element matrix, where indices are numbered from 1 to 16 as described in section
2.11.2 of the OpenGL 2.1 Specification. 2.11.2 of the OpenGL 2.1 Specification.
Column-major versus row-major is purely a notational convention. Note that post-multiplying Column-major versus row-major is purely a notational convention. Note that post-multiplying
with column-major matrices produces the same result as pre-multiplying with row-major matrices. with column-major matrices produces the same result as pre-multiplying with row-major matrices.
The OpenGL Specification and the OpenGL Reference Manual both use column-major notation. The OpenGL Specification and the OpenGL Reference Manual both use column-major notation.
You can use any notation, as long as it's clearly stated. You can use any notation, as long as it's clearly stated.
Sadly, the use of column-major format in the spec and blue book has resulted in endless confusion Sadly, the use of column-major format in the spec and blue book has resulted in endless confusion
in the OpenGL programming community. Column-major notation suggests that matrices in the OpenGL programming community. Column-major notation suggests that matrices
are not laid out in memory as a programmer would expect. are not laid out in memory as a programmer would expect.
*/ */
Matrix result = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 }; Matrix result = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1 };
return result; return result;
} }
@ -482,50 +482,50 @@ Matrix MatrixTranslate(float x, float y, float z)
Matrix MatrixRotate(float angleX, float angleY, float angleZ) Matrix MatrixRotate(float angleX, float angleY, float angleZ)
{ {
Matrix result; Matrix result;
Matrix rotX = MatrixRotateX(angleX); Matrix rotX = MatrixRotateX(angleX);
Matrix rotY = MatrixRotateY(angleY); Matrix rotY = MatrixRotateY(angleY);
Matrix rotZ = MatrixRotateZ(angleZ); Matrix rotZ = MatrixRotateZ(angleZ);
result = MatrixMultiply(MatrixMultiply(rotX, rotY), rotZ); result = MatrixMultiply(MatrixMultiply(rotX, rotY), rotZ);
return result; return result;
} }
// Create rotation matrix from axis and angle // Create rotation matrix from axis and angle
// TODO: Test this function // TODO: Test this function
Matrix MatrixFromAxisAngle(Vector3 axis, float angle) Matrix MatrixFromAxisAngle(Vector3 axis, float angle)
{ {
Matrix result; Matrix result;
Matrix mat = MatrixIdentity(); Matrix mat = MatrixIdentity();
float x = axis.x, y = axis.y, z = axis.z; float x = axis.x, y = axis.y, z = axis.z;
float length = sqrt(x*x + y*y + z*z); float length = sqrt(x*x + y*y + z*z);
if ((length != 1) && (length != 0)) if ((length != 1) && (length != 0))
{ {
length = 1 / length; length = 1 / length;
x *= length; x *= length;
y *= length; y *= length;
z *= length; z *= length;
} }
float s = sin(angle); float s = sin(angle);
float c = cos(angle); float c = cos(angle);
float t = 1-c; float t = 1-c;
// Cache some matrix values (speed optimization) // Cache some matrix values (speed optimization)
float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3; float a00 = mat.m0, a01 = mat.m1, a02 = mat.m2, a03 = mat.m3;
float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7; float a10 = mat.m4, a11 = mat.m5, a12 = mat.m6, a13 = mat.m7;
float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11; float a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;
// Construct the elements of the rotation matrix // Construct the elements of the rotation matrix
float b00 = x*x*t + c, b01 = y*x*t + z*s, b02 = z*x*t - y*s; float b00 = x*x*t + c, b01 = y*x*t + z*s, b02 = z*x*t - y*s;
float b10 = x*y*t - z*s, b11 = y*y*t + c, b12 = z*y*t + x*s; float b10 = x*y*t - z*s, b11 = y*y*t + c, b12 = z*y*t + x*s;
float b20 = x*z*t + y*s, b21 = y*z*t - x*s, b22 = z*z*t + c; float b20 = x*z*t + y*s, b21 = y*z*t - x*s, b22 = z*z*t + c;
// Perform rotation-specific matrix multiplication // Perform rotation-specific matrix multiplication
result.m0 = a00*b00 + a10*b01 + a20*b02; result.m0 = a00*b00 + a10*b01 + a20*b02;
result.m1 = a01*b00 + a11*b01 + a21*b02; result.m1 = a01*b00 + a11*b01 + a21*b02;
@ -543,7 +543,7 @@ Matrix MatrixFromAxisAngle(Vector3 axis, float angle)
result.m13 = mat.m13; result.m13 = mat.m13;
result.m14 = mat.m14; result.m14 = mat.m14;
result.m15 = mat.m15; result.m15 = mat.m15;
return result; return result;
}; };
@ -552,7 +552,7 @@ Matrix MatrixFromAxisAngle(Vector3 axis, float angle)
Matrix MatrixFromAxisAngle2(Vector3 axis, float angle) Matrix MatrixFromAxisAngle2(Vector3 axis, float angle)
{ {
Matrix result; Matrix result;
VectorNormalize(&axis); VectorNormalize(&axis);
float axisX = axis.x, axisY = axis.y, axisZ = axis.y; float axisX = axis.x, axisY = axis.y, axisZ = axis.y;
@ -589,7 +589,7 @@ Matrix MatrixFromAxisAngle2(Vector3 axis, float angle)
result.m13 = 0; result.m13 = 0;
result.m14 = 0; result.m14 = 0;
result.m15 = 1; result.m15 = 1;
return result; return result;
} }
@ -597,14 +597,14 @@ Matrix MatrixFromAxisAngle2(Vector3 axis, float angle)
Matrix MatrixFromQuaternion(Quaternion q) Matrix MatrixFromQuaternion(Quaternion q)
{ {
Matrix result = MatrixIdentity(); Matrix result = MatrixIdentity();
Vector3 axis; Vector3 axis;
float angle; float angle;
QuaternionToAxisAngle(q, &axis, &angle); QuaternionToAxisAngle(q, &axis, &angle);
result = MatrixFromAxisAngle2(axis, angle); result = MatrixFromAxisAngle2(axis, angle);
return result; return result;
} }
@ -612,10 +612,10 @@ Matrix MatrixFromQuaternion(Quaternion q)
Matrix MatrixRotateX(float angle) Matrix MatrixRotateX(float angle)
{ {
Matrix result = MatrixIdentity(); Matrix result = MatrixIdentity();
float cosres = (float)cos(angle); float cosres = (float)cos(angle);
float sinres = (float)sin(angle); float sinres = (float)sin(angle);
result.m5 = cosres; result.m5 = cosres;
result.m6 = -sinres; result.m6 = -sinres;
result.m9 = sinres; result.m9 = sinres;
@ -628,10 +628,10 @@ Matrix MatrixRotateX(float angle)
Matrix MatrixRotateY(float angle) Matrix MatrixRotateY(float angle)
{ {
Matrix result = MatrixIdentity(); Matrix result = MatrixIdentity();
float cosres = (float)cos(angle); float cosres = (float)cos(angle);
float sinres = (float)sin(angle); float sinres = (float)sin(angle);
result.m0 = cosres; result.m0 = cosres;
result.m2 = sinres; result.m2 = sinres;
result.m8 = -sinres; result.m8 = -sinres;
@ -644,10 +644,10 @@ Matrix MatrixRotateY(float angle)
Matrix MatrixRotateZ(float angle) Matrix MatrixRotateZ(float angle)
{ {
Matrix result = MatrixIdentity(); Matrix result = MatrixIdentity();
float cosres = (float)cos(angle); float cosres = (float)cos(angle);
float sinres = (float)sin(angle); float sinres = (float)sin(angle);
result.m0 = cosres; result.m0 = cosres;
result.m1 = -sinres; result.m1 = -sinres;
result.m4 = sinres; result.m4 = sinres;
@ -669,7 +669,7 @@ Matrix MatrixScale(float x, float y, float z)
Matrix MatrixTransform(Vector3 translation, Vector3 rotation, Vector3 scale) Matrix MatrixTransform(Vector3 translation, Vector3 rotation, Vector3 scale)
{ {
Matrix result = MatrixIdentity(); Matrix result = MatrixIdentity();
Matrix mRotation = MatrixRotate(rotation.x, rotation.y, rotation.z); Matrix mRotation = MatrixRotate(rotation.x, rotation.y, rotation.z);
Matrix mScale = MatrixScale(scale.x, scale.y, scale.z); Matrix mScale = MatrixScale(scale.x, scale.y, scale.z);
Matrix mTranslate = MatrixTranslate(translation.x, translation.y, translation.z); Matrix mTranslate = MatrixTranslate(translation.x, translation.y, translation.z);
@ -690,12 +690,12 @@ Matrix MatrixMultiply(Matrix left, Matrix right)
float a10 = left.m4, a11 = left.m5, a12 = left.m6, a13 = left.m7; float a10 = left.m4, a11 = left.m5, a12 = left.m6, a13 = left.m7;
float a20 = left.m8, a21 = left.m9, a22 = left.m10, a23 = left.m11; float a20 = left.m8, a21 = left.m9, a22 = left.m10, a23 = left.m11;
float a30 = left.m12, a31 = left.m13, a32 = left.m14, a33 = left.m15; float a30 = left.m12, a31 = left.m13, a32 = left.m14, a33 = left.m15;
float b00 = right.m0, b01 = right.m1, b02 = right.m2, b03 = right.m3; float b00 = right.m0, b01 = right.m1, b02 = right.m2, b03 = right.m3;
float b10 = right.m4, b11 = right.m5, b12 = right.m6, b13 = right.m7; float b10 = right.m4, b11 = right.m5, b12 = right.m6, b13 = right.m7;
float b20 = right.m8, b21 = right.m9, b22 = right.m10, b23 = right.m11; float b20 = right.m8, b21 = right.m9, b22 = right.m10, b23 = right.m11;
float b30 = right.m12, b31 = right.m13, b32 = right.m14, b33 = right.m15; float b30 = right.m12, b31 = right.m13, b32 = right.m14, b33 = right.m15;
result.m0 = b00*a00 + b01*a10 + b02*a20 + b03*a30; result.m0 = b00*a00 + b01*a10 + b02*a20 + b03*a30;
result.m1 = b00*a01 + b01*a11 + b02*a21 + b03*a31; result.m1 = b00*a01 + b01*a11 + b02*a21 + b03*a31;
result.m2 = b00*a02 + b01*a12 + b02*a22 + b03*a32; result.m2 = b00*a02 + b01*a12 + b02*a22 + b03*a32;
@ -712,19 +712,19 @@ Matrix MatrixMultiply(Matrix left, Matrix right)
result.m13 = b30*a01 + b31*a11 + b32*a21 + b33*a31; result.m13 = b30*a01 + b31*a11 + b32*a21 + b33*a31;
result.m14 = b30*a02 + b31*a12 + b32*a22 + b33*a32; result.m14 = b30*a02 + b31*a12 + b32*a22 + b33*a32;
result.m15 = b30*a03 + b31*a13 + b32*a23 + b33*a33; result.m15 = b30*a03 + b31*a13 + b32*a23 + b33*a33;
return result; return result;
} }
// Returns perspective projection matrix // Returns perspective projection matrix
Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far) Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far)
{ {
Matrix result; Matrix result;
float rl = (right - left); float rl = (right - left);
float tb = (top - bottom); float tb = (top - bottom);
float fn = (far - near); float fn = (far - near);
result.m0 = (near*2) / rl; result.m0 = (near*2) / rl;
result.m1 = 0; result.m1 = 0;
result.m2 = 0; result.m2 = 0;
@ -741,7 +741,7 @@ Matrix MatrixFrustum(double left, double right, double bottom, double top, doubl
result.m13 = 0; result.m13 = 0;
result.m14 = -(far*near*2) / fn; result.m14 = -(far*near*2) / fn;
result.m15 = 0; result.m15 = 0;
return result; return result;
} }
@ -755,14 +755,14 @@ Matrix MatrixPerspective(double fovy, double aspect, double near, double far)
} }
// Returns orthographic projection matrix // Returns orthographic projection matrix
Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far) Matrix MatrixOrtho(double left, double right, double bottom, double top, double near, double far)
{ {
Matrix result; Matrix result;
float rl = (right - left); float rl = (right - left);
float tb = (top - bottom); float tb = (top - bottom);
float fn = (far - near); float fn = (far - near);
result.m0 = 2 / rl; result.m0 = 2 / rl;
result.m1 = 0; result.m1 = 0;
result.m2 = 0; result.m2 = 0;
@ -779,7 +779,7 @@ Matrix MatrixOrtho(double left, double right, double bottom, double top, double
result.m13 = -(top + bottom) / tb; result.m13 = -(top + bottom) / tb;
result.m14 = -(far + near) / fn; result.m14 = -(far + near) / fn;
result.m15 = 1; result.m15 = 1;
return result; return result;
} }
@ -787,14 +787,14 @@ Matrix MatrixOrtho(double left, double right, double bottom, double top, double
Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up) Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up)
{ {
Matrix result; Matrix result;
Vector3 z = VectorSubtract(eye, target); Vector3 z = VectorSubtract(eye, target);
VectorNormalize(&z); VectorNormalize(&z);
Vector3 x = VectorCrossProduct(up, z); Vector3 x = VectorCrossProduct(up, z);
VectorNormalize(&x); VectorNormalize(&x);
Vector3 y = VectorCrossProduct(z, x); Vector3 y = VectorCrossProduct(z, x);
VectorNormalize(&y); VectorNormalize(&y);
result.m0 = x.x; result.m0 = x.x;
result.m1 = x.y; result.m1 = x.y;
result.m2 = x.z; result.m2 = x.z;
@ -811,7 +811,7 @@ Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up)
result.m13 = 0; result.m13 = 0;
result.m14 = 0; result.m14 = 0;
result.m15 = 1; result.m15 = 1;
return result; return result;
} }
@ -837,16 +837,16 @@ float QuaternionLength(Quaternion quat)
} }
// Normalize provided quaternion // Normalize provided quaternion
void QuaternionNormalize(Quaternion *q) void QuaternionNormalize(Quaternion *q)
{ {
float length, ilength; float length, ilength;
length = QuaternionLength(*q); length = QuaternionLength(*q);
if (length == 0) length = 1; if (length == 0) length = 1;
ilength = 1.0/length; ilength = 1.0/length;
q->x *= ilength; q->x *= ilength;
q->y *= ilength; q->y *= ilength;
q->z *= ilength; q->z *= ilength;
@ -854,28 +854,28 @@ void QuaternionNormalize(Quaternion *q)
} }
// Calculate two quaternion multiplication // Calculate two quaternion multiplication
Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2) Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2)
{ {
Quaternion result; Quaternion result;
float qax = q1.x, qay = q1.y, qaz = q1.z, qaw = q1.w; float qax = q1.x, qay = q1.y, qaz = q1.z, qaw = q1.w;
float qbx = q2.x, qby = q2.y, qbz = q2.z, qbw = q2.w; float qbx = q2.x, qby = q2.y, qbz = q2.z, qbw = q2.w;
result.x = qax*qbw + qaw*qbx + qay*qbz - qaz*qby; result.x = qax*qbw + qaw*qbx + qay*qbz - qaz*qby;
result.y = qay*qbw + qaw*qby + qaz*qbx - qax*qbz; result.y = qay*qbw + qaw*qby + qaz*qbx - qax*qbz;
result.z = qaz*qbw + qaw*qbz + qax*qby - qay*qbx; result.z = qaz*qbw + qaw*qbz + qax*qby - qay*qbx;
result.w = qaw*qbw - qax*qbx - qay*qby - qaz*qbz; result.w = qaw*qbw - qax*qbx - qay*qby - qaz*qbz;
return result; return result;
} }
// Calculates spherical linear interpolation between two quaternions // Calculates spherical linear interpolation between two quaternions
Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount) Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
{ {
Quaternion result; Quaternion result;
float cosHalfTheta = q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w; float cosHalfTheta = q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w;
if (abs(cosHalfTheta) >= 1.0) result = q1; if (abs(cosHalfTheta) >= 1.0) result = q1;
else else
{ {
@ -892,15 +892,15 @@ Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
else else
{ {
float ratioA = sin((1 - amount)*halfTheta) / sinHalfTheta; float ratioA = sin((1 - amount)*halfTheta) / sinHalfTheta;
float ratioB = sin(amount*halfTheta) / sinHalfTheta; float ratioB = sin(amount*halfTheta) / sinHalfTheta;
result.x = (q1.x*ratioA + q2.x*ratioB); result.x = (q1.x*ratioA + q2.x*ratioB);
result.y = (q1.y*ratioA + q2.y*ratioB); result.y = (q1.y*ratioA + q2.y*ratioB);
result.z = (q1.z*ratioA + q2.z*ratioB); result.z = (q1.z*ratioA + q2.z*ratioB);
result.w = (q1.w*ratioA + q2.w*ratioB); result.w = (q1.w*ratioA + q2.w*ratioB);
} }
} }
return result; return result;
} }
@ -956,7 +956,7 @@ Quaternion QuaternionFromMatrix(Matrix matrix)
result.z = s * 0.25; result.z = s * 0.25;
} }
} }
return result; return result;
} }
@ -966,24 +966,24 @@ Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle)
{ {
Quaternion result = { 0, 0, 0, 1 }; Quaternion result = { 0, 0, 0, 1 };
if (VectorLength(axis) != 0.0) if (VectorLength(axis) != 0.0)
angle *= 0.5; angle *= 0.5;
VectorNormalize(&axis); VectorNormalize(&axis);
result.x = axis.x * (float)sin(angle); result.x = axis.x * (float)sin(angle);
result.y = axis.y * (float)sin(angle); result.y = axis.y * (float)sin(angle);
result.z = axis.z * (float)sin(angle); result.z = axis.z * (float)sin(angle);
result.w = (float)cos(angle); result.w = (float)cos(angle);
QuaternionNormalize(&result); QuaternionNormalize(&result);
return result; return result;
} }
// Calculates the matrix from the given quaternion // Calculates the matrix from the given quaternion
Matrix QuaternionToMatrix(Quaternion q) Matrix QuaternionToMatrix(Quaternion q)
{ {
Matrix result; Matrix result;
@ -1021,7 +1021,7 @@ Matrix QuaternionToMatrix(Quaternion q)
result.m13 = 0; result.m13 = 0;
result.m14 = 0; result.m14 = 0;
result.m15 = 1; result.m15 = 1;
return result; return result;
} }
@ -1035,7 +1035,7 @@ void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle)
resAngle = 2.0f * (float)acos(q.w); resAngle = 2.0f * (float)acos(q.w);
float den = (float)sqrt(1.0 - q.w * q.w); float den = (float)sqrt(1.0 - q.w * q.w);
if (den > 0.0001f) if (den > 0.0001f)
{ {
resAxis.x = q.x / den; resAxis.x = q.x / den;
@ -1044,11 +1044,11 @@ void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle)
} }
else else
{ {
// This occurs when the angle is zero. // This occurs when the angle is zero.
// Not a problem: just set an arbitrary normalized axis. // Not a problem: just set an arbitrary normalized axis.
resAxis.x = 1.0; resAxis.x = 1.0;
} }
*outAxis = resAxis; *outAxis = resAxis;
*outAngle = resAngle; *outAngle = resAngle;
} }

View file

@ -1,19 +1,19 @@
/********************************************************************************************* /*********************************************************************************************
* *
* raymath * raymath
* *
* Some useful functions to work with Vector3, Matrix and Quaternions * Some useful functions to work with Vector3, Matrix and Quaternions
* *
* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) * Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
* *
* Permission is granted to anyone to use this software for any purpose, including commercial * Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions: * applications, and to alter it and redistribute it freely, subject to the following restrictions:
* *
* 1. The origin of this software must not be misrepresented; you must not claim that you * 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment * wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required. * in the product documentation would be appreciated but is not required.
* *
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented * 2. Altered source versions must be plainly marked as such, and must not be misrepresented

File diff suppressed because it is too large Load diff

View file

@ -1,22 +1,22 @@
/********************************************************************************************* /*********************************************************************************************
* *
* rlgl - raylib OpenGL abstraction layer * rlgl - raylib OpenGL abstraction layer
* *
* raylib now uses OpenGL 1.1 style functions (rlVertex) that are mapped to selected OpenGL version: * raylib now uses OpenGL 1.1 style functions (rlVertex) that are mapped to selected OpenGL version:
* OpenGL 1.1 - Direct map rl* -> gl* * OpenGL 1.1 - Direct map rl* -> gl*
* OpenGL 3.3+ - Vertex data is stored in VAOs, call rlglDraw() to render * OpenGL 3.3+ - Vertex data is stored in VAOs, call rlglDraw() to render
* OpenGL ES 2 - Same behaviour as OpenGL 3.3+ (NOT TESTED) * OpenGL ES 2 - Same behaviour as OpenGL 3.3+ (NOT TESTED)
* *
* Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com) * Copyright (c) 2014 Ramon Santamaria (Ray San - raysan@raysanweb.com)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
* *
* Permission is granted to anyone to use this software for any purpose, including commercial * Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions: * applications, and to alter it and redistribute it freely, subject to the following restrictions:
* *
* 1. The origin of this software must not be misrepresented; you must not claim that you * 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment * wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required. * in the product documentation would be appreciated but is not required.
* *
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented * 2. Altered source versions must be plainly marked as such, and must not be misrepresented

View file

@ -3,17 +3,17 @@
* raylib.shapes * raylib.shapes
* *
* Basic functions to draw 2d Shapes and check collisions * Basic functions to draw 2d Shapes and check collisions
* *
* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) * Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
* *
* Permission is granted to anyone to use this software for any purpose, including commercial * Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions: * applications, and to alter it and redistribute it freely, subject to the following restrictions:
* *
* 1. The origin of this software must not be misrepresented; you must not claim that you * 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment * wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required. * in the product documentation would be appreciated but is not required.
* *
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
@ -28,7 +28,7 @@
#include <stdlib.h> // Required for abs() function #include <stdlib.h> // Required for abs() function
#include <math.h> // Math related functions, sin() and cos() used on DrawCircle* #include <math.h> // Math related functions, sin() and cos() used on DrawCircle*
// sqrt() and pow() and abs() used on CheckCollision* // sqrt() and pow() and abs() used on CheckCollision*
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2 #include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
// Security check in case no USE_OPENGL_* defined // Security check in case no USE_OPENGL_* defined
@ -110,7 +110,7 @@ void DrawCircle(int centerX, int centerY, float radius, Color color)
// NOTE: Gradient goes from center (color1) to border (color2) // NOTE: Gradient goes from center (color1) to border (color2)
void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2) void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2)
{ {
rlBegin(RL_TRIANGLES); rlBegin(RL_TRIANGLES);
for (int i=0; i < 360; i += 2) for (int i=0; i < 360; i += 2)
{ {
rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlColor4ub(color1.r, color1.g, color1.b, color1.a);
@ -142,7 +142,7 @@ void DrawCircleLines(int centerX, int centerY, float radius, Color color)
{ {
rlBegin(RL_LINES); rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
// NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360) // NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360)
for (int i=0; i < 360; i++) for (int i=0; i < 360; i++)
{ {
@ -165,7 +165,7 @@ void DrawRectangle(int posX, int posY, int width, int height, Color color)
void DrawRectangleRec(Rectangle rec, Color color) void DrawRectangleRec(Rectangle rec, Color color)
{ {
DrawRectangle(rec.x, rec.y, rec.width, rec.height, color); DrawRectangle(rec.x, rec.y, rec.width, rec.height, color);
} }
// Draw a gradient-filled rectangle // Draw a gradient-filled rectangle
// NOTE: Gradient goes from bottom (color1) to top (color2) // NOTE: Gradient goes from bottom (color1) to top (color2)
@ -175,9 +175,9 @@ void DrawRectangleGradient(int posX, int posY, int width, int height, Color colo
rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX, posY); 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, posY + height);
rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX + width, posY + height); rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX + width, posY + height);
rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX, posY); rlColor4ub(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(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); rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX + width, posY);
rlEnd(); rlEnd();
} }
@ -188,16 +188,16 @@ void DrawRectangleV(Vector2 position, Vector2 size, Color color)
#ifdef USE_OPENGL_11 #ifdef USE_OPENGL_11
rlBegin(RL_TRIANGLES); rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2i(position.x, position.y); rlVertex2i(position.x, position.y);
rlVertex2i(position.x, position.y + size.y); rlVertex2i(position.x, position.y + size.y);
rlVertex2i(position.x + size.x, position.y + size.y); rlVertex2i(position.x + size.x, position.y + size.y);
rlVertex2i(position.x, position.y); rlVertex2i(position.x, position.y);
rlVertex2i(position.x + size.x, position.y + size.y); rlVertex2i(position.x + size.x, position.y + size.y);
rlVertex2i(position.x + size.x, position.y); rlVertex2i(position.x + size.x, position.y);
rlEnd(); rlEnd();
#endif #endif
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2) #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
// NOTE: This shape uses QUADS to avoid drawing order issues (view rlglDraw) // NOTE: This shape uses QUADS to avoid drawing order issues (view rlglDraw)
@ -206,17 +206,17 @@ void DrawRectangleV(Vector2 position, Vector2 size, Color color)
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
rlTexCoord2f(0.0f, 0.0f); rlTexCoord2f(0.0f, 0.0f);
rlVertex2f(position.x, position.y); rlVertex2f(position.x, position.y);
rlTexCoord2f(0.0f, 1.0f); rlTexCoord2f(0.0f, 1.0f);
rlVertex2f(position.x, position.y + size.y); rlVertex2f(position.x, position.y + size.y);
rlTexCoord2f(1.0f, 1.0f); rlTexCoord2f(1.0f, 1.0f);
rlVertex2f(position.x + size.x, position.y + size.y); rlVertex2f(position.x + size.x, position.y + size.y);
rlTexCoord2f(1.0f, 0.0f); rlTexCoord2f(1.0f, 0.0f);
rlVertex2f(position.x + size.x, position.y); rlVertex2f(position.x + size.x, position.y);
rlEnd(); rlEnd();
@ -231,13 +231,13 @@ void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2i(posX + 1, posY + 1); rlVertex2i(posX + 1, posY + 1);
rlVertex2i(posX + width, posY + 1); rlVertex2i(posX + width, posY + 1);
rlVertex2i(posX + width, posY + 1); rlVertex2i(posX + width, posY + 1);
rlVertex2i(posX + width, posY + height); rlVertex2i(posX + width, posY + height);
rlVertex2i(posX + width, posY + height); rlVertex2i(posX + width, posY + height);
rlVertex2i(posX + 1, posY + height); rlVertex2i(posX + 1, posY + height);
rlVertex2i(posX + 1, posY + height); rlVertex2i(posX + 1, posY + height);
rlVertex2i(posX + 1, posY + 1); rlVertex2i(posX + 1, posY + 1);
rlEnd(); rlEnd();
@ -260,10 +260,10 @@ void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(v1.x, v1.y); rlVertex2f(v1.x, v1.y);
rlVertex2f(v2.x, v2.y); rlVertex2f(v2.x, v2.y);
rlVertex2f(v2.x, v2.y); rlVertex2f(v2.x, v2.y);
rlVertex2f(v3.x, v3.y); rlVertex2f(v3.x, v3.y);
rlVertex2f(v3.x, v3.y); rlVertex2f(v3.x, v3.y);
rlVertex2f(v1.x, v1.y); rlVertex2f(v1.x, v1.y);
rlEnd(); rlEnd();
@ -277,12 +277,12 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col
rlPushMatrix(); rlPushMatrix();
rlTranslatef(center.x, center.y, 0.0); rlTranslatef(center.x, center.y, 0.0);
rlRotatef(rotation, 0, 0, 1); rlRotatef(rotation, 0, 0, 1);
rlBegin(RL_TRIANGLES); rlBegin(RL_TRIANGLES);
for (int i=0; i < 360; i += 360/sides) for (int i=0; i < 360; i += 360/sides)
{ {
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2i(0, 0); rlVertex2i(0, 0);
rlVertex2f(sin(DEG2RAD*i) * radius, cos(DEG2RAD*i) * radius); rlVertex2f(sin(DEG2RAD*i) * radius, cos(DEG2RAD*i) * radius);
rlVertex2f(sin(DEG2RAD*(i+360/sides)) * radius, cos(DEG2RAD*(i+360/sides)) * radius); rlVertex2f(sin(DEG2RAD*(i+360/sides)) * radius, cos(DEG2RAD*(i+360/sides)) * radius);
@ -299,7 +299,7 @@ void DrawPolyEx(Vector2 *points, int numPoints, Color color)
{ {
rlBegin(RL_TRIANGLES); rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 0; i < numPoints - 2; i++) for (int i = 0; i < numPoints - 2; i++)
{ {
rlVertex2f(points[i].x, points[i].y); rlVertex2f(points[i].x, points[i].y);
@ -311,14 +311,14 @@ void DrawPolyEx(Vector2 *points, int numPoints, Color color)
} }
// Draw polygon lines // Draw polygon lines
// NOTE: Array num elements MUST be passed as parameter to function // NOTE: Array num elements MUST be passed as parameter to function
void DrawPolyExLines(Vector2 *points, int numPoints, Color color) void DrawPolyExLines(Vector2 *points, int numPoints, Color color)
{ {
if (numPoints >= 2) if (numPoints >= 2)
{ {
rlBegin(RL_LINES); rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 0; i < numPoints - 1; i++) for (int i = 0; i < numPoints - 1; i++)
{ {
rlVertex2f(points[i].x, points[i].y); rlVertex2f(points[i].x, points[i].y);
@ -336,9 +336,9 @@ void DrawPolyExLines(Vector2 *points, int numPoints, Color color)
bool CheckCollisionPointRec(Vector2 point, Rectangle rec) bool CheckCollisionPointRec(Vector2 point, Rectangle rec)
{ {
bool collision = false; bool collision = false;
if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) && (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true; if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) && (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true;
return collision; return collision;
} }
@ -355,14 +355,14 @@ bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2
float alpha = ((p2.y - p3.y)*(point.x - p3.x) + (p3.x - p2.x)*(point.y - p3.y)) / float alpha = ((p2.y - p3.y)*(point.x - p3.x) + (p3.x - p2.x)*(point.y - p3.y)) /
((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y)); ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y));
float beta = ((p3.y - p1.y)*(point.x - p3.x) + (p1.x - p3.x)*(point.y - p3.y)) / float beta = ((p3.y - p1.y)*(point.x - p3.x) + (p1.x - p3.x)*(point.y - p3.y)) /
((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y)); ((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y));
float gamma = 1.0f - alpha - beta; float gamma = 1.0f - alpha - beta;
if ((alpha > 0) && (beta > 0) & (gamma > 0)) collision = true; if ((alpha > 0) && (beta > 0) & (gamma > 0)) collision = true;
return collision; return collision;
} }
@ -370,12 +370,12 @@ bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2
bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2) bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2)
{ {
bool collision = false; bool collision = false;
int dx = abs((rec1.x + rec1.width / 2) - (rec2.x + rec2.width / 2)); int dx = abs((rec1.x + rec1.width / 2) - (rec2.x + rec2.width / 2));
int dy = abs((rec1.y + rec1.height / 2) - (rec2.y + rec2.height / 2)); int dy = abs((rec1.y + rec1.height / 2) - (rec2.y + rec2.height / 2));
if ((dx <= (rec1.width / 2 + rec2.width / 2)) && ((dy <= (rec1.height / 2 + rec2.height / 2)))) collision = true; if ((dx <= (rec1.width / 2 + rec2.width / 2)) && ((dy <= (rec1.height / 2 + rec2.height / 2)))) collision = true;
return collision; return collision;
} }
@ -383,14 +383,14 @@ bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2)
bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2) bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2)
{ {
bool collision = false; bool collision = false;
float dx = center2.x - center1.x; // X distance between centers float dx = center2.x - center1.x; // X distance between centers
float dy = center2.y - center1.y; // Y distance between centers float dy = center2.y - center1.y; // Y distance between centers
float distance = sqrt(dx*dx + dy*dy); // Distance between centers float distance = sqrt(dx*dx + dy*dy); // Distance between centers
if (distance <= (radius1 + radius2)) collision = true; if (distance <= (radius1 + radius2)) collision = true;
return collision; return collision;
} }
@ -398,12 +398,12 @@ bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, floa
bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec) bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
{ {
bool collision = false; bool collision = false;
float dx = abs((rec.x + rec.width / 2) - center.x); float dx = abs((rec.x + rec.width / 2) - center.x);
float dy = abs((rec.y + rec.height / 2) - center.y); float dy = abs((rec.y + rec.height / 2) - center.y);
if ((dx <= (rec.width / 2 + radius)) && (dy <= (rec.height / 2 + radius))) collision = true; if ((dx <= (rec.width / 2 + radius)) && (dy <= (rec.height / 2 + radius))) collision = true;
return collision; return collision;
} }
@ -411,16 +411,16 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2) Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
{ {
Rectangle retRec = { 0, 0, 0, 0 }; Rectangle retRec = { 0, 0, 0, 0 };
if (CheckCollisionRecs(rec1, rec2)) if (CheckCollisionRecs(rec1, rec2))
{ {
int dxx = abs(rec1.x - rec2.x); int dxx = abs(rec1.x - rec2.x);
int dyy = abs(rec1.y - rec2.y); int dyy = abs(rec1.y - rec2.y);
if (rec1.x <= rec2.x) if (rec1.x <= rec2.x)
{ {
if (rec1.y <= rec2.y) if (rec1.y <= rec2.y)
{ {
retRec.x = rec2.x; retRec.x = rec2.x;
retRec.y = rec2.y; retRec.y = rec2.y;
retRec.width = rec1.width - dxx; retRec.width = rec1.width - dxx;
@ -437,7 +437,7 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
else else
{ {
if (rec1.y <= rec2.y) if (rec1.y <= rec2.y)
{ {
retRec.x = rec1.x; retRec.x = rec1.x;
retRec.y = rec2.y; retRec.y = rec2.y;
retRec.width = rec2.width - dxx; retRec.width = rec2.width - dxx;
@ -451,10 +451,10 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
retRec.height = rec2.height - dyy; retRec.height = rec2.height - dyy;
} }
} }
if (retRec.width >= rec2.width) retRec.width = rec2.width; if (retRec.width >= rec2.width) retRec.width = rec2.width;
if (retRec.height >= rec2.height) retRec.height = rec2.height; if (retRec.height >= rec2.height) retRec.height = rec2.height;
} }
return retRec; return retRec;
} }

View file

@ -3,20 +3,20 @@
* raylib.text * raylib.text
* *
* Basic functions to load SpriteFonts and draw Text * Basic functions to load SpriteFonts and draw Text
* *
* Uses external lib: * Uses external lib:
* stb_image - Multiple formats image loading (JPEG, PNG, BMP, TGA, PSD, GIF, HDR, PIC) * stb_image - Multiple formats image loading (JPEG, PNG, BMP, TGA, PSD, GIF, HDR, PIC)
* *
* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) * Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
* *
* Permission is granted to anyone to use this software for any purpose, including commercial * Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions: * applications, and to alter it and redistribute it freely, subject to the following restrictions:
* *
* 1. The origin of this software must not be misrepresented; you must not claim that you * 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment * wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required. * in the product documentation would be appreciated but is not required.
* *
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
@ -82,14 +82,14 @@ static SpriteFont LoadRBMF(const char *fileName); // Load a rBMF font file (ra
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Module Functions Definition // Module Functions Definition
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
extern void LoadDefaultFont() extern void LoadDefaultFont()
{ {
defaultFont.numChars = 96; // We know our default font has 94 chars defaultFont.numChars = 96; // We know our default font has 94 chars
Image image; Image image;
image.width = 128; // We know our default font image is 128 pixels width image.width = 128; // We know our default font image is 128 pixels width
image.height = 64; // We know our default font image is 64 pixels height image.height = 64; // We know our default font image is 64 pixels height
// Default font is directly defined here (data generated from a sprite font image) // Default font is directly defined here (data generated from a sprite font image)
// This way, we reconstruct SpriteFont without creating large global variables // This way, we reconstruct SpriteFont without creating large global variables
// This data is automatically allocated to Stack and automatically deallocated at the end of this function // This data is automatically allocated to Stack and automatically deallocated at the end of this function
@ -119,19 +119,19 @@ extern void LoadDefaultFont()
int charsHeight = 10; int charsHeight = 10;
int charsDivisor = 1; // Every char is separated from the consecutive by a 1 pixel divisor, horizontally and vertically int charsDivisor = 1; // Every char is separated from the consecutive by a 1 pixel divisor, horizontally and vertically
int charsWidth[96] = { 3, 1, 4, 6, 5, 7, 6, 2, 3, 3, 5, 5, 2, 4, 1, 7, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 3, 4, 3, 6, int charsWidth[96] = { 3, 1, 4, 6, 5, 7, 6, 2, 3, 3, 5, 5, 2, 4, 1, 7, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 3, 4, 3, 6,
7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 5, 6, 5, 7, 6, 6, 6, 6, 6, 6, 7, 6, 7, 7, 6, 6, 6, 2, 7, 2, 3, 5, 7, 6, 6, 6, 6, 6, 6, 6, 6, 3, 5, 6, 5, 7, 6, 6, 6, 6, 6, 6, 7, 6, 7, 7, 6, 6, 6, 2, 7, 2, 3, 5,
2, 5, 5, 5, 5, 5, 4, 5, 5, 1, 2, 5, 2, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 3, 1, 3, 4, 4 }; 2, 5, 5, 5, 5, 5, 4, 5, 5, 1, 2, 5, 2, 5, 5, 5, 5, 5, 5, 5, 4, 5, 5, 5, 5, 5, 5, 3, 1, 3, 4, 4 };
// Re-construct image from defaultFontData and generate OpenGL texture // Re-construct image from defaultFontData and generate OpenGL texture
//---------------------------------------------------------------------- //----------------------------------------------------------------------
image.pixels = (Color *)malloc(image.width * image.height * sizeof(Color)); image.pixels = (Color *)malloc(image.width * image.height * sizeof(Color));
for (int i = 0; i < image.width * image.height; i++) image.pixels[i] = BLANK; // Initialize array for (int i = 0; i < image.width * image.height; i++) image.pixels[i] = BLANK; // Initialize array
int counter = 0; // Font data elements counter int counter = 0; // Font data elements counter
// Fill imgData with defaultFontData (convert from bit to pixel!) // Fill imgData with defaultFontData (convert from bit to pixel!)
for (int i = 0; i < image.width * image.height; i += 32) for (int i = 0; i < image.width * image.height; i += 32)
{ {
@ -139,15 +139,15 @@ extern void LoadDefaultFont()
{ {
if (BIT_CHECK(defaultFontData[counter], j)) image.pixels[i+j] = WHITE; if (BIT_CHECK(defaultFontData[counter], j)) image.pixels[i+j] = WHITE;
} }
counter++; counter++;
if (counter > 256) counter = 0; // Security check... if (counter > 256) counter = 0; // Security check...
} }
defaultFont.texture = CreateTexture(image, false); // Convert loaded image to OpenGL texture defaultFont.texture = CreateTexture(image, false); // Convert loaded image to OpenGL texture
UnloadImage(image); UnloadImage(image);
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, numChars // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, numChars
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
defaultFont.charSet = (Character *)malloc(defaultFont.numChars * sizeof(Character)); // Allocate space for our character data defaultFont.charSet = (Character *)malloc(defaultFont.numChars * sizeof(Character)); // Allocate space for our character data
@ -155,7 +155,7 @@ extern void LoadDefaultFont()
int currentLine = 0; int currentLine = 0;
int currentPosX = charsDivisor; int currentPosX = charsDivisor;
int testPosX = charsDivisor; int testPosX = charsDivisor;
for (int i = 0; i < defaultFont.numChars; i++) for (int i = 0; i < defaultFont.numChars; i++)
{ {
defaultFont.charSet[i].value = FONT_FIRST_CHAR + i; // First char is 32 defaultFont.charSet[i].value = FONT_FIRST_CHAR + i; // First char is 32
@ -163,21 +163,21 @@ extern void LoadDefaultFont()
defaultFont.charSet[i].y = charsDivisor + currentLine * (charsHeight + charsDivisor); defaultFont.charSet[i].y = charsDivisor + currentLine * (charsHeight + charsDivisor);
defaultFont.charSet[i].w = charsWidth[i]; defaultFont.charSet[i].w = charsWidth[i];
defaultFont.charSet[i].h = charsHeight; defaultFont.charSet[i].h = charsHeight;
testPosX += (defaultFont.charSet[i].w + charsDivisor); testPosX += (defaultFont.charSet[i].w + charsDivisor);
if (testPosX >= defaultFont.texture.width) if (testPosX >= defaultFont.texture.width)
{ {
currentLine++; currentLine++;
currentPosX = 2 * charsDivisor + charsWidth[i]; currentPosX = 2 * charsDivisor + charsWidth[i];
testPosX = currentPosX; testPosX = currentPosX;
defaultFont.charSet[i].x = charsDivisor; defaultFont.charSet[i].x = charsDivisor;
defaultFont.charSet[i].y = charsDivisor + currentLine * (charsHeight + charsDivisor); defaultFont.charSet[i].y = charsDivisor + currentLine * (charsHeight + charsDivisor);
} }
else currentPosX = testPosX; else currentPosX = testPosX;
} }
TraceLog(INFO, "Default font loaded successfully"); TraceLog(INFO, "Default font loaded successfully");
} }
@ -194,29 +194,29 @@ SpriteFont GetDefaultFont()
} }
// Load a SpriteFont image into GPU memory // Load a SpriteFont image into GPU memory
SpriteFont LoadSpriteFont(const char* fileName) SpriteFont LoadSpriteFont(const char* fileName)
{ {
SpriteFont spriteFont; SpriteFont spriteFont;
Image image; Image image;
// Check file extension // Check file extension
if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName); if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName);
else else
{ {
// Use stb_image to load image data! // Use stb_image to load image data!
int imgWidth; int imgWidth;
int imgHeight; int imgHeight;
int imgBpp; int imgBpp;
byte *imgData = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 4); // Force loading to 4 components (RGBA) byte *imgData = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 4); // Force loading to 4 components (RGBA)
// Convert array to pixel array for working convenience // Convert array to pixel array for working convenience
Color *imgDataPixel = (Color *)malloc(imgWidth * imgHeight * sizeof(Color)); Color *imgDataPixel = (Color *)malloc(imgWidth * imgHeight * sizeof(Color));
Color *imgDataPixelPOT = NULL; Color *imgDataPixelPOT = NULL;
int pix = 0; int pix = 0;
for (int i = 0; i < (imgWidth * imgHeight * 4); i += 4) for (int i = 0; i < (imgWidth * imgHeight * 4); i += 4)
{ {
imgDataPixel[pix].r = imgData[i]; imgDataPixel[pix].r = imgData[i];
@ -225,33 +225,33 @@ SpriteFont LoadSpriteFont(const char* fileName)
imgDataPixel[pix].a = imgData[i+3]; imgDataPixel[pix].a = imgData[i+3];
pix++; pix++;
} }
stbi_image_free(imgData); stbi_image_free(imgData);
// At this point we have a pixel array with all the data... // At this point we have a pixel array with all the data...
TraceLog(INFO, "[%s] SpriteFont image loaded: %i x %i", fileName, imgWidth, imgHeight); TraceLog(INFO, "[%s] SpriteFont image loaded: %i x %i", fileName, imgWidth, imgHeight);
// Process bitmap Font pixel data to get measures (Character array) // Process bitmap Font pixel data to get measures (Character array)
// spriteFont.charSet data is filled inside the function and memory is allocated! // spriteFont.charSet data is filled inside the function and memory is allocated!
int numChars = ParseImageData(imgDataPixel, imgWidth, imgHeight, &spriteFont.charSet); int numChars = ParseImageData(imgDataPixel, imgWidth, imgHeight, &spriteFont.charSet);
TraceLog(INFO, "[%s] SpriteFont data parsed correctly", fileName); TraceLog(INFO, "[%s] SpriteFont data parsed correctly", fileName);
TraceLog(INFO, "[%s] SpriteFont num chars detected: %i", fileName, numChars); TraceLog(INFO, "[%s] SpriteFont num chars detected: %i", fileName, numChars);
spriteFont.numChars = numChars; spriteFont.numChars = numChars;
// Convert image font to POT image before conversion to texture // Convert image font to POT image before conversion to texture
// Just add the required amount of pixels at the right and bottom sides of image... // Just add the required amount of pixels at the right and bottom sides of image...
int potWidth = GetNextPOT(imgWidth); int potWidth = GetNextPOT(imgWidth);
int potHeight = GetNextPOT(imgHeight); int potHeight = GetNextPOT(imgHeight);
// Check if POT texture generation is required (if texture is not already POT) // Check if POT texture generation is required (if texture is not already POT)
if ((potWidth != imgWidth) || (potHeight != imgHeight)) if ((potWidth != imgWidth) || (potHeight != imgHeight))
{ {
// Generate POT array from NPOT data // Generate POT array from NPOT data
imgDataPixelPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color)); imgDataPixelPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color));
for (int j = 0; j < potHeight; j++) for (int j = 0; j < potHeight; j++)
{ {
for (int i = 0; i < potWidth; i++) for (int i = 0; i < potWidth; i++)
@ -260,20 +260,20 @@ SpriteFont LoadSpriteFont(const char* fileName)
else imgDataPixelPOT[j*potWidth + i] = MAGENTA; else imgDataPixelPOT[j*potWidth + i] = MAGENTA;
} }
} }
TraceLog(WARNING, "SpriteFont texture converted to POT: %ix%i", potWidth, potHeight); TraceLog(WARNING, "SpriteFont texture converted to POT: %ix%i", potWidth, potHeight);
} }
free(imgDataPixel); free(imgDataPixel);
image.pixels = imgDataPixelPOT; image.pixels = imgDataPixelPOT;
image.width = potWidth; image.width = potWidth;
image.height = potHeight; image.height = potHeight;
spriteFont.texture = CreateTexture(image, false); // Convert loaded image to OpenGL texture spriteFont.texture = CreateTexture(image, false); // Convert loaded image to OpenGL texture
UnloadImage(image); UnloadImage(image);
} }
return spriteFont; return spriteFont;
} }
@ -290,13 +290,13 @@ void UnloadSpriteFont(SpriteFont spriteFont)
void DrawText(const char* text, int posX, int posY, int fontSize, Color color) void DrawText(const char* text, int posX, int posY, int fontSize, Color color)
{ {
Vector2 position = { (float)posX, (float)posY }; Vector2 position = { (float)posX, (float)posY };
int defaultFontSize = 10; // Default Font chars height in pixel int defaultFontSize = 10; // Default Font chars height in pixel
if (fontSize < defaultFontSize) fontSize = defaultFontSize; if (fontSize < defaultFontSize) fontSize = defaultFontSize;
int spacing = fontSize / defaultFontSize; int spacing = fontSize / defaultFontSize;
DrawTextEx(defaultFont, text, position, fontSize, spacing, color); DrawTextEx(defaultFont, text, position, fontSize, spacing, color);
} }
@ -308,9 +308,9 @@ void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, int f
int length = strlen(text); int length = strlen(text);
int positionX = (int)position.x; int positionX = (int)position.x;
float scaleFactor; float scaleFactor;
Character c; Character c;
if (fontSize <= spriteFont.charSet[0].h) scaleFactor = 1.0f; if (fontSize <= spriteFont.charSet[0].h) scaleFactor = 1.0f;
else scaleFactor = (float)fontSize / spriteFont.charSet[0].h; else scaleFactor = (float)fontSize / spriteFont.charSet[0].h;
@ -320,22 +320,22 @@ void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, int f
for(int i = 0; i < length; i++) for(int i = 0; i < length; i++)
{ {
c = spriteFont.charSet[(int)text[i] - FONT_FIRST_CHAR]; c = spriteFont.charSet[(int)text[i] - FONT_FIRST_CHAR];
rlColor4ub(tint.r, tint.g, tint.b, tint.a); rlColor4ub(tint.r, tint.g, tint.b, tint.a);
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
rlTexCoord2f((float)c.x / spriteFont.texture.width, (float)c.y / spriteFont.texture.height); rlTexCoord2f((float)c.x / spriteFont.texture.width, (float)c.y / spriteFont.texture.height);
rlVertex2f(positionX, position.y); rlVertex2f(positionX, position.y);
rlTexCoord2f((float)c.x / spriteFont.texture.width, (float)(c.y + c.h) / spriteFont.texture.height); rlTexCoord2f((float)c.x / spriteFont.texture.width, (float)(c.y + c.h) / spriteFont.texture.height);
rlVertex2f(positionX, position.y + (c.h) * scaleFactor); rlVertex2f(positionX, position.y + (c.h) * scaleFactor);
rlTexCoord2f((float)(c.x + c.w) / spriteFont.texture.width, (float)(c.y + c.h) / spriteFont.texture.height); rlTexCoord2f((float)(c.x + c.w) / spriteFont.texture.width, (float)(c.y + c.h) / spriteFont.texture.height);
rlVertex2f(positionX + (c.w) * scaleFactor, position.y + (c.h) * scaleFactor); rlVertex2f(positionX + (c.w) * scaleFactor, position.y + (c.h) * scaleFactor);
rlTexCoord2f((float)(c.x + c.w) / spriteFont.texture.width, (float)c.y / spriteFont.texture.height); rlTexCoord2f((float)(c.x + c.w) / spriteFont.texture.width, (float)c.y / spriteFont.texture.height);
rlVertex2f(positionX + (c.w) * scaleFactor, position.y); rlVertex2f(positionX + (c.w) * scaleFactor, position.y);
positionX += ((spriteFont.charSet[(int)text[i] - FONT_FIRST_CHAR].w) * scaleFactor + spacing); positionX += ((spriteFont.charSet[(int)text[i] - FONT_FIRST_CHAR].w) * scaleFactor + spacing);
} }
rlEnd(); rlEnd();
@ -347,7 +347,7 @@ void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, int f
const char *FormatText(const char *text, ...) const char *FormatText(const char *text, ...)
{ {
static char buffer[MAX_FORMATTEXT_LENGTH]; static char buffer[MAX_FORMATTEXT_LENGTH];
va_list args; va_list args;
va_start(args, text); va_start(args, text);
vsprintf(buffer, text, args); vsprintf(buffer, text, args);
@ -372,19 +372,19 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int
int len = strlen(text); int len = strlen(text);
int textWidth = 0; int textWidth = 0;
float scaleFactor; float scaleFactor;
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
{ {
textWidth += spriteFont.charSet[(int)text[i] - FONT_FIRST_CHAR].w; textWidth += spriteFont.charSet[(int)text[i] - FONT_FIRST_CHAR].w;
} }
if (fontSize <= spriteFont.charSet[0].h) scaleFactor = 1.0f; if (fontSize <= spriteFont.charSet[0].h) scaleFactor = 1.0f;
else scaleFactor = (float)fontSize / spriteFont.charSet[0].h; else scaleFactor = (float)fontSize / spriteFont.charSet[0].h;
Vector2 vec; Vector2 vec;
vec.x = (float)textWidth * scaleFactor + (len - 1) * spacing; // Adds chars spacing to measure vec.x = (float)textWidth * scaleFactor + (len - 1) * spacing; // Adds chars spacing to measure
vec.y = (float)spriteFont.charSet[0].h * scaleFactor; vec.y = (float)spriteFont.charSet[0].h * scaleFactor;
return vec; return vec;
} }
@ -402,11 +402,11 @@ void DrawFPS(int posX, int posY)
static float fps; static float fps;
static int counter = 0; static int counter = 0;
static int refreshRate = 0; static int refreshRate = 0;
char buffer[20]; char buffer[20];
if (counter < refreshRate) if (counter < refreshRate)
{ {
counter++; counter++;
} }
else else
@ -415,7 +415,7 @@ void DrawFPS(int posX, int posY)
refreshRate = fps; refreshRate = fps;
counter = 0; counter = 0;
} }
sprintf(buffer, "%2.0f FPS", fps); sprintf(buffer, "%2.0f FPS", fps);
DrawText(buffer, posX, posY, 20, LIME); DrawText(buffer, posX, posY, 20, LIME);
} }
@ -435,36 +435,36 @@ static int ParseImageData(Color *imgDataPixel, int imgWidth, int imgHeight, Char
{ {
int charSpacing = 0; int charSpacing = 0;
int lineSpacing = 0; int lineSpacing = 0;
int x = 0; int x = 0;
int y = 0; int y = 0;
Character tempCharSet[MAX_FONTCHARS]; // We allocate a temporal array for charData, once we get the actual charNumber we copy data to a sized array. Character tempCharSet[MAX_FONTCHARS]; // We allocate a temporal array for charData, once we get the actual charNumber we copy data to a sized array.
for(y = 0; y < imgHeight; y++) for(y = 0; y < imgHeight; y++)
{ {
for(x = 0; x < imgWidth; x++) for(x = 0; x < imgWidth; x++)
{ {
if (!PixelIsMagenta(imgDataPixel[y*imgWidth + x])) break; if (!PixelIsMagenta(imgDataPixel[y*imgWidth + x])) break;
} }
if (!PixelIsMagenta(imgDataPixel[y*imgWidth + x])) break; if (!PixelIsMagenta(imgDataPixel[y*imgWidth + x])) break;
} }
charSpacing = x; charSpacing = x;
lineSpacing = y; lineSpacing = y;
int charHeight = 0; int charHeight = 0;
int j = 0; int j = 0;
while(!PixelIsMagenta(imgDataPixel[(lineSpacing + j)*imgWidth + charSpacing])) j++; while(!PixelIsMagenta(imgDataPixel[(lineSpacing + j)*imgWidth + charSpacing])) j++;
charHeight = j; charHeight = j;
// Check array values to get characters: value, x, y, w, h // Check array values to get characters: value, x, y, w, h
int index = 0; int index = 0;
int lineToRead = 0; int lineToRead = 0;
int xPosToRead = charSpacing; int xPosToRead = charSpacing;
while((lineSpacing + lineToRead * (charHeight + lineSpacing)) < imgHeight) while((lineSpacing + lineToRead * (charHeight + lineSpacing)) < imgHeight)
{ {
while((xPosToRead < imgWidth) && while((xPosToRead < imgWidth) &&
@ -474,22 +474,22 @@ static int ParseImageData(Color *imgDataPixel, int imgWidth, int imgHeight, Char
tempCharSet[index].x = xPosToRead; tempCharSet[index].x = xPosToRead;
tempCharSet[index].y = lineSpacing + lineToRead * (charHeight + lineSpacing); tempCharSet[index].y = lineSpacing + lineToRead * (charHeight + lineSpacing);
tempCharSet[index].h = charHeight; tempCharSet[index].h = charHeight;
int charWidth = 0; int charWidth = 0;
while(!PixelIsMagenta(imgDataPixel[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*imgWidth + xPosToRead + charWidth])) charWidth++; while(!PixelIsMagenta(imgDataPixel[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*imgWidth + xPosToRead + charWidth])) charWidth++;
tempCharSet[index].w = charWidth; tempCharSet[index].w = charWidth;
index++; index++;
xPosToRead += (charWidth + charSpacing); xPosToRead += (charWidth + charSpacing);
} }
lineToRead++; lineToRead++;
xPosToRead = charSpacing; xPosToRead = charSpacing;
} }
// We got tempCharSet populated with char data and the number of chars (index) // We got tempCharSet populated with char data and the number of chars (index)
// Now we move temp data to real charSet (passed as parameter to the function) // Now we move temp data to real charSet (passed as parameter to the function)
(*charSet) = (Character *)malloc(index * sizeof(Character)); // BE CAREFUL! This memory should be freed! (*charSet) = (Character *)malloc(index * sizeof(Character)); // BE CAREFUL! This memory should be freed!
@ -531,7 +531,7 @@ static SpriteFont LoadRBMF(const char *fileName)
short imgHeight; // Image height - always POT (power-of-two) short imgHeight; // Image height - always POT (power-of-two)
short numChars; // Number of characters contained short numChars; // Number of characters contained
short charHeight; // Characters height - the same for all characters short charHeight; // Characters height - the same for all characters
char compType; // Compression type: char compType; // Compression type:
// 4 MSB --> image data compression // 4 MSB --> image data compression
// 4 LSB --> chars data compression // 4 LSB --> chars data compression
char charsDataType; // Char data type provided char charsDataType; // Char data type provided
@ -539,42 +539,42 @@ static SpriteFont LoadRBMF(const char *fileName)
SpriteFont spriteFont; SpriteFont spriteFont;
Image image; Image image;
rbmfInfoHeader rbmfHeader; rbmfInfoHeader rbmfHeader;
unsigned int *rbmfFileData; unsigned int *rbmfFileData;
unsigned char *rbmfCharWidthData; unsigned char *rbmfCharWidthData;
int charsDivisor = 1; // Every char is separated from the consecutive by a 1 pixel divisor, horizontally and vertically int charsDivisor = 1; // Every char is separated from the consecutive by a 1 pixel divisor, horizontally and vertically
FILE *rbmfFile = fopen(fileName, "rb"); // Define a pointer to bitmap file and open it in read-binary mode FILE *rbmfFile = fopen(fileName, "rb"); // Define a pointer to bitmap file and open it in read-binary mode
fread(&rbmfHeader, sizeof(rbmfInfoHeader), 1, rbmfFile); fread(&rbmfHeader, sizeof(rbmfInfoHeader), 1, rbmfFile);
TraceLog(INFO, "[%s] Loading rBMF file, size: %ix%i, numChars: %i, charHeight: %i", fileName, rbmfHeader.imgWidth, rbmfHeader.imgHeight, rbmfHeader.numChars, rbmfHeader.charHeight); TraceLog(INFO, "[%s] Loading rBMF file, size: %ix%i, numChars: %i, charHeight: %i", fileName, rbmfHeader.imgWidth, rbmfHeader.imgHeight, rbmfHeader.numChars, rbmfHeader.charHeight);
spriteFont.numChars = (int)rbmfHeader.numChars; spriteFont.numChars = (int)rbmfHeader.numChars;
image.width = (int)rbmfHeader.imgWidth; image.width = (int)rbmfHeader.imgWidth;
image.height = (int)rbmfHeader.imgHeight; image.height = (int)rbmfHeader.imgHeight;
int numPixelBits = rbmfHeader.imgWidth * rbmfHeader.imgHeight / 32; int numPixelBits = rbmfHeader.imgWidth * rbmfHeader.imgHeight / 32;
rbmfFileData = (unsigned int *)malloc(numPixelBits * sizeof(unsigned int)); rbmfFileData = (unsigned int *)malloc(numPixelBits * sizeof(unsigned int));
for(int i = 0; i < numPixelBits; i++) fread(&rbmfFileData[i], sizeof(unsigned int), 1, rbmfFile); for(int i = 0; i < numPixelBits; i++) fread(&rbmfFileData[i], sizeof(unsigned int), 1, rbmfFile);
rbmfCharWidthData = (unsigned char *)malloc(spriteFont.numChars * sizeof(unsigned char)); rbmfCharWidthData = (unsigned char *)malloc(spriteFont.numChars * sizeof(unsigned char));
for(int i = 0; i < spriteFont.numChars; i++) fread(&rbmfCharWidthData[i], sizeof(unsigned char), 1, rbmfFile); for(int i = 0; i < spriteFont.numChars; i++) fread(&rbmfCharWidthData[i], sizeof(unsigned char), 1, rbmfFile);
// Re-construct image from rbmfFileData // Re-construct image from rbmfFileData
//----------------------------------------- //-----------------------------------------
image.pixels = (Color *)malloc(image.width * image.height * sizeof(Color)); image.pixels = (Color *)malloc(image.width * image.height * sizeof(Color));
for (int i = 0; i < image.width * image.height; i++) image.pixels[i] = BLANK; // Initialize array for (int i = 0; i < image.width * image.height; i++) image.pixels[i] = BLANK; // Initialize array
int counter = 0; // Font data elements counter int counter = 0; // Font data elements counter
// Fill image data (convert from bit to pixel!) // Fill image data (convert from bit to pixel!)
for (int i = 0; i < image.width * image.height; i += 32) for (int i = 0; i < image.width * image.height; i += 32)
{ {
@ -582,24 +582,24 @@ static SpriteFont LoadRBMF(const char *fileName)
{ {
if (BIT_CHECK(rbmfFileData[counter], j)) image.pixels[i+j] = WHITE; if (BIT_CHECK(rbmfFileData[counter], j)) image.pixels[i+j] = WHITE;
} }
counter++; counter++;
} }
TraceLog(INFO, "[%s] Image reconstructed correctly, now converting it to texture", fileName); TraceLog(INFO, "[%s] Image reconstructed correctly, now converting it to texture", fileName);
spriteFont.texture = CreateTexture(image, false); spriteFont.texture = CreateTexture(image, false);
UnloadImage(image); // Unload image data UnloadImage(image); // Unload image data
TraceLog(INFO, "[%s] Starting charSet reconstruction", fileName); TraceLog(INFO, "[%s] Starting charSet reconstruction", fileName);
// Reconstruct charSet using rbmfCharWidthData, rbmfHeader.charHeight, charsDivisor, rbmfHeader.numChars // Reconstruct charSet using rbmfCharWidthData, rbmfHeader.charHeight, charsDivisor, rbmfHeader.numChars
spriteFont.charSet = (Character *)malloc(spriteFont.numChars * sizeof(Character)); // Allocate space for our character data spriteFont.charSet = (Character *)malloc(spriteFont.numChars * sizeof(Character)); // Allocate space for our character data
int currentLine = 0; int currentLine = 0;
int currentPosX = charsDivisor; int currentPosX = charsDivisor;
int testPosX = charsDivisor; int testPosX = charsDivisor;
for (int i = 0; i < spriteFont.numChars; i++) for (int i = 0; i < spriteFont.numChars; i++)
{ {
spriteFont.charSet[i].value = (int)rbmfHeader.firstChar + i; spriteFont.charSet[i].value = (int)rbmfHeader.firstChar + i;
@ -607,27 +607,27 @@ static SpriteFont LoadRBMF(const char *fileName)
spriteFont.charSet[i].y = charsDivisor + currentLine * ((int)rbmfHeader.charHeight + charsDivisor); spriteFont.charSet[i].y = charsDivisor + currentLine * ((int)rbmfHeader.charHeight + charsDivisor);
spriteFont.charSet[i].w = (int)rbmfCharWidthData[i]; spriteFont.charSet[i].w = (int)rbmfCharWidthData[i];
spriteFont.charSet[i].h = (int)rbmfHeader.charHeight; spriteFont.charSet[i].h = (int)rbmfHeader.charHeight;
testPosX += (spriteFont.charSet[i].w + charsDivisor); testPosX += (spriteFont.charSet[i].w + charsDivisor);
if (testPosX > spriteFont.texture.width) if (testPosX > spriteFont.texture.width)
{ {
currentLine++; currentLine++;
currentPosX = 2 * charsDivisor + (int)rbmfCharWidthData[i]; currentPosX = 2 * charsDivisor + (int)rbmfCharWidthData[i];
testPosX = currentPosX; testPosX = currentPosX;
spriteFont.charSet[i].x = charsDivisor; spriteFont.charSet[i].x = charsDivisor;
spriteFont.charSet[i].y = charsDivisor + currentLine * (rbmfHeader.charHeight + charsDivisor); spriteFont.charSet[i].y = charsDivisor + currentLine * (rbmfHeader.charHeight + charsDivisor);
} }
else currentPosX = testPosX; else currentPosX = testPosX;
} }
TraceLog(INFO, "[%s] rBMF file loaded correctly as SpriteFont", fileName); TraceLog(INFO, "[%s] rBMF file loaded correctly as SpriteFont", fileName);
fclose(rbmfFile); fclose(rbmfFile);
free(rbmfFileData); // Now we can free loaded data from RAM memory free(rbmfFileData); // Now we can free loaded data from RAM memory
free(rbmfCharWidthData); free(rbmfCharWidthData);
return spriteFont; return spriteFont;
} }
@ -636,8 +636,8 @@ static SpriteFont LoadRBMF(const char *fileName)
static SpriteFont GenerateFromTTF(const char *fileName, int fontSize) static SpriteFont GenerateFromTTF(const char *fileName, int fontSize)
{ {
SpriteFont font; SpriteFont font;
// TODO: Load TTF and generate bitmap font and chars data // TODO: Load TTF and generate bitmap font and chars data
return font; return font;
} }

View file

@ -3,20 +3,20 @@
* raylib.textures * raylib.textures
* *
* Basic functions to load and draw Textures (2d) * Basic functions to load and draw Textures (2d)
* *
* Uses external lib: * Uses external lib:
* stb_image - Multiple formats image loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC) * stb_image - Multiple formats image loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC)
* *
* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) * Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
* *
* Permission is granted to anyone to use this software for any purpose, including commercial * Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions: * applications, and to alter it and redistribute it freely, subject to the following restrictions:
* *
* 1. The origin of this software must not be misrepresented; you must not claim that you * 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment * wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required. * in the product documentation would be appreciated but is not required.
* *
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
@ -83,12 +83,12 @@ static ImageEx LoadDDS(const char *fileName);
Image LoadImage(const char *fileName) Image LoadImage(const char *fileName)
{ {
Image image; Image image;
// Initial values // Initial values
image.pixels = NULL; image.pixels = NULL;
image.width = 0; image.width = 0;
image.height = 0; image.height = 0;
if ((strcmp(GetExtension(fileName),"png") == 0) || if ((strcmp(GetExtension(fileName),"png") == 0) ||
(strcmp(GetExtension(fileName),"bmp") == 0) || (strcmp(GetExtension(fileName),"bmp") == 0) ||
(strcmp(GetExtension(fileName),"tga") == 0) || (strcmp(GetExtension(fileName),"tga") == 0) ||
@ -96,22 +96,22 @@ Image LoadImage(const char *fileName)
(strcmp(GetExtension(fileName),"gif") == 0) || (strcmp(GetExtension(fileName),"gif") == 0) ||
(strcmp(GetExtension(fileName),"psd") == 0) || (strcmp(GetExtension(fileName),"psd") == 0) ||
(strcmp(GetExtension(fileName),"pic") == 0)) (strcmp(GetExtension(fileName),"pic") == 0))
{ {
int imgWidth; int imgWidth;
int imgHeight; int imgHeight;
int imgBpp; int imgBpp;
// NOTE: Using stb_image to load images (Supports: BMP, TGA, PNG, JPG, ...) // NOTE: Using stb_image to load images (Supports: BMP, TGA, PNG, JPG, ...)
// Force loading to 4 components (RGBA) // Force loading to 4 components (RGBA)
byte *imgData = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 4); byte *imgData = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 4);
if (imgData != NULL) if (imgData != NULL)
{ {
// Convert array to pixel array for working convenience // Convert array to pixel array for working convenience
image.pixels = (Color *)malloc(imgWidth * imgHeight * sizeof(Color)); image.pixels = (Color *)malloc(imgWidth * imgHeight * sizeof(Color));
int pix = 0; int pix = 0;
for (int i = 0; i < (imgWidth * imgHeight * 4); i += 4) for (int i = 0; i < (imgWidth * imgHeight * 4); i += 4)
{ {
image.pixels[pix].r = imgData[i]; image.pixels[pix].r = imgData[i];
@ -120,12 +120,12 @@ Image LoadImage(const char *fileName)
image.pixels[pix].a = imgData[i+3]; image.pixels[pix].a = imgData[i+3];
pix++; pix++;
} }
stbi_image_free(imgData); stbi_image_free(imgData);
image.width = imgWidth; image.width = imgWidth;
image.height = imgHeight; image.height = imgHeight;
TraceLog(INFO, "[%s] Image loaded successfully", fileName); TraceLog(INFO, "[%s] Image loaded successfully", fileName);
} }
else TraceLog(WARNING, "[%s] Image could not be loaded", fileName); else TraceLog(WARNING, "[%s] Image could not be loaded", fileName);
@ -133,17 +133,17 @@ Image LoadImage(const char *fileName)
else if (strcmp(GetExtension(fileName),"dds") == 0) else if (strcmp(GetExtension(fileName),"dds") == 0)
{ {
// NOTE: DDS uncompressed images can also be loaded (discarding mipmaps...) // NOTE: DDS uncompressed images can also be loaded (discarding mipmaps...)
ImageEx imageDDS = LoadDDS(fileName); ImageEx imageDDS = LoadDDS(fileName);
if (imageDDS.compFormat == 0) if (imageDDS.compFormat == 0)
{ {
image.pixels = (Color *)malloc(imageDDS.width * imageDDS.height * sizeof(Color)); image.pixels = (Color *)malloc(imageDDS.width * imageDDS.height * sizeof(Color));
image.width = imageDDS.width; image.width = imageDDS.width;
image.height = imageDDS.height; image.height = imageDDS.height;
int pix = 0; int pix = 0;
for (int i = 0; i < (image.width * image.height * 4); i += 4) for (int i = 0; i < (image.width * image.height * 4); i += 4)
{ {
image.pixels[pix].r = imageDDS.data[i]; image.pixels[pix].r = imageDDS.data[i];
@ -152,16 +152,16 @@ Image LoadImage(const char *fileName)
image.pixels[pix].a = imageDDS.data[i+3]; image.pixels[pix].a = imageDDS.data[i+3];
pix++; pix++;
} }
free(imageDDS.data); free(imageDDS.data);
TraceLog(INFO, "[%s] Image loaded successfully", fileName); TraceLog(INFO, "[%s] Image loaded successfully", fileName);
} }
else TraceLog(WARNING, "[%s] Compressed image data could not be loaded", fileName); else TraceLog(WARNING, "[%s] Compressed image data could not be loaded", fileName);
} }
else TraceLog(WARNING, "[%s] Image extension not recognized, it can't be loaded", fileName); else TraceLog(WARNING, "[%s] Image extension not recognized, it can't be loaded", fileName);
// ALTERNATIVE: We can load pixel data directly into Color struct pixels array, // ALTERNATIVE: We can load pixel data directly into Color struct pixels array,
// to do that struct data alignment should be the right one (4 byte); it is. // to do that struct data alignment should be the right one (4 byte); it is.
//image.pixels = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 4); //image.pixels = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 4);
@ -172,7 +172,7 @@ Image LoadImage(const char *fileName)
Image LoadImageFromRES(const char *rresName, int resId) Image LoadImageFromRES(const char *rresName, int resId)
{ {
// TODO: rresName could be directly a char array with all the data! --> support it! :P // TODO: rresName could be directly a char array with all the data! --> support it! :P
Image image; Image image;
bool found = false; bool found = false;
@ -180,9 +180,9 @@ Image LoadImageFromRES(const char *rresName, int resId)
unsigned char version; // rRES file version and subversion unsigned char version; // rRES file version and subversion
char useless; // rRES header reserved data char useless; // rRES header reserved data
short numRes; short numRes;
ResInfoHeader infoHeader; ResInfoHeader infoHeader;
FILE *rresFile = fopen(rresName, "rb"); FILE *rresFile = fopen(rresName, "rb");
if (!rresFile) TraceLog(WARNING, "[%s] Could not open raylib resource file", rresName); if (!rresFile) TraceLog(WARNING, "[%s] Could not open raylib resource file", rresName);
@ -195,7 +195,7 @@ Image LoadImageFromRES(const char *rresName, int resId)
fread(&id[3], sizeof(char), 1, rresFile); fread(&id[3], sizeof(char), 1, rresFile);
fread(&version, sizeof(char), 1, rresFile); fread(&version, sizeof(char), 1, rresFile);
fread(&useless, sizeof(char), 1, rresFile); fread(&useless, sizeof(char), 1, rresFile);
if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S')) if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S'))
{ {
TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName); TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName);
@ -204,15 +204,15 @@ Image LoadImageFromRES(const char *rresName, int resId)
{ {
// Read number of resources embedded // Read number of resources embedded
fread(&numRes, sizeof(short), 1, rresFile); fread(&numRes, sizeof(short), 1, rresFile);
for (int i = 0; i < numRes; i++) for (int i = 0; i < numRes; i++)
{ {
fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile); fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile);
if (infoHeader.id == resId) if (infoHeader.id == resId)
{ {
found = true; found = true;
// Check data is of valid IMAGE type // Check data is of valid IMAGE type
if (infoHeader.type == 0) // IMAGE data type if (infoHeader.type == 0) // IMAGE data type
{ {
@ -221,25 +221,25 @@ Image LoadImageFromRES(const char *rresName, int resId)
short imgWidth, imgHeight; short imgWidth, imgHeight;
char colorFormat, mipmaps; char colorFormat, mipmaps;
fread(&imgWidth, sizeof(short), 1, rresFile); // Image width fread(&imgWidth, sizeof(short), 1, rresFile); // Image width
fread(&imgHeight, sizeof(short), 1, rresFile); // Image height fread(&imgHeight, sizeof(short), 1, rresFile); // Image height
fread(&colorFormat, 1, 1, rresFile); // Image data color format (default: RGBA 32 bit) fread(&colorFormat, 1, 1, rresFile); // Image data color format (default: RGBA 32 bit)
fread(&mipmaps, 1, 1, rresFile); // Mipmap images included (default: 0) fread(&mipmaps, 1, 1, rresFile); // Mipmap images included (default: 0)
image.width = (int)imgWidth; image.width = (int)imgWidth;
image.height = (int)imgHeight; image.height = (int)imgHeight;
unsigned char *data = malloc(infoHeader.size); unsigned char *data = malloc(infoHeader.size);
fread(data, infoHeader.size, 1, rresFile); fread(data, infoHeader.size, 1, rresFile);
unsigned char *imgData = DecompressData(data, infoHeader.size, infoHeader.srcSize); unsigned char *imgData = DecompressData(data, infoHeader.size, infoHeader.srcSize);
image.pixels = (Color *)malloc(sizeof(Color)*imgWidth*imgHeight); image.pixels = (Color *)malloc(sizeof(Color)*imgWidth*imgHeight);
int pix = 0; int pix = 0;
for (int i = 0; i < (imgWidth*imgHeight*4); i += 4) for (int i = 0; i < (imgWidth*imgHeight*4); i += 4)
{ {
image.pixels[pix].r = imgData[i]; image.pixels[pix].r = imgData[i];
@ -248,11 +248,11 @@ Image LoadImageFromRES(const char *rresName, int resId)
image.pixels[pix].a = imgData[i+3]; image.pixels[pix].a = imgData[i+3];
pix++; pix++;
} }
free(imgData); free(imgData);
free(data); free(data);
TraceLog(INFO, "[%s] Image loaded successfully from resource, size: %ix%i", rresName, image.width, image.height); TraceLog(INFO, "[%s] Image loaded successfully from resource, size: %ix%i", rresName, image.width, image.height);
} }
else else
@ -272,18 +272,18 @@ Image LoadImageFromRES(const char *rresName, int resId)
case 4: break; // RAW: No parameters case 4: break; // RAW: No parameters
default: break; default: break;
} }
// Jump DATA to read next infoHeader // Jump DATA to read next infoHeader
fseek(rresFile, infoHeader.size, SEEK_CUR); fseek(rresFile, infoHeader.size, SEEK_CUR);
} }
} }
} }
fclose(rresFile); fclose(rresFile);
} }
if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId); if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId);
return image; return image;
} }
@ -295,7 +295,7 @@ Texture2D LoadTexture(const char *fileName)
if (strcmp(GetExtension(fileName),"dds") == 0) if (strcmp(GetExtension(fileName),"dds") == 0)
{ {
ImageEx image = LoadDDS(fileName); ImageEx image = LoadDDS(fileName);
if (image.compFormat == 0) if (image.compFormat == 0)
{ {
texture.id = rlglLoadTexture(image.data, image.width, image.height, false); texture.id = rlglLoadTexture(image.data, image.width, image.height, false);
@ -306,26 +306,26 @@ Texture2D LoadTexture(const char *fileName)
texture.id = rlglLoadCompressedTexture(image.data, image.width, image.height, image.mipmaps, image.compFormat); texture.id = rlglLoadCompressedTexture(image.data, image.width, image.height, image.mipmaps, image.compFormat);
#endif #endif
} }
texture.width = image.width; texture.width = image.width;
texture.height = image.height; texture.height = image.height;
if (texture.id == 0) TraceLog(WARNING, "[%s] DDS texture could not be loaded", fileName); if (texture.id == 0) TraceLog(WARNING, "[%s] DDS texture could not be loaded", fileName);
else TraceLog(INFO, "[%s] DDS texture loaded successfully", fileName); else TraceLog(INFO, "[%s] DDS texture loaded successfully", fileName);
free(image.data); free(image.data);
} }
else else
{ {
Image image = LoadImage(fileName); Image image = LoadImage(fileName);
if (image.pixels != NULL) if (image.pixels != NULL)
{ {
texture = CreateTexture(image, false); texture = CreateTexture(image, false);
UnloadImage(image); UnloadImage(image);
} }
} }
return texture; return texture;
} }
@ -337,7 +337,7 @@ Texture2D LoadTextureFromRES(const char *rresName, int resId)
Image image = LoadImageFromRES(rresName, resId); Image image = LoadImageFromRES(rresName, resId);
texture = CreateTexture(image, false); texture = CreateTexture(image, false);
UnloadImage(image); UnloadImage(image);
return texture; return texture;
} }
@ -371,7 +371,7 @@ void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float sc
Rectangle sourceRec = { 0, 0, texture.width, texture.height }; Rectangle sourceRec = { 0, 0, texture.width, texture.height };
Rectangle destRec = { (int)position.x, (int)position.y, texture.width*scale, texture.height*scale }; Rectangle destRec = { (int)position.x, (int)position.y, texture.width*scale, texture.height*scale };
Vector2 origin = { 0, 0 }; Vector2 origin = { 0, 0 };
DrawTexturePro(texture, sourceRec, destRec, origin, rotation, tint); DrawTexturePro(texture, sourceRec, destRec, origin, rotation, tint);
} }
@ -380,7 +380,7 @@ void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Co
{ {
Rectangle destRec = { (int)position.x, (int)position.y, sourceRec.width, sourceRec.height }; Rectangle destRec = { (int)position.x, (int)position.y, sourceRec.width, sourceRec.height };
Vector2 origin = { 0, 0 }; Vector2 origin = { 0, 0 };
DrawTexturePro(texture, sourceRec, destRec, origin, 0, tint); DrawTexturePro(texture, sourceRec, destRec, origin, 0, tint);
} }
@ -389,34 +389,34 @@ void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Co
void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint) void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint)
{ {
rlEnableTexture(texture.id); rlEnableTexture(texture.id);
rlPushMatrix(); rlPushMatrix();
rlTranslatef(destRec.x, destRec.y, 0); rlTranslatef(destRec.x, destRec.y, 0);
rlRotatef(rotation, 0, 0, 1); rlRotatef(rotation, 0, 0, 1);
rlTranslatef(-origin.x, -origin.y, 0); rlTranslatef(-origin.x, -origin.y, 0);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(tint.r, tint.g, tint.b, tint.a); rlColor4ub(tint.r, tint.g, tint.b, tint.a);
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer
// Bottom-left corner for texture and quad // Bottom-left corner for texture and quad
rlTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height); rlTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height);
rlVertex2f(0.0f, 0.0f); rlVertex2f(0.0f, 0.0f);
// Bottom-right corner for texture and quad // Bottom-right corner for texture and quad
rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
rlVertex2f(0.0f, destRec.height); rlVertex2f(0.0f, destRec.height);
// Top-right corner for texture and quad // Top-right corner for texture and quad
rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
rlVertex2f(destRec.width, destRec.height); rlVertex2f(destRec.width, destRec.height);
// Top-left corner for texture and quad // Top-left corner for texture and quad
rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height); rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height);
rlVertex2f(destRec.width, 0.0f); rlVertex2f(destRec.width, 0.0f);
rlEnd(); rlEnd();
rlPopMatrix(); rlPopMatrix();
rlDisableTexture(); rlDisableTexture();
} }
@ -425,25 +425,25 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V
Texture2D CreateTexture(Image image, bool genMipmaps) Texture2D CreateTexture(Image image, bool genMipmaps)
{ {
Texture2D texture; Texture2D texture;
// Init texture to default values // Init texture to default values
texture.id = 0; texture.id = 0;
texture.width = 0; texture.width = 0;
texture.height = 0; texture.height = 0;
if (image.pixels != NULL) if (image.pixels != NULL)
{ {
unsigned char *imgData = malloc(image.width * image.height * 4); unsigned char *imgData = malloc(image.width * image.height * 4);
int j = 0; int j = 0;
for (int i = 0; i < image.width * image.height * 4; i += 4) for (int i = 0; i < image.width * image.height * 4; i += 4)
{ {
imgData[i] = image.pixels[j].r; imgData[i] = image.pixels[j].r;
imgData[i+1] = image.pixels[j].g; imgData[i+1] = image.pixels[j].g;
imgData[i+2] = image.pixels[j].b; imgData[i+2] = image.pixels[j].b;
imgData[i+3] = image.pixels[j].a; imgData[i+3] = image.pixels[j].a;
j++; j++;
} }
@ -452,24 +452,24 @@ Texture2D CreateTexture(Image image, bool genMipmaps)
texture.width = image.width; texture.width = image.width;
texture.height = image.height; texture.height = image.height;
TraceLog(INFO, "[ID %i] Texture created successfully", texture.id); TraceLog(INFO, "[ID %i] Texture created successfully", texture.id);
free(imgData); free(imgData);
} }
else TraceLog(WARNING, "Texture could not be created, image data is not valid"); else TraceLog(WARNING, "Texture could not be created, image data is not valid");
return texture; return texture;
} }
// Loading DDS image data (compressed or uncompressed) // Loading DDS image data (compressed or uncompressed)
// NOTE: Compressed data loading not supported on OpenGL 1.1 // NOTE: Compressed data loading not supported on OpenGL 1.1
ImageEx LoadDDS(const char *fileName) ImageEx LoadDDS(const char *fileName)
{ {
#define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII #define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII
#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII #define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII
#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII #define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT #ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
#endif #endif
@ -481,7 +481,7 @@ ImageEx LoadDDS(const char *fileName)
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT #ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
#endif #endif
// DDS Pixel Format // DDS Pixel Format
typedef struct { typedef struct {
unsigned int size; unsigned int size;
@ -493,7 +493,7 @@ ImageEx LoadDDS(const char *fileName)
unsigned int bitMask; unsigned int bitMask;
unsigned int aBitMask; unsigned int aBitMask;
} ddsPixelFormat; } ddsPixelFormat;
// DDS Header (124 bytes) // DDS Header (124 bytes)
typedef struct { typedef struct {
unsigned int size; unsigned int size;
@ -511,12 +511,12 @@ ImageEx LoadDDS(const char *fileName)
unsigned int caps4; unsigned int caps4;
unsigned int reserved2; unsigned int reserved2;
} ddsHeader; } ddsHeader;
ImageEx image; ImageEx image;
ddsHeader header; ddsHeader header;
FILE *ddsFile = fopen(fileName, "rb"); FILE *ddsFile = fopen(fileName, "rb");
if (ddsFile == NULL) if (ddsFile == NULL)
{ {
TraceLog(WARNING, "DDS File could not be opened"); TraceLog(WARNING, "DDS File could not be opened");
@ -525,16 +525,16 @@ ImageEx LoadDDS(const char *fileName)
{ {
// Verify the type of file // Verify the type of file
char filecode[4]; char filecode[4];
fread(filecode, 1, 4, ddsFile); fread(filecode, 1, 4, ddsFile);
if (strncmp(filecode, "DDS ", 4) != 0) if (strncmp(filecode, "DDS ", 4) != 0)
{ {
TraceLog(WARNING, "DDS File does not seem to be valid"); TraceLog(WARNING, "DDS File does not seem to be valid");
fclose(ddsFile); fclose(ddsFile);
} }
else else
{ {
// Get the surface descriptor // Get the surface descriptor
fread(&header, sizeof(ddsHeader), 1, ddsFile); fread(&header, sizeof(ddsHeader), 1, ddsFile);
@ -542,25 +542,25 @@ ImageEx LoadDDS(const char *fileName)
TraceLog(DEBUG, "[%s] DDS file pixel format size: %i", fileName, header.ddspf.size); TraceLog(DEBUG, "[%s] DDS file pixel format size: %i", fileName, header.ddspf.size);
TraceLog(DEBUG, "[%s] DDS file pixel format flags: 0x%x", fileName, header.ddspf.flags); TraceLog(DEBUG, "[%s] DDS file pixel format flags: 0x%x", fileName, header.ddspf.flags);
TraceLog(DEBUG, "[%s] DDS file format: 0x%x", fileName, header.ddspf.fourCC); TraceLog(DEBUG, "[%s] DDS file format: 0x%x", fileName, header.ddspf.fourCC);
image.width = header.width; image.width = header.width;
image.height = header.height; image.height = header.height;
image.mipmaps = 1; image.mipmaps = 1;
image.compFormat = 0; image.compFormat = 0;
if (header.ddspf.flags == 0x40 && header.ddspf.rgbBitCount == 24) // DDS_RGB, no compressed if (header.ddspf.flags == 0x40 && header.ddspf.rgbBitCount == 24) // DDS_RGB, no compressed
{ {
image.data = (unsigned char *)malloc(header.width * header.height * 4); image.data = (unsigned char *)malloc(header.width * header.height * 4);
unsigned char *buffer = (unsigned char *)malloc(header.width * header.height * 3); unsigned char *buffer = (unsigned char *)malloc(header.width * header.height * 3);
fread(buffer, image.width*image.height*3, 1, ddsFile); fread(buffer, image.width*image.height*3, 1, ddsFile);
unsigned char *src = buffer; unsigned char *src = buffer;
unsigned char *dest = image.data; unsigned char *dest = image.data;
for(int y = 0; y < image.height; y++) for(int y = 0; y < image.height; y++)
{ {
for(int x = 0; x < image.width; x++) for(int x = 0; x < image.width; x++)
{ {
*dest++ = *src++; *dest++ = *src++;
*dest++ = *src++; *dest++ = *src++;
@ -568,49 +568,49 @@ ImageEx LoadDDS(const char *fileName)
*dest++ = 255; *dest++ = 255;
} }
} }
free(buffer); free(buffer);
} }
else if (header.ddspf.flags == 0x41 && header.ddspf.rgbBitCount == 32) // DDS_RGBA, no compressed else if (header.ddspf.flags == 0x41 && header.ddspf.rgbBitCount == 32) // DDS_RGBA, no compressed
{ {
image.data = (unsigned char *)malloc(header.width * header.height * 4); image.data = (unsigned char *)malloc(header.width * header.height * 4);
fread(image.data, image.width*image.height*4, 1, ddsFile); fread(image.data, image.width*image.height*4, 1, ddsFile);
image.mipmaps = 1; image.mipmaps = 1;
image.compFormat = 0; image.compFormat = 0;
} }
else if ((header.ddspf.flags == 0x04) && (header.ddspf.fourCC > 0)) else if ((header.ddspf.flags == 0x04) && (header.ddspf.fourCC > 0))
{ {
#ifdef USE_OPENGL_11 #ifdef USE_OPENGL_11
TraceLog(WARNING, "[%s] DDS image uses compression, not supported by current OpenGL version", fileName); TraceLog(WARNING, "[%s] DDS image uses compression, not supported by current OpenGL version", fileName);
TraceLog(WARNING, "[%s] DDS compressed files require OpenGL 3.2+ or ES 2.0", fileName); TraceLog(WARNING, "[%s] DDS compressed files require OpenGL 3.2+ or ES 2.0", fileName);
fclose(ddsFile); fclose(ddsFile);
#else #else
int bufsize; int bufsize;
// Calculate data size, including all mipmaps // Calculate data size, including all mipmaps
if (header.mipMapCount > 1) bufsize = header.pitchOrLinearSize * 2; if (header.mipMapCount > 1) bufsize = header.pitchOrLinearSize * 2;
else bufsize = header.pitchOrLinearSize; else bufsize = header.pitchOrLinearSize;
image.data = (unsigned char*)malloc(bufsize * sizeof(unsigned char)); image.data = (unsigned char*)malloc(bufsize * sizeof(unsigned char));
fread(image.data, 1, bufsize, ddsFile); fread(image.data, 1, bufsize, ddsFile);
// Close file pointer // Close file pointer
fclose(ddsFile); fclose(ddsFile);
image.mipmaps = header.mipMapCount; image.mipmaps = header.mipMapCount;
image.compFormat = 0; image.compFormat = 0;
switch(header.ddspf.fourCC) switch(header.ddspf.fourCC)
{ {
case FOURCC_DXT1: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; case FOURCC_DXT1: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
case FOURCC_DXT3: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; case FOURCC_DXT3: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;
case FOURCC_DXT5: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; case FOURCC_DXT5: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
default: break; default: break;
} }
// NOTE: Image num color components not required... for now... // NOTE: Image num color components not required... for now...
//if (fourCC == FOURCC_DXT1) image.components = 3; //if (fourCC == FOURCC_DXT1) image.components = 3;
//else image.components = 4; //else image.components = 4;
@ -618,6 +618,6 @@ ImageEx LoadDDS(const char *fileName)
} }
} }
} }
return image; return image;
} }

View file

@ -3,21 +3,21 @@
* raylib.utils * raylib.utils
* *
* Utils Functions Definitions * Utils Functions Definitions
* *
* Uses external libs: * Uses external libs:
* tinfl - zlib DEFLATE algorithm decompression lib * tinfl - zlib DEFLATE algorithm decompression lib
* stb_image_write - PNG writting functions * stb_image_write - PNG writting functions
* *
* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) * Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
* *
* Permission is granted to anyone to use this software for any purpose, including commercial * Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions: * applications, and to alter it and redistribute it freely, subject to the following restrictions:
* *
* 1. The origin of this software must not be misrepresented; you must not claim that you * 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment * wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required. * in the product documentation would be appreciated but is not required.
* *
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented * 2. Altered source versions must be plainly marked as such, and must not be misrepresented
@ -54,10 +54,10 @@ unsigned char *DecompressData(const unsigned char *data, unsigned long compSize,
{ {
int tempUncompSize; int tempUncompSize;
unsigned char *pUncomp; unsigned char *pUncomp;
// Allocate buffer to hold decompressed data // Allocate buffer to hold decompressed data
pUncomp = (mz_uint8 *)malloc((size_t)uncompSize); pUncomp = (mz_uint8 *)malloc((size_t)uncompSize);
// Check correct memory allocation // Check correct memory allocation
if (!pUncomp) if (!pUncomp)
{ {
@ -67,13 +67,13 @@ unsigned char *DecompressData(const unsigned char *data, unsigned long compSize,
{ {
// Decompress data // Decompress data
tempUncompSize = tinfl_decompress_mem_to_mem(pUncomp, (size_t)uncompSize, data, compSize, 1); tempUncompSize = tinfl_decompress_mem_to_mem(pUncomp, (size_t)uncompSize, data, compSize, 1);
if (tempUncompSize == -1) if (tempUncompSize == -1)
{ {
TraceLog(WARNING, "Data decompression failed"); TraceLog(WARNING, "Data decompression failed");
free(pUncomp); free(pUncomp);
} }
if (uncompSize != (int)tempUncompSize) if (uncompSize != (int)tempUncompSize)
{ {
TraceLog(WARNING, "Expected uncompressed size do not match, data may be corrupted"); TraceLog(WARNING, "Expected uncompressed size do not match, data may be corrupted");
@ -83,7 +83,7 @@ unsigned char *DecompressData(const unsigned char *data, unsigned long compSize,
TraceLog(INFO, "Data decompressed successfully from %u bytes to %u bytes", (mz_uint32)compSize, (mz_uint32)tempUncompSize); TraceLog(INFO, "Data decompressed successfully from %u bytes to %u bytes", (mz_uint32)compSize, (mz_uint32)tempUncompSize);
} }
return pUncomp; return pUncomp;
} }
@ -92,7 +92,7 @@ unsigned char *DecompressData(const unsigned char *data, unsigned long compSize,
void WriteBitmap(const char *fileName, unsigned char *imgData, int width, int height) void WriteBitmap(const char *fileName, unsigned char *imgData, int width, int height)
{ {
int filesize = 54 + 3*width*height; int filesize = 54 + 3*width*height;
unsigned char bmpFileHeader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0}; // Standard BMP file header unsigned char bmpFileHeader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0}; // Standard BMP file header
unsigned char bmpInfoHeader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0}; // Standard BMP info header unsigned char bmpInfoHeader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0}; // Standard BMP info header
@ -111,11 +111,11 @@ void WriteBitmap(const char *fileName, unsigned char *imgData, int width, int he
bmpInfoHeader[11] = (unsigned char)(height>>24); bmpInfoHeader[11] = (unsigned char)(height>>24);
FILE *bmpFile = fopen(fileName, "wb"); // Define a pointer to bitmap file and open it in write-binary mode FILE *bmpFile = fopen(fileName, "wb"); // Define a pointer to bitmap file and open it in write-binary mode
// NOTE: fwrite parameters are: data pointer, size in bytes of each element to be written, number of elements, file-to-write pointer // NOTE: fwrite parameters are: data pointer, size in bytes of each element to be written, number of elements, file-to-write pointer
fwrite(bmpFileHeader, sizeof(unsigned char), 14, bmpFile); // Write BMP file header data fwrite(bmpFileHeader, sizeof(unsigned char), 14, bmpFile); // Write BMP file header data
fwrite(bmpInfoHeader, sizeof(unsigned char), 40, bmpFile); // Write BMP info header data fwrite(bmpInfoHeader, sizeof(unsigned char), 40, bmpFile); // Write BMP info header data
// Write pixel data to file // Write pixel data to file
for (int y = 0; y < height ; y++) for (int y = 0; y < height ; y++)
{ {
@ -143,14 +143,14 @@ void TraceLog(int msgType, const char *text, ...)
{ {
va_list args; va_list args;
int traceDebugMsgs = 1; int traceDebugMsgs = 1;
#ifdef DO_NOT_TRACE_DEBUG_MSGS #ifdef DO_NOT_TRACE_DEBUG_MSGS
traceDebugMsgs = 0; traceDebugMsgs = 0;
#endif #endif
// NOTE: If trace log file not set, output redirected to stdout // NOTE: If trace log file not set, output redirected to stdout
if (logstream == NULL) logstream = stdout; if (logstream == NULL) logstream = stdout;
switch(msgType) switch(msgType)
{ {
case INFO: fprintf(logstream, "INFO: "); break; case INFO: fprintf(logstream, "INFO: "); break;
@ -159,16 +159,16 @@ void TraceLog(int msgType, const char *text, ...)
case DEBUG: if (traceDebugMsgs) fprintf(logstream, "DEBUG: "); break; case DEBUG: if (traceDebugMsgs) fprintf(logstream, "DEBUG: "); break;
default: break; default: break;
} }
if ((msgType != DEBUG) || ((msgType == DEBUG) && (traceDebugMsgs))) if ((msgType != DEBUG) || ((msgType == DEBUG) && (traceDebugMsgs)))
{ {
va_start(args, text); va_start(args, text);
vfprintf(logstream, text, args); vfprintf(logstream, text, args);
va_end(args); va_end(args);
fprintf(logstream, "\n"); fprintf(logstream, "\n");
} }
if (msgType == ERROR) exit(1); // If ERROR message, exit program if (msgType == ERROR) exit(1); // If ERROR message, exit program
} }
@ -196,7 +196,7 @@ void RecordMalloc(int mallocType, int mallocSize, const char *msg)
} }
// Get the extension for a filename // Get the extension for a filename
const char *GetExtension(const char *fileName) const char *GetExtension(const char *fileName)
{ {
const char *dot = strrchr(fileName, '.'); const char *dot = strrchr(fileName, '.');
if(!dot || dot == fileName) return ""; if(!dot || dot == fileName) return "";

View file

@ -3,17 +3,17 @@
* raylib.utils * raylib.utils
* *
* Some utility functions: rRES files data decompression * Some utility functions: rRES files data decompression
* *
* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) * Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com)
* *
* This software is provided "as-is", without any express or implied warranty. In no event * 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. * will the authors be held liable for any damages arising from the use of this software.
* *
* Permission is granted to anyone to use this software for any purpose, including commercial * Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions: * applications, and to alter it and redistribute it freely, subject to the following restrictions:
* *
* 1. The origin of this software must not be misrepresented; you must not claim that you * 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment * wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required. * in the product documentation would be appreciated but is not required.
* *
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented * 2. Altered source versions must be plainly marked as such, and must not be misrepresented