Removed useless spaces
This commit is contained in:
parent
222995c32e
commit
d2b98fbb5c
288
src/audio.c
288
src/audio.c
@ -3,21 +3,21 @@
|
||||
* raylib.audio
|
||||
*
|
||||
* Basic functions to manage Audio: InitAudioDevice, LoadAudioFiles, PlayAudioFiles
|
||||
*
|
||||
* Uses external lib:
|
||||
*
|
||||
* Uses external lib:
|
||||
* OpenAL - Audio device management lib
|
||||
* stb_vorbis - Ogg audio files loading
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* 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
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||
* in the product documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||
@ -54,16 +54,16 @@
|
||||
// NOTE: Anything longer than ~10 seconds should be streamed...
|
||||
typedef struct Music {
|
||||
stb_vorbis *stream;
|
||||
|
||||
ALuint buffers[MUSIC_STREAM_BUFFERS];
|
||||
ALuint source;
|
||||
ALenum format;
|
||||
|
||||
|
||||
ALuint buffers[MUSIC_STREAM_BUFFERS];
|
||||
ALuint source;
|
||||
ALenum format;
|
||||
|
||||
int channels;
|
||||
int sampleRate;
|
||||
int totalSamplesLeft;
|
||||
bool loop;
|
||||
|
||||
int totalSamplesLeft;
|
||||
bool loop;
|
||||
|
||||
} Music;
|
||||
|
||||
// Wave file data
|
||||
@ -72,7 +72,7 @@ typedef struct Wave {
|
||||
unsigned int dataSize; // Data size in bytes
|
||||
unsigned int sampleRate;
|
||||
short bitsPerSample;
|
||||
short channels;
|
||||
short channels;
|
||||
} Wave;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
@ -102,22 +102,22 @@ void InitAudioDevice()
|
||||
{
|
||||
// Open and initialize a device with default settings
|
||||
ALCdevice *device = alcOpenDevice(NULL);
|
||||
|
||||
|
||||
if(!device) TraceLog(ERROR, "Could not open audio device");
|
||||
|
||||
ALCcontext *context = alcCreateContext(device, NULL);
|
||||
|
||||
|
||||
if(context == NULL || alcMakeContextCurrent(context) == ALC_FALSE)
|
||||
{
|
||||
if(context != NULL) alcDestroyContext(context);
|
||||
|
||||
|
||||
alcCloseDevice(device);
|
||||
|
||||
|
||||
TraceLog(ERROR, "Could not setup audio context");
|
||||
}
|
||||
|
||||
TraceLog(INFO, "Audio device and context initialized successfully: %s\n", alcGetString(device, ALC_DEVICE_SPECIFIER));
|
||||
|
||||
|
||||
// Listener definition (just for 2D)
|
||||
alListener3f(AL_POSITION, 0, 0, 0);
|
||||
alListener3f(AL_VELOCITY, 0, 0, 0);
|
||||
@ -131,7 +131,7 @@ void CloseAudioDevice()
|
||||
|
||||
ALCdevice *device;
|
||||
ALCcontext *context = alcGetCurrentContext();
|
||||
|
||||
|
||||
if (context == NULL) TraceLog(WARNING, "Could not get current audio context for closing");
|
||||
|
||||
device = alcGetContextsDevice(context);
|
||||
@ -150,41 +150,41 @@ Sound LoadSound(char *fileName)
|
||||
{
|
||||
Sound sound;
|
||||
Wave wave;
|
||||
|
||||
|
||||
// NOTE: The entire file is loaded to memory to play it all at once (no-streaming)
|
||||
|
||||
|
||||
// Audio file loading
|
||||
// NOTE: Buffer space is allocated inside function, Wave must be freed
|
||||
|
||||
|
||||
if (strcmp(GetExtension(fileName),"wav") == 0) wave = LoadWAV(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);
|
||||
|
||||
|
||||
if (wave.data != NULL)
|
||||
{
|
||||
ALenum format = 0;
|
||||
// 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;
|
||||
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;
|
||||
else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16;
|
||||
}
|
||||
|
||||
|
||||
// Create an audio source
|
||||
ALuint source;
|
||||
alGenSources(1, &source); // Generate pointer to audio source
|
||||
|
||||
alSourcef(source, AL_PITCH, 1);
|
||||
alSourcef(source, AL_PITCH, 1);
|
||||
alSourcef(source, AL_GAIN, 1);
|
||||
alSource3f(source, AL_POSITION, 0, 0, 0);
|
||||
alSource3f(source, AL_VELOCITY, 0, 0, 0);
|
||||
alSourcei(source, AL_LOOPING, AL_FALSE);
|
||||
|
||||
|
||||
// Convert loaded data to OpenAL buffer
|
||||
//----------------------------------------
|
||||
ALuint buffer;
|
||||
@ -195,17 +195,17 @@ Sound LoadSound(char *fileName)
|
||||
|
||||
// Attach sound buffer to source
|
||||
alSourcei(source, AL_BUFFER, buffer);
|
||||
|
||||
|
||||
// Unallocate WAV data
|
||||
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);
|
||||
|
||||
|
||||
sound.source = source;
|
||||
sound.buffer = buffer;
|
||||
}
|
||||
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
@ -220,9 +220,9 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
|
||||
unsigned char version; // rRES file version and subversion
|
||||
char useless; // rRES header reserved data
|
||||
short numRes;
|
||||
|
||||
|
||||
ResInfoHeader infoHeader;
|
||||
|
||||
|
||||
FILE *rresFile = fopen(rresName, "rb");
|
||||
|
||||
if (!rresFile) 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(&version, sizeof(char), 1, rresFile);
|
||||
fread(&useless, sizeof(char), 1, rresFile);
|
||||
|
||||
|
||||
if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S'))
|
||||
{
|
||||
TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName);
|
||||
@ -244,11 +244,11 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
|
||||
{
|
||||
// Read number of resources embedded
|
||||
fread(&numRes, sizeof(short), 1, rresFile);
|
||||
|
||||
|
||||
for (int i = 0; i < numRes; i++)
|
||||
{
|
||||
fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile);
|
||||
|
||||
|
||||
if (infoHeader.id == resId)
|
||||
{
|
||||
found = true;
|
||||
@ -258,56 +258,56 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
|
||||
{
|
||||
// TODO: Check data compression type
|
||||
// NOTE: We suppose compression type 2 (DEFLATE - default)
|
||||
|
||||
|
||||
// Reading SOUND parameters
|
||||
Wave wave;
|
||||
short sampleRate, bps;
|
||||
char channels, reserved;
|
||||
|
||||
|
||||
fread(&sampleRate, sizeof(short), 1, rresFile); // Sample rate (frequency)
|
||||
fread(&bps, sizeof(short), 1, rresFile); // Bits per sample
|
||||
fread(&channels, 1, 1, rresFile); // Channels (1 - mono, 2 - stereo)
|
||||
fread(&reserved, 1, 1, rresFile); // <reserved>
|
||||
|
||||
|
||||
wave.sampleRate = sampleRate;
|
||||
wave.dataSize = infoHeader.srcSize;
|
||||
wave.bitsPerSample = bps;
|
||||
wave.channels = (short)channels;
|
||||
|
||||
|
||||
unsigned char *data = malloc(infoHeader.size);
|
||||
|
||||
fread(data, infoHeader.size, 1, rresFile);
|
||||
|
||||
|
||||
wave.data = DecompressData(data, infoHeader.size, infoHeader.srcSize);
|
||||
|
||||
|
||||
free(data);
|
||||
|
||||
|
||||
// Convert wave to Sound (OpenAL)
|
||||
ALenum format = 0;
|
||||
|
||||
|
||||
// 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;
|
||||
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;
|
||||
else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Create an audio source
|
||||
ALuint source;
|
||||
alGenSources(1, &source); // Generate pointer to audio source
|
||||
|
||||
alSourcef(source, AL_PITCH, 1);
|
||||
alSourcef(source, AL_PITCH, 1);
|
||||
alSourcef(source, AL_GAIN, 1);
|
||||
alSource3f(source, AL_POSITION, 0, 0, 0);
|
||||
alSource3f(source, AL_VELOCITY, 0, 0, 0);
|
||||
alSourcei(source, AL_LOOPING, AL_FALSE);
|
||||
|
||||
|
||||
// Convert loaded data to OpenAL buffer
|
||||
//----------------------------------------
|
||||
ALuint buffer;
|
||||
@ -318,12 +318,12 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
|
||||
|
||||
// Attach sound buffer to source
|
||||
alSourcei(source, AL_BUFFER, buffer);
|
||||
|
||||
|
||||
// Unallocate WAV data
|
||||
UnloadWave(wave);
|
||||
|
||||
TraceLog(INFO, "[%s] Sound loaded successfully from resource, sample rate: %i", rresName, (int)sampleRate);
|
||||
|
||||
|
||||
sound.source = source;
|
||||
sound.buffer = buffer;
|
||||
}
|
||||
@ -344,18 +344,18 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
|
||||
case 4: break; // RAW: No parameters
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
// Jump DATA to read next infoHeader
|
||||
fseek(rresFile, infoHeader.size, SEEK_CUR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fclose(rresFile);
|
||||
}
|
||||
|
||||
|
||||
if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId);
|
||||
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
@ -370,7 +370,7 @@ void UnloadSound(Sound sound)
|
||||
void PlaySound(Sound sound)
|
||||
{
|
||||
alSourcePlay(sound.source); // Play the sound
|
||||
|
||||
|
||||
//TraceLog(INFO, "Playing sound");
|
||||
|
||||
// Find the current position of the sound being played
|
||||
@ -380,7 +380,7 @@ void PlaySound(Sound sound)
|
||||
//
|
||||
//int sampleRate;
|
||||
//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
|
||||
//or
|
||||
//float result;
|
||||
@ -404,10 +404,10 @@ bool SoundIsPlaying(Sound sound)
|
||||
{
|
||||
bool playing = false;
|
||||
ALint state;
|
||||
|
||||
|
||||
alGetSourcei(sound.source, AL_SOURCE_STATE, &state);
|
||||
if (state == AL_PLAYING) playing = true;
|
||||
|
||||
|
||||
return playing;
|
||||
}
|
||||
|
||||
@ -434,49 +434,49 @@ void PlayMusicStream(char *fileName)
|
||||
{
|
||||
// Stop current music, clean buffers, unload current stream
|
||||
StopMusicStream();
|
||||
|
||||
|
||||
// Open audio stream
|
||||
currentMusic.stream = stb_vorbis_open_filename(fileName, NULL, NULL);
|
||||
|
||||
|
||||
if (currentMusic.stream == NULL) TraceLog(WARNING, "[%s] Could not open ogg audio file", fileName);
|
||||
else
|
||||
{
|
||||
// Get file info
|
||||
stb_vorbis_info info = stb_vorbis_get_info(currentMusic.stream);
|
||||
|
||||
|
||||
currentMusic.channels = info.channels;
|
||||
currentMusic.sampleRate = 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] Temp memory required: %i", fileName, info.temp_memory_required);
|
||||
|
||||
|
||||
if (info.channels == 2) currentMusic.format = AL_FORMAT_STEREO16;
|
||||
else currentMusic.format = AL_FORMAT_MONO16;
|
||||
|
||||
|
||||
currentMusic.loop = true; // We loop by default
|
||||
musicEnabled = true;
|
||||
|
||||
|
||||
// Create an audio source
|
||||
alGenSources(1, ¤tMusic.source); // Generate pointer to audio source
|
||||
|
||||
alSourcef(currentMusic.source, AL_PITCH, 1);
|
||||
alSourcef(currentMusic.source, AL_PITCH, 1);
|
||||
alSourcef(currentMusic.source, AL_GAIN, 1);
|
||||
alSource3f(currentMusic.source, AL_POSITION, 0, 0, 0);
|
||||
alSource3f(currentMusic.source, AL_VELOCITY, 0, 0, 0);
|
||||
//alSourcei(currentMusic.source, AL_LOOPING, AL_TRUE); // ERROR: Buffers do not queue!
|
||||
|
||||
|
||||
// Generate two OpenAL buffers
|
||||
alGenBuffers(2, currentMusic.buffers);
|
||||
|
||||
// Fill buffers with music...
|
||||
BufferMusicStream(currentMusic.buffers[0]);
|
||||
BufferMusicStream(currentMusic.buffers[1]);
|
||||
|
||||
|
||||
// Queue buffers and start playing
|
||||
alSourceQueueBuffers(currentMusic.source, 2, currentMusic.buffers);
|
||||
alSourcePlay(currentMusic.source);
|
||||
|
||||
|
||||
// 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;
|
||||
@ -491,15 +491,15 @@ void StopMusicStream()
|
||||
if (musicEnabled)
|
||||
{
|
||||
alSourceStop(currentMusic.source);
|
||||
|
||||
|
||||
EmptyMusicStream(); // Empty music buffers
|
||||
|
||||
|
||||
alDeleteSources(1, ¤tMusic.source);
|
||||
alDeleteBuffers(2, currentMusic.buffers);
|
||||
|
||||
|
||||
stb_vorbis_close(currentMusic.stream);
|
||||
}
|
||||
|
||||
|
||||
musicEnabled = false;
|
||||
}
|
||||
|
||||
@ -514,9 +514,9 @@ void PauseMusicStream()
|
||||
bool MusicIsPlaying()
|
||||
{
|
||||
ALenum state;
|
||||
|
||||
|
||||
alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
|
||||
|
||||
|
||||
return (state == AL_PLAYING);
|
||||
}
|
||||
|
||||
@ -530,7 +530,7 @@ void SetMusicVolume(float volume)
|
||||
float GetMusicTimeLength()
|
||||
{
|
||||
float totalSeconds = stb_vorbis_stream_length_in_seconds(currentMusic.stream);
|
||||
|
||||
|
||||
return totalSeconds;
|
||||
}
|
||||
|
||||
@ -538,11 +538,11 @@ float GetMusicTimeLength()
|
||||
float GetMusicTimePlayed()
|
||||
{
|
||||
int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels;
|
||||
|
||||
|
||||
int samplesPlayed = totalSamples - currentMusic.totalSamplesLeft;
|
||||
|
||||
|
||||
float secondsPlayed = (float)samplesPlayed / (currentMusic.sampleRate * currentMusic.channels);
|
||||
|
||||
|
||||
return secondsPlayed;
|
||||
}
|
||||
|
||||
@ -553,30 +553,30 @@ float GetMusicTimePlayed()
|
||||
// Fill music buffers with new data from music stream
|
||||
static bool BufferMusicStream(ALuint buffer)
|
||||
{
|
||||
short pcm[MUSIC_BUFFER_SIZE];
|
||||
|
||||
int size = 0; // Total size of data steamed (in bytes)
|
||||
int streamedBytes = 0; // Bytes of data obtained in one samples get
|
||||
|
||||
short pcm[MUSIC_BUFFER_SIZE];
|
||||
|
||||
int size = 0; // Total size of data steamed (in bytes)
|
||||
int streamedBytes = 0; // Bytes of data obtained in one samples get
|
||||
|
||||
bool active = true; // We can get more data from stream (not finished)
|
||||
|
||||
|
||||
if (musicEnabled)
|
||||
{
|
||||
while (size < MUSIC_BUFFER_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);
|
||||
else break;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
currentMusic.totalSamplesLeft -= size;
|
||||
}
|
||||
else
|
||||
@ -585,21 +585,21 @@ static bool BufferMusicStream(ALuint buffer)
|
||||
TraceLog(WARNING, "No more data obtained from stream");
|
||||
}
|
||||
|
||||
return active;
|
||||
return active;
|
||||
}
|
||||
|
||||
// Empty music buffers
|
||||
static void EmptyMusicStream()
|
||||
{
|
||||
ALuint buffer = 0;
|
||||
ALuint buffer = 0;
|
||||
int queued = 0;
|
||||
|
||||
|
||||
alGetSourcei(currentMusic.source, AL_BUFFERS_QUEUED, &queued);
|
||||
|
||||
|
||||
while(queued > 0)
|
||||
{
|
||||
alSourceUnqueueBuffers(currentMusic.source, 1, &buffer);
|
||||
|
||||
|
||||
queued--;
|
||||
}
|
||||
}
|
||||
@ -610,12 +610,12 @@ extern void UpdateMusicStream()
|
||||
ALuint buffer = 0;
|
||||
ALint processed = 0;
|
||||
bool active = true;
|
||||
|
||||
|
||||
if (musicEnabled)
|
||||
{
|
||||
// Get the number of already processed buffers (if any)
|
||||
alGetSourcei(currentMusic.source, AL_BUFFERS_PROCESSED, &processed);
|
||||
|
||||
|
||||
while (processed > 0)
|
||||
{
|
||||
// Recover processed buffer for refill
|
||||
@ -623,32 +623,32 @@ extern void UpdateMusicStream()
|
||||
|
||||
// Refill buffer
|
||||
active = BufferMusicStream(buffer);
|
||||
|
||||
|
||||
// If no more data to stream, restart music (if loop)
|
||||
if ((!active) && (currentMusic.loop))
|
||||
if ((!active) && (currentMusic.loop))
|
||||
{
|
||||
if (currentMusic.loop)
|
||||
{
|
||||
stb_vorbis_seek_start(currentMusic.stream);
|
||||
currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels;
|
||||
|
||||
|
||||
active = BufferMusicStream(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add refilled buffer to queue again... don't let the music stop!
|
||||
alSourceQueueBuffers(currentMusic.source, 1, &buffer);
|
||||
|
||||
|
||||
if(alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Ogg playing, error buffering data...");
|
||||
|
||||
|
||||
processed--;
|
||||
}
|
||||
|
||||
|
||||
ALenum state;
|
||||
alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
|
||||
|
||||
|
||||
if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic.source);
|
||||
|
||||
|
||||
if (!active) StopMusicStream();
|
||||
}
|
||||
}
|
||||
@ -678,16 +678,16 @@ static Wave LoadWAV(const char *fileName)
|
||||
char subChunkID[4];
|
||||
long subChunkSize;
|
||||
} WaveData;
|
||||
|
||||
|
||||
RiffHeader riffHeader;
|
||||
WaveFormat waveFormat;
|
||||
WaveData waveData;
|
||||
|
||||
|
||||
Wave wave;
|
||||
FILE *wavFile;
|
||||
|
||||
|
||||
wavFile = fopen(fileName, "rb");
|
||||
|
||||
|
||||
if (!wavFile)
|
||||
{
|
||||
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
|
||||
fread(&riffHeader, sizeof(RiffHeader), 1, wavFile);
|
||||
|
||||
|
||||
// Check for RIFF and WAVE tags
|
||||
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')))
|
||||
@ -707,7 +707,7 @@ static Wave LoadWAV(const char *fileName)
|
||||
{
|
||||
// Read in the 2nd chunk for the wave info
|
||||
fread(&waveFormat, sizeof(WaveFormat), 1, wavFile);
|
||||
|
||||
|
||||
// Check for fmt tag
|
||||
if ((waveFormat.subChunkID[0] != 'f') || (waveFormat.subChunkID[1] != 'm') ||
|
||||
(waveFormat.subChunkID[2] != 't') || (waveFormat.subChunkID[3] != ' '))
|
||||
@ -718,10 +718,10 @@ static Wave LoadWAV(const char *fileName)
|
||||
{
|
||||
// Check for extra parameters;
|
||||
if (waveFormat.subChunkSize > 16) fseek(wavFile, sizeof(short), SEEK_CUR);
|
||||
|
||||
|
||||
// Read in the the last byte of data before the sound file
|
||||
fread(&waveData, sizeof(WaveData), 1, wavFile);
|
||||
|
||||
|
||||
// Check for data tag
|
||||
if ((waveData.subChunkID[0] != 'd') || (waveData.subChunkID[1] != 'a') ||
|
||||
(waveData.subChunkID[2] != 't') || (waveData.subChunkID[3] != 'a'))
|
||||
@ -731,17 +731,17 @@ static Wave LoadWAV(const char *fileName)
|
||||
else
|
||||
{
|
||||
// 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
|
||||
fread(wave.data, waveData.subChunkSize, 1, wavFile);
|
||||
|
||||
|
||||
// Now we set the variables that we need later
|
||||
wave.dataSize = waveData.subChunkSize;
|
||||
wave.sampleRate = waveFormat.sampleRate;
|
||||
wave.channels = waveFormat.numChannels;
|
||||
wave.bitsPerSample = waveFormat.bitsPerSample;
|
||||
|
||||
|
||||
TraceLog(INFO, "[%s] Wave file loaded successfully", fileName);
|
||||
}
|
||||
}
|
||||
@ -749,7 +749,7 @@ static Wave LoadWAV(const char *fileName)
|
||||
|
||||
fclose(wavFile);
|
||||
}
|
||||
|
||||
|
||||
return wave;
|
||||
}
|
||||
|
||||
@ -757,42 +757,42 @@ static Wave LoadWAV(const char *fileName)
|
||||
static Wave LoadOGG(char *fileName)
|
||||
{
|
||||
Wave wave;
|
||||
|
||||
|
||||
stb_vorbis *oggFile = stb_vorbis_open_filename(fileName, NULL, NULL);
|
||||
stb_vorbis_info info = stb_vorbis_get_info(oggFile);
|
||||
|
||||
|
||||
wave.sampleRate = info.sample_rate;
|
||||
wave.bitsPerSample = 16;
|
||||
wave.channels = info.channels;
|
||||
|
||||
|
||||
TraceLog(DEBUG, "[%s] Ogg sample rate: %i", fileName, info.sample_rate);
|
||||
TraceLog(DEBUG, "[%s] Ogg channels: %i", fileName, info.channels);
|
||||
|
||||
int totalSamplesLength = (stb_vorbis_stream_length_in_samples(oggFile) * info.channels);
|
||||
|
||||
|
||||
wave.dataSize = totalSamplesLength*sizeof(short); // Size must be in bytes
|
||||
|
||||
|
||||
TraceLog(DEBUG, "[%s] Samples length: %i", fileName, totalSamplesLength);
|
||||
|
||||
|
||||
float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
int totalSamples = totalSeconds*info.sample_rate*info.channels;
|
||||
|
||||
|
||||
TraceLog(DEBUG, "[%s] Total samples calculated: %i", fileName, totalSamples);
|
||||
|
||||
//short *data
|
||||
|
||||
//short *data
|
||||
wave.data = malloc(sizeof(short)*totalSamplesLength);
|
||||
|
||||
int samplesObtained = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, wave.data, totalSamplesLength);
|
||||
|
||||
|
||||
TraceLog(DEBUG, "[%s] Samples obtained: %i", fileName, samplesObtained);
|
||||
|
||||
stb_vorbis_close(oggFile);
|
||||
|
||||
|
||||
return wave;
|
||||
}
|
||||
|
||||
|
196
src/core.c
196
src/core.c
@ -3,20 +3,20 @@
|
||||
* raylib.core
|
||||
*
|
||||
* Basic functions to manage Windows, OpenGL context and Input
|
||||
*
|
||||
* Uses external lib:
|
||||
*
|
||||
* Uses external lib:
|
||||
* GLFW3 - Window, context and Input management (static lib version)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* 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
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||
* in the product documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||
@ -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)
|
||||
{
|
||||
glfwSetErrorCallback(ErrorCallback);
|
||||
|
||||
|
||||
if (!glfwInit()) TraceLog(ERROR, "Failed to initialize GLFW");
|
||||
|
||||
|
||||
//glfwDefaultWindowHints() // Set default windows hints
|
||||
|
||||
|
||||
if (!resizable) glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable
|
||||
|
||||
#ifdef USE_OPENGL_33
|
||||
@ -137,20 +137,20 @@ void InitWindowEx(int width, int height, const char* title, bool resizable, cons
|
||||
#endif
|
||||
|
||||
window = glfwCreateWindow(width, height, title, NULL, NULL);
|
||||
|
||||
|
||||
windowWidth = width;
|
||||
windowHeight = height;
|
||||
windowTitle = title;
|
||||
|
||||
|
||||
if (!window)
|
||||
{
|
||||
glfwTerminate();
|
||||
TraceLog(ERROR, "Failed to initialize Window");
|
||||
}
|
||||
|
||||
|
||||
glfwSetWindowSizeCallback(window, WindowSizeCallback);
|
||||
glfwSetCursorEnterCallback(window, CursorEnterCallback);
|
||||
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSetKeyCallback(window, KeyCallback);
|
||||
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
|
||||
// Framerate can be setup using SetTargetFPS()
|
||||
|
||||
//------------------------------------------------------
|
||||
//------------------------------------------------------
|
||||
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
|
||||
rlglInit(); // Init rlgl
|
||||
#endif
|
||||
//------------------------------------------------------
|
||||
|
||||
|
||||
int fbWidth, fbHeight;
|
||||
glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window
|
||||
|
||||
//------------------------------------------------------
|
||||
//------------------------------------------------------
|
||||
rlglInitGraphicsDevice(fbWidth, fbHeight);
|
||||
//------------------------------------------------------
|
||||
|
||||
|
||||
previousTime = glfwGetTime();
|
||||
|
||||
LoadDefaultFont(); // NOTE: External function (defined in module: text)
|
||||
|
||||
|
||||
if (cursorImage != NULL) SetCustomCursor(cursorImage);
|
||||
|
||||
|
||||
srand(time(NULL)); // Initialize random seed
|
||||
|
||||
|
||||
ClearBackground(RAYWHITE); // Default background color for raylib games :P
|
||||
|
||||
|
||||
// raylib logo appearing animation
|
||||
if (showLogo)
|
||||
{
|
||||
@ -193,7 +193,7 @@ void InitWindowEx(int width, int height, const char* title, bool resizable, cons
|
||||
void CloseWindow()
|
||||
{
|
||||
UnloadDefaultFont();
|
||||
|
||||
|
||||
//------------------------------------------------------
|
||||
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
|
||||
rlglClose(); // De-init rlgl
|
||||
@ -208,9 +208,9 @@ void CloseWindow()
|
||||
void SetCustomCursor(const char *cursorImage)
|
||||
{
|
||||
if (customCursor) UnloadTexture(cursor);
|
||||
|
||||
|
||||
cursor = LoadTexture(cursorImage);
|
||||
|
||||
|
||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
|
||||
customCursor = true;
|
||||
}
|
||||
@ -231,14 +231,14 @@ bool WindowShouldClose()
|
||||
// Fullscreen toggle (by default F11)
|
||||
void ToggleFullscreen()
|
||||
{
|
||||
if (glfwGetKey(window, GLFW_KEY_F11))
|
||||
if (glfwGetKey(window, GLFW_KEY_F11))
|
||||
{
|
||||
fullscreen = !fullscreen; // Toggle fullscreen flag
|
||||
|
||||
UnloadDefaultFont();
|
||||
|
||||
|
||||
glfwDestroyWindow(window); // Destroy the current window (we will recreate it!)
|
||||
|
||||
|
||||
// TODO: WARNING! All loaded resources are lost, we loose Context!
|
||||
|
||||
// NOTE: Window aspect ratio is always windowWidth / windowHeight
|
||||
@ -248,7 +248,7 @@ void ToggleFullscreen()
|
||||
//const GLFWvidmode *mode = glfwGetVideoMode(glfwGetPrimaryMonitor());
|
||||
//windowWidth = mode->width;
|
||||
//windowHeight = mode->height;
|
||||
|
||||
|
||||
window = glfwCreateWindow(windowWidth, windowHeight, windowTitle, glfwGetPrimaryMonitor(), NULL); // Fullscreen mode
|
||||
}
|
||||
else window = glfwCreateWindow(windowWidth, windowHeight, windowTitle, NULL, NULL);
|
||||
@ -258,7 +258,7 @@ void ToggleFullscreen()
|
||||
glfwTerminate();
|
||||
TraceLog(ERROR, "Failed to initialize Window when switching fullscreen mode");
|
||||
}
|
||||
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSetKeyCallback(window, KeyCallback);
|
||||
|
||||
@ -266,7 +266,7 @@ void ToggleFullscreen()
|
||||
glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window
|
||||
|
||||
rlglInitGraphicsDevice(fbWidth, fbHeight);
|
||||
|
||||
|
||||
LoadDefaultFont();
|
||||
}
|
||||
}
|
||||
@ -275,9 +275,9 @@ void ToggleFullscreen()
|
||||
void ClearBackground(Color color)
|
||||
{
|
||||
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);
|
||||
|
||||
|
||||
background = color;
|
||||
}
|
||||
}
|
||||
@ -290,7 +290,7 @@ void BeginDrawing()
|
||||
previousTime = currentTime;
|
||||
|
||||
rlClearScreenBuffers();
|
||||
|
||||
|
||||
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
|
||||
|
||||
//#ifdef USE_OPENGL_11
|
||||
@ -309,18 +309,18 @@ void EndDrawing()
|
||||
rlglDraw(); // Draw Buffers
|
||||
#endif
|
||||
//------------------------------------------------------
|
||||
|
||||
|
||||
glfwSwapBuffers(window); // Swap back and front buffers
|
||||
glfwPollEvents(); // Register keyboard/mouse events
|
||||
|
||||
|
||||
UpdateMusicStream(); // NOTE: Function checks if music is enabled
|
||||
|
||||
|
||||
currentTime = glfwGetTime();
|
||||
drawTime = currentTime - previousTime;
|
||||
previousTime = currentTime;
|
||||
|
||||
|
||||
frameTime = updateTime + drawTime;
|
||||
|
||||
|
||||
double extraTime = 0;
|
||||
|
||||
while (frameTime < targetTime)
|
||||
@ -343,20 +343,20 @@ void Begin3dMode(Camera camera)
|
||||
//------------------------------------------------------
|
||||
|
||||
rlMatrixMode(RL_PROJECTION); // Switch to projection matrix
|
||||
|
||||
|
||||
rlPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection
|
||||
rlLoadIdentity(); // Reset current matrix (PROJECTION)
|
||||
|
||||
|
||||
// Setup perspective projection
|
||||
float aspect = (GLfloat)windowWidth/(GLfloat)windowHeight;
|
||||
double top = 0.1f*tan(45.0f*PI / 360.0);
|
||||
double right = top*aspect;
|
||||
|
||||
rlFrustum(-right, right, -top, top, 0.1f, 100.0f);
|
||||
|
||||
|
||||
rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix
|
||||
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
|
||||
|
||||
|
||||
// Setup Camera view
|
||||
Matrix matLookAt = MatrixLookAt(camera.position, camera.target, camera.up);
|
||||
rlMultMatrixf(GetMatrixVector(matLookAt)); // Multiply MODELVIEW matrix by view matrix (camera)
|
||||
@ -373,10 +373,10 @@ void End3dMode()
|
||||
|
||||
rlMatrixMode(RL_PROJECTION); // Switch to projection matrix
|
||||
rlPopMatrix(); // Restore previous matrix (PROJECTION) from matrix stack
|
||||
|
||||
|
||||
rlMatrixMode(RL_MODELVIEW); // Get back to modelview matrix
|
||||
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
|
||||
|
||||
|
||||
//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)
|
||||
{
|
||||
targetTime = 1 / (float)fps;
|
||||
|
||||
|
||||
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
|
||||
// NOTE: There are still problems with high framerates (>500fps)
|
||||
double roundedFrameTime = round(frameTime*10000) / 10000;
|
||||
|
||||
|
||||
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.b = (unsigned char)(hexValue >> 8) & 0xFF;
|
||||
color.a = (unsigned char)hexValue & 0xFF;
|
||||
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
@ -458,7 +458,7 @@ void ShowLogo()
|
||||
|
||||
// Detect if a key has been pressed once
|
||||
bool IsKeyPressed(int key)
|
||||
{
|
||||
{
|
||||
bool pressed = false;
|
||||
|
||||
currentKeyState[key] = IsKeyDown(key);
|
||||
@ -469,7 +469,7 @@ bool IsKeyPressed(int key)
|
||||
previousKeyState[key] = currentKeyState[key];
|
||||
}
|
||||
else pressed = false;
|
||||
|
||||
|
||||
return pressed;
|
||||
}
|
||||
|
||||
@ -482,9 +482,9 @@ bool IsKeyDown(int key)
|
||||
|
||||
// Detect if a key has been released once
|
||||
bool IsKeyReleased(int key)
|
||||
{
|
||||
{
|
||||
bool released = false;
|
||||
|
||||
|
||||
currentKeyState[key] = IsKeyUp(key);
|
||||
|
||||
if (currentKeyState[key] != previousKeyState[key])
|
||||
@ -493,7 +493,7 @@ bool IsKeyReleased(int key)
|
||||
previousKeyState[key] = currentKeyState[key];
|
||||
}
|
||||
else released = false;
|
||||
|
||||
|
||||
return released;
|
||||
}
|
||||
|
||||
@ -517,7 +517,7 @@ bool IsMouseButtonPressed(int button)
|
||||
previousMouseState[button] = currentMouseState[button];
|
||||
}
|
||||
else pressed = false;
|
||||
|
||||
|
||||
return pressed;
|
||||
}
|
||||
|
||||
@ -541,7 +541,7 @@ bool IsMouseButtonReleased(int button)
|
||||
previousMouseState[button] = currentMouseState[button];
|
||||
}
|
||||
else released = false;
|
||||
|
||||
|
||||
return released;
|
||||
}
|
||||
|
||||
@ -557,7 +557,7 @@ int GetMouseX()
|
||||
{
|
||||
double mouseX;
|
||||
double mouseY;
|
||||
|
||||
|
||||
glfwGetCursorPos(window, &mouseX, &mouseY);
|
||||
|
||||
return (int)mouseX;
|
||||
@ -568,7 +568,7 @@ int GetMouseY()
|
||||
{
|
||||
double mouseX;
|
||||
double mouseY;
|
||||
|
||||
|
||||
glfwGetCursorPos(window, &mouseX, &mouseY);
|
||||
|
||||
return (int)mouseY;
|
||||
@ -579,9 +579,9 @@ Vector2 GetMousePosition()
|
||||
{
|
||||
double mouseX;
|
||||
double mouseY;
|
||||
|
||||
|
||||
glfwGetCursorPos(window, &mouseX, &mouseY);
|
||||
|
||||
|
||||
Vector2 position = { (float)mouseX, (float)mouseY };
|
||||
|
||||
return position;
|
||||
@ -593,7 +593,7 @@ int GetMouseWheelMove()
|
||||
previousMouseWheelY = currentMouseWheelY;
|
||||
|
||||
currentMouseWheelY = 0;
|
||||
|
||||
|
||||
return previousMouseWheelY;
|
||||
}
|
||||
|
||||
@ -601,7 +601,7 @@ int GetMouseWheelMove()
|
||||
bool IsGamepadAvailable(int gamepad)
|
||||
{
|
||||
int result = glfwJoystickPresent(gamepad);
|
||||
|
||||
|
||||
if (result == 1) return true;
|
||||
else return false;
|
||||
}
|
||||
@ -610,20 +610,20 @@ bool IsGamepadAvailable(int gamepad)
|
||||
Vector2 GetGamepadMovement(int gamepad)
|
||||
{
|
||||
Vector2 vec = { 0, 0 };
|
||||
|
||||
|
||||
const float *axes;
|
||||
int axisCount;
|
||||
|
||||
|
||||
axes = glfwGetJoystickAxes(gamepad, &axisCount);
|
||||
|
||||
|
||||
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.x = axes[2]; // Right joystick X
|
||||
//vec.x = axes[3]; // Right joystick Y
|
||||
}
|
||||
}
|
||||
|
||||
return vec;
|
||||
}
|
||||
@ -641,7 +641,7 @@ bool IsGamepadButtonPressed(int gamepad, int button)
|
||||
previousGamepadState[button] = currentGamepadState[button];
|
||||
}
|
||||
else pressed = false;
|
||||
|
||||
|
||||
return pressed;
|
||||
}
|
||||
|
||||
@ -649,9 +649,9 @@ bool IsGamepadButtonDown(int gamepad, int button)
|
||||
{
|
||||
const unsigned char* buttons;
|
||||
int buttonsCount;
|
||||
|
||||
|
||||
buttons = glfwGetJoystickButtons(gamepad, &buttonsCount);
|
||||
|
||||
|
||||
if ((buttons != NULL) && (buttons[button] == GLFW_PRESS))
|
||||
{
|
||||
return true;
|
||||
@ -672,7 +672,7 @@ bool IsGamepadButtonReleased(int gamepad, int button)
|
||||
previousGamepadState[button] = currentGamepadState[button];
|
||||
}
|
||||
else released = false;
|
||||
|
||||
|
||||
return released;
|
||||
}
|
||||
|
||||
@ -680,9 +680,9 @@ bool IsGamepadButtonUp(int gamepad, int button)
|
||||
{
|
||||
const unsigned char* buttons;
|
||||
int buttonsCount;
|
||||
|
||||
|
||||
buttons = glfwGetJoystickButtons(gamepad, &buttonsCount);
|
||||
|
||||
|
||||
if ((buttons != NULL) && (buttons[button] == GLFW_RELEASE))
|
||||
{
|
||||
return true;
|
||||
@ -712,7 +712,7 @@ static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, i
|
||||
if (key == exitKey && action == GLFW_PRESS)
|
||||
{
|
||||
glfwSetWindowShouldClose(window, GL_TRUE);
|
||||
|
||||
|
||||
// NOTE: Before closing window, while loop must be left!
|
||||
}
|
||||
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)
|
||||
rlglInitGraphicsDevice(fbWidth, fbHeight);
|
||||
|
||||
|
||||
// Window size must be updated to be used on 3D mode to get new aspect ratio (Begin3dMode())
|
||||
windowWidth = fbWidth;
|
||||
windowHeight = fbHeight;
|
||||
|
||||
|
||||
// Background must be also re-cleared
|
||||
rlClearColor(background.r, background.g, background.b, background.a);
|
||||
}
|
||||
@ -767,7 +767,7 @@ static void TakeScreenshot()
|
||||
free(imgData);
|
||||
|
||||
shotNum++;
|
||||
|
||||
|
||||
TraceLog(INFO, "[%s] Screenshot taken!", buffer);
|
||||
}
|
||||
|
||||
@ -775,20 +775,20 @@ static void LogoAnimation()
|
||||
{
|
||||
int logoPositionX = windowWidth/2 - 128;
|
||||
int logoPositionY = windowHeight/2 - 128;
|
||||
|
||||
|
||||
int framesCounter = 0;
|
||||
int lettersCount = 0;
|
||||
|
||||
|
||||
int topSideRecWidth = 16;
|
||||
int leftSideRecHeight = 16;
|
||||
|
||||
|
||||
int bottomSideRecWidth = 16;
|
||||
int rightSideRecHeight = 16;
|
||||
|
||||
|
||||
char raylib[8] = " "; // raylib text array, max 8 letters
|
||||
int state = 0; // Tracking animation states (State Machine)
|
||||
float alpha = 1.0; // Useful for fading
|
||||
|
||||
|
||||
while (!WindowShouldClose() && (state != 4)) // Detect window close button or ESC key
|
||||
{
|
||||
// Update
|
||||
@ -796,9 +796,9 @@ static void LogoAnimation()
|
||||
if (state == 0) // State 0: Small box blinking
|
||||
{
|
||||
framesCounter++;
|
||||
|
||||
|
||||
if (framesCounter == 84)
|
||||
{
|
||||
{
|
||||
state = 1;
|
||||
framesCounter = 0; // Reset counter... will be used later...
|
||||
}
|
||||
@ -807,26 +807,26 @@ static void LogoAnimation()
|
||||
{
|
||||
topSideRecWidth += 4;
|
||||
leftSideRecHeight += 4;
|
||||
|
||||
|
||||
if (topSideRecWidth == 256) state = 2;
|
||||
}
|
||||
else if (state == 2) // State 2: Bottom and right bars growing
|
||||
{
|
||||
bottomSideRecWidth += 4;
|
||||
rightSideRecHeight += 4;
|
||||
|
||||
|
||||
if (bottomSideRecWidth == 256) state = 3;
|
||||
}
|
||||
else if (state == 3) // State 3: Letters appearing (one by one)
|
||||
{
|
||||
framesCounter++;
|
||||
|
||||
|
||||
if (framesCounter/12) // Every 12 frames, one more letter!
|
||||
{
|
||||
{
|
||||
lettersCount++;
|
||||
framesCounter = 0;
|
||||
}
|
||||
|
||||
|
||||
switch (lettersCount)
|
||||
{
|
||||
case 1: raylib[0] = 'r'; break;
|
||||
@ -837,11 +837,11 @@ static void LogoAnimation()
|
||||
case 6: raylib[5] = 'b'; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
if (lettersCount >= 10) // When all letters have appeared, just fade out everything
|
||||
{
|
||||
alpha -= 0.02;
|
||||
|
||||
|
||||
if (alpha <= 0)
|
||||
{
|
||||
alpha = 0;
|
||||
@ -850,11 +850,11 @@ static void LogoAnimation()
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Draw
|
||||
//----------------------------------------------------------------------------------
|
||||
BeginDrawing();
|
||||
|
||||
|
||||
if (state == 0)
|
||||
{
|
||||
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, 16, leftSideRecHeight, BLACK);
|
||||
|
||||
|
||||
DrawRectangle(logoPositionX + 240, logoPositionY, 16, rightSideRecHeight, 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 + 16, 16, leftSideRecHeight - 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(windowWidth/2 - 112, windowHeight/2 - 112, 224, 224, Fade(RAYWHITE, alpha));
|
||||
|
||||
|
||||
DrawText(raylib, windowWidth/2 - 44, windowHeight/2 + 48, 50, Fade(BLACK, alpha));
|
||||
}
|
||||
|
||||
|
||||
EndDrawing();
|
||||
//----------------------------------------------------------------------------------
|
||||
}
|
||||
|
628
src/models.c
628
src/models.c
File diff suppressed because it is too large
Load Diff
24
src/raylib.h
24
src/raylib.h
@ -1,7 +1,7 @@
|
||||
/*********************************************************************************************
|
||||
*
|
||||
*
|
||||
* raylib 1.1 (www.raylib.com)
|
||||
*
|
||||
*
|
||||
* A simple and easy-to-use library to learn videogames programming
|
||||
*
|
||||
* Features:
|
||||
@ -14,7 +14,7 @@
|
||||
* Basic 3d support for Shapes, Models, Heightmaps and Billboards
|
||||
* Powerful math module for Vector and Matrix operations [raymath]
|
||||
* Audio loading and playing with streaming support
|
||||
*
|
||||
*
|
||||
* Used external libs:
|
||||
* GLFW3 (www.glfw.org) for window/context management and input
|
||||
* GLEW for OpenGL extensions loading (3.3+ and ES2)
|
||||
@ -33,19 +33,19 @@
|
||||
*
|
||||
* -- 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:
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* 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
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||
* in the product documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||
@ -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 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
|
||||
float rotation, Color tint);
|
||||
float rotation, Color tint);
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
// 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 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)
|
||||
|
246
src/raymath.c
246
src/raymath.c
@ -5,15 +5,15 @@
|
||||
* Some useful functions to work with Vector3, Matrix and Quaternions
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* 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
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||
* in the product documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||
@ -51,7 +51,7 @@ Vector3 VectorAdd(Vector3 v1, Vector3 v2)
|
||||
result.x = v1.x + v2.x;
|
||||
result.y = v1.y + v2.y;
|
||||
result.z = v1.z + v2.z;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ Vector3 VectorSubtract(Vector3 v1, Vector3 v2)
|
||||
result.x = v1.x - v2.x;
|
||||
result.y = v1.y - v2.y;
|
||||
result.z = v1.z - v2.z;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ Vector3 VectorCrossProduct(Vector3 v1, Vector3 v2)
|
||||
result.x = v1.y*v2.z - v1.z*v2.y;
|
||||
result.y = v1.z*v2.x - v1.x*v2.z;
|
||||
result.z = v1.x*v2.y - v1.y*v2.x;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -83,23 +83,23 @@ Vector3 VectorCrossProduct(Vector3 v1, Vector3 v2)
|
||||
Vector3 VectorPerpendicular(Vector3 v)
|
||||
{
|
||||
Vector3 result;
|
||||
|
||||
|
||||
float min = fabs(v.x);
|
||||
Vector3 cardinalAxis = {1.0, 0.0, 0.0};
|
||||
|
||||
if (fabs(v.y) < min)
|
||||
|
||||
if (fabs(v.y) < min)
|
||||
{
|
||||
min = fabs(v.y);
|
||||
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};
|
||||
}
|
||||
|
||||
|
||||
result = VectorCrossProduct(v, cardinalAxis);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -107,9 +107,9 @@ Vector3 VectorPerpendicular(Vector3 v)
|
||||
float VectorDotProduct(Vector3 v1, Vector3 v2)
|
||||
{
|
||||
float result;
|
||||
|
||||
|
||||
result = v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -117,9 +117,9 @@ float VectorDotProduct(Vector3 v1, Vector3 v2)
|
||||
float VectorLength(const Vector3 v)
|
||||
{
|
||||
float length;
|
||||
|
||||
|
||||
length = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
|
||||
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
@ -145,11 +145,11 @@ void VectorNormalize(Vector3 *v)
|
||||
float length, ilength;
|
||||
|
||||
length = VectorLength(*v);
|
||||
|
||||
|
||||
if (length == 0) length = 1;
|
||||
|
||||
ilength = 1.0/length;
|
||||
|
||||
|
||||
v->x *= ilength;
|
||||
v->y *= ilength;
|
||||
v->z *= ilength;
|
||||
@ -159,13 +159,13 @@ void VectorNormalize(Vector3 *v)
|
||||
float VectorDistance(Vector3 v1, Vector3 v2)
|
||||
{
|
||||
float result;
|
||||
|
||||
|
||||
float dx = v2.x - v1.x;
|
||||
float dy = v2.y - v1.y;
|
||||
float dz = v2.z - v1.z;
|
||||
|
||||
|
||||
result = sqrt(dx*dx + dy*dy + dz*dz);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -173,7 +173,7 @@ float VectorDistance(Vector3 v1, Vector3 v2)
|
||||
Vector3 VectorLerp(Vector3 v1, Vector3 v2, float amount)
|
||||
{
|
||||
Vector3 result;
|
||||
|
||||
|
||||
result.x = v1.x + amount * (v2.x - v1.x);
|
||||
result.y = v1.y + amount * (v2.y - v1.y);
|
||||
result.z = v1.z + amount * (v2.z - v1.z);
|
||||
@ -187,11 +187,11 @@ Vector3 VectorReflect(Vector3 vector, Vector3 normal)
|
||||
// I is the original vector
|
||||
// N is the normal of the incident plane
|
||||
// R = I - (2 * N * ( DotProduct[ I,N] ))
|
||||
|
||||
|
||||
Vector3 result;
|
||||
|
||||
|
||||
float dotProduct = VectorDotProduct(vector, normal);
|
||||
|
||||
|
||||
result.x = vector.x - (2.0 * normal.x) * dotProduct;
|
||||
result.y = vector.y - (2.0 * normal.y) * 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)
|
||||
{
|
||||
float x = v->x;
|
||||
float y = v->y;
|
||||
float y = v->y;
|
||||
float z = v->z;
|
||||
|
||||
|
||||
//MatrixTranspose(&mat);
|
||||
|
||||
|
||||
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->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 zero = { 0.0, 0.0, 0.0 };
|
||||
|
||||
|
||||
return zero;
|
||||
}
|
||||
|
||||
@ -229,7 +229,7 @@ Vector3 VectorZero()
|
||||
float *GetMatrixVector(Matrix mat)
|
||||
{
|
||||
static float vector[16];
|
||||
|
||||
|
||||
vector[0] = mat.m0;
|
||||
vector[1] = mat.m4;
|
||||
vector[2] = mat.m8;
|
||||
@ -246,7 +246,7 @@ float *GetMatrixVector(Matrix mat)
|
||||
vector[13] = mat.m7;
|
||||
vector[14] = mat.m11;
|
||||
vector[15] = mat.m15;
|
||||
|
||||
|
||||
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 +
|
||||
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;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -298,7 +298,7 @@ void MatrixTranspose(Matrix *mat)
|
||||
temp.m13 = mat->m7;
|
||||
temp.m14 = mat->m11;
|
||||
temp.m15 = mat->m15;
|
||||
|
||||
|
||||
*mat = temp;
|
||||
}
|
||||
|
||||
@ -306,13 +306,13 @@ void MatrixTranspose(Matrix *mat)
|
||||
void MatrixInvert(Matrix *mat)
|
||||
{
|
||||
Matrix temp;
|
||||
|
||||
|
||||
// Cache the matrix values (speed optimization)
|
||||
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 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 b00 = a00*a11 - a01*a10;
|
||||
float b01 = a00*a12 - a02*a10;
|
||||
float b02 = a00*a13 - a03*a10;
|
||||
@ -325,12 +325,12 @@ void MatrixInvert(Matrix *mat)
|
||||
float b09 = a21*a32 - a22*a31;
|
||||
float b10 = a21*a33 - a23*a31;
|
||||
float b11 = a22*a33 - a23*a32;
|
||||
|
||||
|
||||
// Calculate the invert determinant (inlined to avoid double-caching)
|
||||
float invDet = 1/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
|
||||
|
||||
|
||||
printf("%f\n", invDet);
|
||||
|
||||
|
||||
temp.m0 = (a11*b11 - a12*b10 + a13*b09)*invDet;
|
||||
temp.m1 = (-a01*b11 + a02*b10 - a03*b09)*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.m14 = (-a30*b03 + a31*b01 - a32*b00)*invDet;
|
||||
temp.m15 = (a20*b03 - a21*b01 + a22*b00)*invDet;
|
||||
|
||||
|
||||
PrintMatrix(temp);
|
||||
|
||||
|
||||
*mat = temp;
|
||||
}
|
||||
|
||||
@ -357,7 +357,7 @@ void MatrixInvert(Matrix *mat)
|
||||
void MatrixNormalize(Matrix *mat)
|
||||
{
|
||||
float det = MatrixDeterminant(*mat);
|
||||
|
||||
|
||||
mat->m0 /= det;
|
||||
mat->m1 /= det;
|
||||
mat->m2 /= det;
|
||||
@ -388,7 +388,7 @@ Matrix MatrixIdentity()
|
||||
Matrix MatrixAdd(Matrix left, Matrix right)
|
||||
{
|
||||
Matrix result = MatrixIdentity();
|
||||
|
||||
|
||||
result.m0 = left.m0 + right.m0;
|
||||
result.m1 = left.m1 + right.m1;
|
||||
result.m2 = left.m2 + right.m2;
|
||||
@ -413,7 +413,7 @@ Matrix MatrixAdd(Matrix left, Matrix right)
|
||||
Matrix MatrixSubstract(Matrix left, Matrix right)
|
||||
{
|
||||
Matrix result = MatrixIdentity();
|
||||
|
||||
|
||||
result.m0 = left.m0 - right.m0;
|
||||
result.m1 = left.m1 - right.m1;
|
||||
result.m2 = left.m2 - right.m2;
|
||||
@ -444,36 +444,36 @@ Matrix MatrixTranslate(float x, float y, float z)
|
||||
0, 1, 0, 0
|
||||
0, 0, 1, 0
|
||||
x, y, z, 1
|
||||
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.
|
||||
Row major is used in most math text-books and also DirectX, so it is a common
|
||||
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.
|
||||
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.
|
||||
|
||||
|
||||
* 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:
|
||||
{ 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?
|
||||
|
||||
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
|
||||
of the 16-element matrix, where indices are numbered from 1 to 16 as described in section
|
||||
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
|
||||
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.
|
||||
|
||||
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.
|
||||
The OpenGL Specification and the OpenGL Reference Manual both use column-major notation.
|
||||
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.
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
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 };
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -482,50 +482,50 @@ Matrix MatrixTranslate(float x, float y, float z)
|
||||
Matrix MatrixRotate(float angleX, float angleY, float angleZ)
|
||||
{
|
||||
Matrix result;
|
||||
|
||||
|
||||
Matrix rotX = MatrixRotateX(angleX);
|
||||
Matrix rotY = MatrixRotateY(angleY);
|
||||
Matrix rotZ = MatrixRotateZ(angleZ);
|
||||
|
||||
|
||||
result = MatrixMultiply(MatrixMultiply(rotX, rotY), rotZ);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Create rotation matrix from axis and angle
|
||||
// TODO: Test this function
|
||||
Matrix MatrixFromAxisAngle(Vector3 axis, float angle)
|
||||
Matrix MatrixFromAxisAngle(Vector3 axis, float angle)
|
||||
{
|
||||
Matrix result;
|
||||
|
||||
|
||||
Matrix mat = MatrixIdentity();
|
||||
|
||||
float x = axis.x, y = axis.y, z = axis.z;
|
||||
|
||||
|
||||
float length = sqrt(x*x + y*y + z*z);
|
||||
|
||||
|
||||
if ((length != 1) && (length != 0))
|
||||
{
|
||||
length = 1 / length;
|
||||
x *= length;
|
||||
y *= length;
|
||||
x *= length;
|
||||
y *= length;
|
||||
z *= length;
|
||||
}
|
||||
|
||||
|
||||
float s = sin(angle);
|
||||
float c = cos(angle);
|
||||
float t = 1-c;
|
||||
|
||||
|
||||
// Cache some matrix values (speed optimization)
|
||||
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 a20 = mat.m8, a21 = mat.m9, a22 = mat.m10, a23 = mat.m11;
|
||||
|
||||
|
||||
// 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 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;
|
||||
|
||||
|
||||
// Perform rotation-specific matrix multiplication
|
||||
result.m0 = a00*b00 + a10*b01 + a20*b02;
|
||||
result.m1 = a01*b00 + a11*b01 + a21*b02;
|
||||
@ -543,7 +543,7 @@ Matrix MatrixFromAxisAngle(Vector3 axis, float angle)
|
||||
result.m13 = mat.m13;
|
||||
result.m14 = mat.m14;
|
||||
result.m15 = mat.m15;
|
||||
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
@ -552,7 +552,7 @@ Matrix MatrixFromAxisAngle(Vector3 axis, float angle)
|
||||
Matrix MatrixFromAxisAngle2(Vector3 axis, float angle)
|
||||
{
|
||||
Matrix result;
|
||||
|
||||
|
||||
VectorNormalize(&axis);
|
||||
float axisX = axis.x, axisY = axis.y, axisZ = axis.y;
|
||||
|
||||
@ -589,7 +589,7 @@ Matrix MatrixFromAxisAngle2(Vector3 axis, float angle)
|
||||
result.m13 = 0;
|
||||
result.m14 = 0;
|
||||
result.m15 = 1;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -597,14 +597,14 @@ Matrix MatrixFromAxisAngle2(Vector3 axis, float angle)
|
||||
Matrix MatrixFromQuaternion(Quaternion q)
|
||||
{
|
||||
Matrix result = MatrixIdentity();
|
||||
|
||||
|
||||
Vector3 axis;
|
||||
float angle;
|
||||
|
||||
|
||||
QuaternionToAxisAngle(q, &axis, &angle);
|
||||
|
||||
|
||||
result = MatrixFromAxisAngle2(axis, angle);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -612,10 +612,10 @@ Matrix MatrixFromQuaternion(Quaternion q)
|
||||
Matrix MatrixRotateX(float angle)
|
||||
{
|
||||
Matrix result = MatrixIdentity();
|
||||
|
||||
|
||||
float cosres = (float)cos(angle);
|
||||
float sinres = (float)sin(angle);
|
||||
|
||||
|
||||
result.m5 = cosres;
|
||||
result.m6 = -sinres;
|
||||
result.m9 = sinres;
|
||||
@ -628,10 +628,10 @@ Matrix MatrixRotateX(float angle)
|
||||
Matrix MatrixRotateY(float angle)
|
||||
{
|
||||
Matrix result = MatrixIdentity();
|
||||
|
||||
|
||||
float cosres = (float)cos(angle);
|
||||
float sinres = (float)sin(angle);
|
||||
|
||||
|
||||
result.m0 = cosres;
|
||||
result.m2 = sinres;
|
||||
result.m8 = -sinres;
|
||||
@ -644,10 +644,10 @@ Matrix MatrixRotateY(float angle)
|
||||
Matrix MatrixRotateZ(float angle)
|
||||
{
|
||||
Matrix result = MatrixIdentity();
|
||||
|
||||
|
||||
float cosres = (float)cos(angle);
|
||||
float sinres = (float)sin(angle);
|
||||
|
||||
|
||||
result.m0 = cosres;
|
||||
result.m1 = -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 result = MatrixIdentity();
|
||||
|
||||
|
||||
Matrix mRotation = MatrixRotate(rotation.x, rotation.y, rotation.z);
|
||||
Matrix mScale = MatrixScale(scale.x, scale.y, scale.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 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 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 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;
|
||||
|
||||
|
||||
result.m0 = b00*a00 + b01*a10 + b02*a20 + b03*a30;
|
||||
result.m1 = b00*a01 + b01*a11 + b02*a21 + b03*a31;
|
||||
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.m14 = b30*a02 + b31*a12 + b32*a22 + b33*a32;
|
||||
result.m15 = b30*a03 + b31*a13 + b32*a23 + b33*a33;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
|
||||
float rl = (right - left);
|
||||
float tb = (top - bottom);
|
||||
float fn = (far - near);
|
||||
|
||||
|
||||
result.m0 = (near*2) / rl;
|
||||
result.m1 = 0;
|
||||
result.m2 = 0;
|
||||
@ -741,7 +741,7 @@ Matrix MatrixFrustum(double left, double right, double bottom, double top, doubl
|
||||
result.m13 = 0;
|
||||
result.m14 = -(far*near*2) / fn;
|
||||
result.m15 = 0;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -755,14 +755,14 @@ Matrix MatrixPerspective(double fovy, double aspect, double near, double far)
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
|
||||
float rl = (right - left);
|
||||
float tb = (top - bottom);
|
||||
float fn = (far - near);
|
||||
|
||||
|
||||
result.m0 = 2 / rl;
|
||||
result.m1 = 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.m14 = -(far + near) / fn;
|
||||
result.m15 = 1;
|
||||
|
||||
|
||||
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 result;
|
||||
|
||||
|
||||
Vector3 z = VectorSubtract(eye, target);
|
||||
VectorNormalize(&z);
|
||||
Vector3 x = VectorCrossProduct(up, z);
|
||||
VectorNormalize(&x);
|
||||
Vector3 y = VectorCrossProduct(z, x);
|
||||
VectorNormalize(&y);
|
||||
|
||||
|
||||
result.m0 = x.x;
|
||||
result.m1 = x.y;
|
||||
result.m2 = x.z;
|
||||
@ -811,7 +811,7 @@ Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up)
|
||||
result.m13 = 0;
|
||||
result.m14 = 0;
|
||||
result.m15 = 1;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -837,16 +837,16 @@ float QuaternionLength(Quaternion quat)
|
||||
}
|
||||
|
||||
// Normalize provided quaternion
|
||||
void QuaternionNormalize(Quaternion *q)
|
||||
void QuaternionNormalize(Quaternion *q)
|
||||
{
|
||||
float length, ilength;
|
||||
|
||||
length = QuaternionLength(*q);
|
||||
|
||||
|
||||
if (length == 0) length = 1;
|
||||
|
||||
ilength = 1.0/length;
|
||||
|
||||
|
||||
q->x *= ilength;
|
||||
q->y *= ilength;
|
||||
q->z *= ilength;
|
||||
@ -854,28 +854,28 @@ void QuaternionNormalize(Quaternion *q)
|
||||
}
|
||||
|
||||
// Calculate two quaternion multiplication
|
||||
Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2)
|
||||
Quaternion QuaternionMultiply(Quaternion q1, Quaternion q2)
|
||||
{
|
||||
Quaternion result;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
result.x = qax*qbw + qaw*qbx + qay*qbz - qaz*qby;
|
||||
result.y = qay*qbw + qaw*qby + qaz*qbx - qax*qbz;
|
||||
result.z = qaz*qbw + qaw*qbz + qax*qby - qay*qbx;
|
||||
result.w = qaw*qbw - qax*qbx - qay*qby - qaz*qbz;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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;
|
||||
else
|
||||
{
|
||||
@ -892,15 +892,15 @@ Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
|
||||
else
|
||||
{
|
||||
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.y = (q1.y*ratioA + q2.y*ratioB);
|
||||
result.z = (q1.z*ratioA + q2.z*ratioB);
|
||||
result.w = (q1.w*ratioA + q2.w*ratioB);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -956,7 +956,7 @@ Quaternion QuaternionFromMatrix(Matrix matrix)
|
||||
result.z = s * 0.25;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -966,24 +966,24 @@ Quaternion QuaternionFromAxisAngle(Vector3 axis, float angle)
|
||||
{
|
||||
Quaternion result = { 0, 0, 0, 1 };
|
||||
|
||||
if (VectorLength(axis) != 0.0)
|
||||
if (VectorLength(axis) != 0.0)
|
||||
|
||||
angle *= 0.5;
|
||||
|
||||
|
||||
VectorNormalize(&axis);
|
||||
|
||||
result.x = axis.x * (float)sin(angle);
|
||||
result.y = axis.y * (float)sin(angle);
|
||||
result.z = axis.z * (float)sin(angle);
|
||||
result.w = (float)cos(angle);
|
||||
|
||||
|
||||
QuaternionNormalize(&result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Calculates the matrix from the given quaternion
|
||||
Matrix QuaternionToMatrix(Quaternion q)
|
||||
Matrix QuaternionToMatrix(Quaternion q)
|
||||
{
|
||||
Matrix result;
|
||||
|
||||
@ -1021,7 +1021,7 @@ Matrix QuaternionToMatrix(Quaternion q)
|
||||
result.m13 = 0;
|
||||
result.m14 = 0;
|
||||
result.m15 = 1;
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1035,7 +1035,7 @@ void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle)
|
||||
|
||||
resAngle = 2.0f * (float)acos(q.w);
|
||||
float den = (float)sqrt(1.0 - q.w * q.w);
|
||||
|
||||
|
||||
if (den > 0.0001f)
|
||||
{
|
||||
resAxis.x = q.x / den;
|
||||
@ -1044,11 +1044,11 @@ void QuaternionToAxisAngle(Quaternion q, Vector3 *outAxis, float *outAngle)
|
||||
}
|
||||
else
|
||||
{
|
||||
// This occurs when the angle is zero.
|
||||
// This occurs when the angle is zero.
|
||||
// Not a problem: just set an arbitrary normalized axis.
|
||||
resAxis.x = 1.0;
|
||||
}
|
||||
|
||||
|
||||
*outAxis = resAxis;
|
||||
*outAngle = resAngle;
|
||||
}
|
@ -1,19 +1,19 @@
|
||||
/*********************************************************************************************
|
||||
*
|
||||
*
|
||||
* raymath
|
||||
*
|
||||
*
|
||||
* Some useful functions to work with Vector3, Matrix and Quaternions
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* 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
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||
* in the product documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||
|
542
src/rlgl.c
542
src/rlgl.c
File diff suppressed because it is too large
Load Diff
16
src/rlgl.h
16
src/rlgl.h
@ -1,22 +1,22 @@
|
||||
/*********************************************************************************************
|
||||
*
|
||||
*
|
||||
* rlgl - raylib OpenGL abstraction layer
|
||||
*
|
||||
*
|
||||
* raylib now uses OpenGL 1.1 style functions (rlVertex) that are mapped to selected OpenGL version:
|
||||
* OpenGL 1.1 - Direct map rl* -> gl*
|
||||
* OpenGL 3.3+ - Vertex data is stored in VAOs, call rlglDraw() to render
|
||||
* OpenGL ES 2 - Same behaviour as OpenGL 3.3+ (NOT TESTED)
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* 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
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||
* in the product documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||
|
114
src/shapes.c
114
src/shapes.c
@ -3,17 +3,17 @@
|
||||
* raylib.shapes
|
||||
*
|
||||
* Basic functions to draw 2d Shapes and check collisions
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* 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
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||
* in the product documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||
@ -28,7 +28,7 @@
|
||||
#include <stdlib.h> // Required for abs() function
|
||||
#include <math.h> // Math related functions, sin() and cos() used on DrawCircle*
|
||||
// sqrt() and pow() and abs() used on CheckCollision*
|
||||
|
||||
|
||||
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
|
||||
|
||||
// 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)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
|
||||
// NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360)
|
||||
for (int i=0; i < 360; i++)
|
||||
{
|
||||
@ -165,7 +165,7 @@ void DrawRectangle(int posX, int posY, int width, int height, Color color)
|
||||
void DrawRectangleRec(Rectangle rec, Color color)
|
||||
{
|
||||
DrawRectangle(rec.x, rec.y, rec.width, rec.height, color);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw a gradient-filled rectangle
|
||||
// NOTE: Gradient goes from bottom (color1) to top (color2)
|
||||
@ -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(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX, posY + height);
|
||||
rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX + width, posY + height);
|
||||
|
||||
|
||||
rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX, posY);
|
||||
rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX + width, posY + height);
|
||||
rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX + width, posY + height);
|
||||
rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX + width, posY);
|
||||
rlEnd();
|
||||
}
|
||||
@ -188,16 +188,16 @@ void DrawRectangleV(Vector2 position, Vector2 size, Color color)
|
||||
#ifdef USE_OPENGL_11
|
||||
rlBegin(RL_TRIANGLES);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
|
||||
rlVertex2i(position.x, position.y);
|
||||
rlVertex2i(position.x, position.y + size.y);
|
||||
rlVertex2i(position.x + size.x, position.y + size.y);
|
||||
|
||||
|
||||
rlVertex2i(position.x, position.y);
|
||||
rlVertex2i(position.x + size.x, position.y + size.y);
|
||||
rlVertex2i(position.x + size.x, position.y + size.y);
|
||||
rlVertex2i(position.x + size.x, position.y);
|
||||
rlEnd();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
|
||||
// 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);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
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);
|
||||
|
||||
rlTexCoord2f(0.0f, 1.0f);
|
||||
|
||||
rlTexCoord2f(0.0f, 1.0f);
|
||||
rlVertex2f(position.x, position.y + size.y);
|
||||
|
||||
rlTexCoord2f(1.0f, 1.0f);
|
||||
rlVertex2f(position.x + size.x, position.y + size.y);
|
||||
|
||||
rlTexCoord2f(1.0f, 0.0f);
|
||||
|
||||
rlTexCoord2f(1.0f, 1.0f);
|
||||
rlVertex2f(position.x + size.x, position.y + size.y);
|
||||
|
||||
rlTexCoord2f(1.0f, 0.0f);
|
||||
rlVertex2f(position.x + size.x, position.y);
|
||||
rlEnd();
|
||||
|
||||
@ -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);
|
||||
rlVertex2i(posX + 1, posY + 1);
|
||||
rlVertex2i(posX + width, posY + 1);
|
||||
|
||||
|
||||
rlVertex2i(posX + width, posY + 1);
|
||||
rlVertex2i(posX + width, posY + height);
|
||||
|
||||
|
||||
rlVertex2i(posX + width, posY + height);
|
||||
rlVertex2i(posX + 1, posY + height);
|
||||
|
||||
|
||||
rlVertex2i(posX + 1, posY + height);
|
||||
rlVertex2i(posX + 1, posY + 1);
|
||||
rlEnd();
|
||||
@ -260,10 +260,10 @@ void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
rlVertex2f(v1.x, v1.y);
|
||||
rlVertex2f(v2.x, v2.y);
|
||||
|
||||
|
||||
rlVertex2f(v2.x, v2.y);
|
||||
rlVertex2f(v3.x, v3.y);
|
||||
|
||||
|
||||
rlVertex2f(v3.x, v3.y);
|
||||
rlVertex2f(v1.x, v1.y);
|
||||
rlEnd();
|
||||
@ -277,12 +277,12 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col
|
||||
rlPushMatrix();
|
||||
rlTranslatef(center.x, center.y, 0.0);
|
||||
rlRotatef(rotation, 0, 0, 1);
|
||||
|
||||
|
||||
rlBegin(RL_TRIANGLES);
|
||||
for (int i=0; i < 360; i += 360/sides)
|
||||
{
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
|
||||
rlVertex2i(0, 0);
|
||||
rlVertex2f(sin(DEG2RAD*i) * radius, cos(DEG2RAD*i) * 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);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
|
||||
for (int i = 0; i < numPoints - 2; i++)
|
||||
{
|
||||
rlVertex2f(points[i].x, points[i].y);
|
||||
@ -311,14 +311,14 @@ void DrawPolyEx(Vector2 *points, int numPoints, Color color)
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (numPoints >= 2)
|
||||
{
|
||||
rlBegin(RL_LINES);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
|
||||
for (int i = 0; i < numPoints - 1; i++)
|
||||
{
|
||||
rlVertex2f(points[i].x, points[i].y);
|
||||
@ -336,9 +336,9 @@ void DrawPolyExLines(Vector2 *points, int numPoints, Color color)
|
||||
bool CheckCollisionPointRec(Vector2 point, Rectangle rec)
|
||||
{
|
||||
bool collision = false;
|
||||
|
||||
|
||||
if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) && (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true;
|
||||
|
||||
|
||||
return collision;
|
||||
}
|
||||
|
||||
@ -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)) /
|
||||
((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y));
|
||||
|
||||
|
||||
float beta = ((p3.y - p1.y)*(point.x - p3.x) + (p1.x - p3.x)*(point.y - p3.y)) /
|
||||
((p2.y - p3.y)*(p1.x - p3.x) + (p3.x - p2.x)*(p1.y - p3.y));
|
||||
|
||||
|
||||
float gamma = 1.0f - alpha - beta;
|
||||
|
||||
if ((alpha > 0) && (beta > 0) & (gamma > 0)) collision = true;
|
||||
|
||||
|
||||
return collision;
|
||||
}
|
||||
|
||||
@ -370,12 +370,12 @@ bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2
|
||||
bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2)
|
||||
{
|
||||
bool collision = false;
|
||||
|
||||
|
||||
int dx = abs((rec1.x + rec1.width / 2) - (rec2.x + rec2.width / 2));
|
||||
int dy = abs((rec1.y + rec1.height / 2) - (rec2.y + rec2.height / 2));
|
||||
|
||||
|
||||
if ((dx <= (rec1.width / 2 + rec2.width / 2)) && ((dy <= (rec1.height / 2 + rec2.height / 2)))) collision = true;
|
||||
|
||||
|
||||
return collision;
|
||||
}
|
||||
|
||||
@ -383,14 +383,14 @@ bool CheckCollisionRecs(Rectangle rec1, Rectangle rec2)
|
||||
bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, float radius2)
|
||||
{
|
||||
bool collision = false;
|
||||
|
||||
|
||||
float dx = center2.x - center1.x; // X distance between centers
|
||||
float dy = center2.y - center1.y; // Y distance between centers
|
||||
|
||||
|
||||
float distance = sqrt(dx*dx + dy*dy); // Distance between centers
|
||||
|
||||
|
||||
if (distance <= (radius1 + radius2)) collision = true;
|
||||
|
||||
|
||||
return collision;
|
||||
}
|
||||
|
||||
@ -398,12 +398,12 @@ bool CheckCollisionCircles(Vector2 center1, float radius1, Vector2 center2, floa
|
||||
bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
|
||||
{
|
||||
bool collision = false;
|
||||
|
||||
|
||||
float dx = abs((rec.x + rec.width / 2) - center.x);
|
||||
float dy = abs((rec.y + rec.height / 2) - center.y);
|
||||
|
||||
|
||||
if ((dx <= (rec.width / 2 + radius)) && (dy <= (rec.height / 2 + radius))) collision = true;
|
||||
|
||||
|
||||
return collision;
|
||||
}
|
||||
|
||||
@ -411,16 +411,16 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
|
||||
Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
|
||||
{
|
||||
Rectangle retRec = { 0, 0, 0, 0 };
|
||||
|
||||
|
||||
if (CheckCollisionRecs(rec1, rec2))
|
||||
{
|
||||
int dxx = abs(rec1.x - rec2.x);
|
||||
int dyy = abs(rec1.y - rec2.y);
|
||||
|
||||
|
||||
if (rec1.x <= rec2.x)
|
||||
{
|
||||
if (rec1.y <= rec2.y)
|
||||
{
|
||||
{
|
||||
retRec.x = rec2.x;
|
||||
retRec.y = rec2.y;
|
||||
retRec.width = rec1.width - dxx;
|
||||
@ -437,7 +437,7 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
|
||||
else
|
||||
{
|
||||
if (rec1.y <= rec2.y)
|
||||
{
|
||||
{
|
||||
retRec.x = rec1.x;
|
||||
retRec.y = rec2.y;
|
||||
retRec.width = rec2.width - dxx;
|
||||
@ -451,10 +451,10 @@ Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
|
||||
retRec.height = rec2.height - dyy;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (retRec.width >= rec2.width) retRec.width = rec2.width;
|
||||
if (retRec.height >= rec2.height) retRec.height = rec2.height;
|
||||
}
|
||||
|
||||
|
||||
return retRec;
|
||||
}
|
||||
}
|
||||
|
228
src/text.c
228
src/text.c
@ -3,20 +3,20 @@
|
||||
* raylib.text
|
||||
*
|
||||
* Basic functions to load SpriteFonts and draw Text
|
||||
*
|
||||
*
|
||||
* Uses external lib:
|
||||
* stb_image - Multiple formats image loading (JPEG, PNG, BMP, TGA, PSD, GIF, HDR, PIC)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* 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
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||
* in the product documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||
@ -82,14 +82,14 @@ static SpriteFont LoadRBMF(const char *fileName); // Load a rBMF font file (ra
|
||||
//----------------------------------------------------------------------------------
|
||||
// Module Functions Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
extern void LoadDefaultFont()
|
||||
extern void LoadDefaultFont()
|
||||
{
|
||||
defaultFont.numChars = 96; // We know our default font has 94 chars
|
||||
|
||||
Image image;
|
||||
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
|
||||
|
||||
|
||||
// Default font is directly defined here (data generated from a sprite font image)
|
||||
// This way, we reconstruct SpriteFont without creating large global variables
|
||||
// This data is automatically allocated to Stack and automatically deallocated at the end of this function
|
||||
@ -119,19 +119,19 @@ extern void LoadDefaultFont()
|
||||
|
||||
int charsHeight = 10;
|
||||
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,
|
||||
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 };
|
||||
|
||||
// Re-construct image from defaultFontData and generate OpenGL texture
|
||||
//----------------------------------------------------------------------
|
||||
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
|
||||
|
||||
int counter = 0; // Font data elements counter
|
||||
|
||||
|
||||
// Fill imgData with defaultFontData (convert from bit to pixel!)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
counter++;
|
||||
|
||||
|
||||
if (counter > 256) counter = 0; // Security check...
|
||||
}
|
||||
|
||||
|
||||
defaultFont.texture = CreateTexture(image, false); // Convert loaded image to OpenGL texture
|
||||
UnloadImage(image);
|
||||
|
||||
|
||||
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, numChars
|
||||
//------------------------------------------------------------------------------
|
||||
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 currentPosX = charsDivisor;
|
||||
int testPosX = charsDivisor;
|
||||
|
||||
|
||||
for (int i = 0; i < defaultFont.numChars; i++)
|
||||
{
|
||||
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].w = charsWidth[i];
|
||||
defaultFont.charSet[i].h = charsHeight;
|
||||
|
||||
|
||||
testPosX += (defaultFont.charSet[i].w + charsDivisor);
|
||||
|
||||
|
||||
if (testPosX >= defaultFont.texture.width)
|
||||
{
|
||||
currentLine++;
|
||||
currentPosX = 2 * charsDivisor + charsWidth[i];
|
||||
testPosX = currentPosX;
|
||||
|
||||
|
||||
defaultFont.charSet[i].x = charsDivisor;
|
||||
defaultFont.charSet[i].y = charsDivisor + currentLine * (charsHeight + charsDivisor);
|
||||
}
|
||||
else currentPosX = testPosX;
|
||||
}
|
||||
|
||||
|
||||
TraceLog(INFO, "Default font loaded successfully");
|
||||
}
|
||||
|
||||
@ -194,29 +194,29 @@ SpriteFont GetDefaultFont()
|
||||
}
|
||||
|
||||
// Load a SpriteFont image into GPU memory
|
||||
SpriteFont LoadSpriteFont(const char* fileName)
|
||||
SpriteFont LoadSpriteFont(const char* fileName)
|
||||
{
|
||||
SpriteFont spriteFont;
|
||||
|
||||
|
||||
Image image;
|
||||
|
||||
|
||||
// Check file extension
|
||||
if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName);
|
||||
else
|
||||
{
|
||||
{
|
||||
// Use stb_image to load image data!
|
||||
int imgWidth;
|
||||
int imgHeight;
|
||||
int imgBpp;
|
||||
|
||||
|
||||
byte *imgData = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 4); // Force loading to 4 components (RGBA)
|
||||
|
||||
|
||||
// Convert array to pixel array for working convenience
|
||||
Color *imgDataPixel = (Color *)malloc(imgWidth * imgHeight * sizeof(Color));
|
||||
Color *imgDataPixelPOT = NULL;
|
||||
|
||||
|
||||
int pix = 0;
|
||||
|
||||
|
||||
for (int i = 0; i < (imgWidth * imgHeight * 4); i += 4)
|
||||
{
|
||||
imgDataPixel[pix].r = imgData[i];
|
||||
@ -225,33 +225,33 @@ SpriteFont LoadSpriteFont(const char* fileName)
|
||||
imgDataPixel[pix].a = imgData[i+3];
|
||||
pix++;
|
||||
}
|
||||
|
||||
|
||||
stbi_image_free(imgData);
|
||||
|
||||
|
||||
// At this point we have a pixel array with all the data...
|
||||
|
||||
|
||||
TraceLog(INFO, "[%s] SpriteFont image loaded: %i x %i", fileName, imgWidth, imgHeight);
|
||||
|
||||
|
||||
// Process bitmap Font pixel data to get measures (Character array)
|
||||
// spriteFont.charSet data is filled inside the function and memory is allocated!
|
||||
int numChars = ParseImageData(imgDataPixel, imgWidth, imgHeight, &spriteFont.charSet);
|
||||
|
||||
|
||||
TraceLog(INFO, "[%s] SpriteFont data parsed correctly", fileName);
|
||||
TraceLog(INFO, "[%s] SpriteFont num chars detected: %i", fileName, numChars);
|
||||
|
||||
|
||||
spriteFont.numChars = numChars;
|
||||
|
||||
|
||||
// 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...
|
||||
int potWidth = GetNextPOT(imgWidth);
|
||||
int potHeight = GetNextPOT(imgHeight);
|
||||
|
||||
|
||||
// Check if POT texture generation is required (if texture is not already POT)
|
||||
if ((potWidth != imgWidth) || (potHeight != imgHeight))
|
||||
{
|
||||
// Generate POT array from NPOT data
|
||||
imgDataPixelPOT = (Color *)malloc(potWidth * potHeight * sizeof(Color));
|
||||
|
||||
|
||||
for (int j = 0; j < potHeight; j++)
|
||||
{
|
||||
for (int i = 0; i < potWidth; i++)
|
||||
@ -260,20 +260,20 @@ SpriteFont LoadSpriteFont(const char* fileName)
|
||||
else imgDataPixelPOT[j*potWidth + i] = MAGENTA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TraceLog(WARNING, "SpriteFont texture converted to POT: %ix%i", potWidth, potHeight);
|
||||
}
|
||||
|
||||
|
||||
free(imgDataPixel);
|
||||
|
||||
image.pixels = imgDataPixelPOT;
|
||||
image.width = potWidth;
|
||||
image.height = potHeight;
|
||||
|
||||
|
||||
spriteFont.texture = CreateTexture(image, false); // Convert loaded image to OpenGL texture
|
||||
UnloadImage(image);
|
||||
}
|
||||
|
||||
|
||||
return spriteFont;
|
||||
}
|
||||
|
||||
@ -290,13 +290,13 @@ void UnloadSpriteFont(SpriteFont spriteFont)
|
||||
void DrawText(const char* text, int posX, int posY, int fontSize, Color color)
|
||||
{
|
||||
Vector2 position = { (float)posX, (float)posY };
|
||||
|
||||
|
||||
int defaultFontSize = 10; // Default Font chars height in pixel
|
||||
|
||||
|
||||
if (fontSize < defaultFontSize) fontSize = defaultFontSize;
|
||||
|
||||
|
||||
int spacing = fontSize / defaultFontSize;
|
||||
|
||||
|
||||
DrawTextEx(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 positionX = (int)position.x;
|
||||
float scaleFactor;
|
||||
|
||||
|
||||
Character c;
|
||||
|
||||
|
||||
if (fontSize <= spriteFont.charSet[0].h) scaleFactor = 1.0f;
|
||||
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++)
|
||||
{
|
||||
c = spriteFont.charSet[(int)text[i] - FONT_FIRST_CHAR];
|
||||
|
||||
|
||||
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
positionX += ((spriteFont.charSet[(int)text[i] - FONT_FIRST_CHAR].w) * scaleFactor + spacing);
|
||||
}
|
||||
rlEnd();
|
||||
@ -347,7 +347,7 @@ void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, int f
|
||||
const char *FormatText(const char *text, ...)
|
||||
{
|
||||
static char buffer[MAX_FORMATTEXT_LENGTH];
|
||||
|
||||
|
||||
va_list args;
|
||||
va_start(args, text);
|
||||
vsprintf(buffer, text, args);
|
||||
@ -372,19 +372,19 @@ Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int
|
||||
int len = strlen(text);
|
||||
int textWidth = 0;
|
||||
float scaleFactor;
|
||||
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
textWidth += spriteFont.charSet[(int)text[i] - FONT_FIRST_CHAR].w;
|
||||
}
|
||||
|
||||
|
||||
if (fontSize <= spriteFont.charSet[0].h) scaleFactor = 1.0f;
|
||||
else scaleFactor = (float)fontSize / spriteFont.charSet[0].h;
|
||||
|
||||
|
||||
Vector2 vec;
|
||||
vec.x = (float)textWidth * scaleFactor + (len - 1) * spacing; // Adds chars spacing to measure
|
||||
vec.y = (float)spriteFont.charSet[0].h * scaleFactor;
|
||||
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
@ -402,11 +402,11 @@ void DrawFPS(int posX, int posY)
|
||||
static float fps;
|
||||
static int counter = 0;
|
||||
static int refreshRate = 0;
|
||||
|
||||
|
||||
char buffer[20];
|
||||
|
||||
|
||||
if (counter < refreshRate)
|
||||
{
|
||||
{
|
||||
counter++;
|
||||
}
|
||||
else
|
||||
@ -415,7 +415,7 @@ void DrawFPS(int posX, int posY)
|
||||
refreshRate = fps;
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
|
||||
sprintf(buffer, "%2.0f FPS", fps);
|
||||
DrawText(buffer, posX, posY, 20, LIME);
|
||||
}
|
||||
@ -435,36 +435,36 @@ static int ParseImageData(Color *imgDataPixel, int imgWidth, int imgHeight, Char
|
||||
{
|
||||
int charSpacing = 0;
|
||||
int lineSpacing = 0;
|
||||
|
||||
|
||||
int x = 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.
|
||||
|
||||
|
||||
for(y = 0; y < imgHeight; y++)
|
||||
{
|
||||
{
|
||||
for(x = 0; x < imgWidth; x++)
|
||||
{
|
||||
{
|
||||
if (!PixelIsMagenta(imgDataPixel[y*imgWidth + x])) break;
|
||||
}
|
||||
if (!PixelIsMagenta(imgDataPixel[y*imgWidth + x])) break;
|
||||
}
|
||||
|
||||
|
||||
charSpacing = x;
|
||||
lineSpacing = y;
|
||||
|
||||
|
||||
int charHeight = 0;
|
||||
int j = 0;
|
||||
|
||||
|
||||
while(!PixelIsMagenta(imgDataPixel[(lineSpacing + j)*imgWidth + charSpacing])) j++;
|
||||
|
||||
|
||||
charHeight = j;
|
||||
|
||||
|
||||
// Check array values to get characters: value, x, y, w, h
|
||||
int index = 0;
|
||||
int lineToRead = 0;
|
||||
int xPosToRead = charSpacing;
|
||||
|
||||
|
||||
while((lineSpacing + lineToRead * (charHeight + lineSpacing)) < imgHeight)
|
||||
{
|
||||
while((xPosToRead < imgWidth) &&
|
||||
@ -474,22 +474,22 @@ static int ParseImageData(Color *imgDataPixel, int imgWidth, int imgHeight, Char
|
||||
tempCharSet[index].x = xPosToRead;
|
||||
tempCharSet[index].y = lineSpacing + lineToRead * (charHeight + lineSpacing);
|
||||
tempCharSet[index].h = charHeight;
|
||||
|
||||
|
||||
int charWidth = 0;
|
||||
|
||||
|
||||
while(!PixelIsMagenta(imgDataPixel[(lineSpacing + (charHeight+lineSpacing)*lineToRead)*imgWidth + xPosToRead + charWidth])) charWidth++;
|
||||
|
||||
|
||||
tempCharSet[index].w = charWidth;
|
||||
|
||||
|
||||
index++;
|
||||
|
||||
|
||||
xPosToRead += (charWidth + charSpacing);
|
||||
}
|
||||
|
||||
|
||||
lineToRead++;
|
||||
xPosToRead = charSpacing;
|
||||
}
|
||||
|
||||
|
||||
// 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)
|
||||
(*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 numChars; // Number of characters contained
|
||||
short charHeight; // Characters height - the same for all characters
|
||||
char compType; // Compression type:
|
||||
char compType; // Compression type:
|
||||
// 4 MSB --> image data compression
|
||||
// 4 LSB --> chars data compression
|
||||
char charsDataType; // Char data type provided
|
||||
@ -539,42 +539,42 @@ static SpriteFont LoadRBMF(const char *fileName)
|
||||
|
||||
SpriteFont spriteFont;
|
||||
Image image;
|
||||
|
||||
|
||||
rbmfInfoHeader rbmfHeader;
|
||||
unsigned int *rbmfFileData;
|
||||
unsigned char *rbmfCharWidthData;
|
||||
|
||||
|
||||
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
|
||||
|
||||
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);
|
||||
|
||||
|
||||
spriteFont.numChars = (int)rbmfHeader.numChars;
|
||||
|
||||
|
||||
image.width = (int)rbmfHeader.imgWidth;
|
||||
image.height = (int)rbmfHeader.imgHeight;
|
||||
|
||||
|
||||
int numPixelBits = rbmfHeader.imgWidth * rbmfHeader.imgHeight / 32;
|
||||
|
||||
|
||||
rbmfFileData = (unsigned int *)malloc(numPixelBits * sizeof(unsigned int));
|
||||
|
||||
|
||||
for(int i = 0; i < numPixelBits; i++) fread(&rbmfFileData[i], sizeof(unsigned int), 1, rbmfFile);
|
||||
|
||||
|
||||
rbmfCharWidthData = (unsigned char *)malloc(spriteFont.numChars * sizeof(unsigned char));
|
||||
|
||||
|
||||
for(int i = 0; i < spriteFont.numChars; i++) fread(&rbmfCharWidthData[i], sizeof(unsigned char), 1, rbmfFile);
|
||||
|
||||
|
||||
// Re-construct image from rbmfFileData
|
||||
//-----------------------------------------
|
||||
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
|
||||
|
||||
int counter = 0; // Font data elements counter
|
||||
|
||||
|
||||
// Fill image data (convert from bit to pixel!)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
counter++;
|
||||
}
|
||||
|
||||
|
||||
TraceLog(INFO, "[%s] Image reconstructed correctly, now converting it to texture", fileName);
|
||||
|
||||
|
||||
spriteFont.texture = CreateTexture(image, false);
|
||||
UnloadImage(image); // Unload image data
|
||||
|
||||
|
||||
TraceLog(INFO, "[%s] Starting charSet reconstruction", fileName);
|
||||
|
||||
|
||||
// Reconstruct charSet using rbmfCharWidthData, rbmfHeader.charHeight, charsDivisor, rbmfHeader.numChars
|
||||
spriteFont.charSet = (Character *)malloc(spriteFont.numChars * sizeof(Character)); // Allocate space for our character data
|
||||
|
||||
int currentLine = 0;
|
||||
int currentPosX = charsDivisor;
|
||||
int testPosX = charsDivisor;
|
||||
|
||||
|
||||
for (int i = 0; i < spriteFont.numChars; 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].w = (int)rbmfCharWidthData[i];
|
||||
spriteFont.charSet[i].h = (int)rbmfHeader.charHeight;
|
||||
|
||||
|
||||
testPosX += (spriteFont.charSet[i].w + charsDivisor);
|
||||
|
||||
|
||||
if (testPosX > spriteFont.texture.width)
|
||||
{
|
||||
currentLine++;
|
||||
currentPosX = 2 * charsDivisor + (int)rbmfCharWidthData[i];
|
||||
testPosX = currentPosX;
|
||||
|
||||
|
||||
spriteFont.charSet[i].x = charsDivisor;
|
||||
spriteFont.charSet[i].y = charsDivisor + currentLine * (rbmfHeader.charHeight + charsDivisor);
|
||||
}
|
||||
else currentPosX = testPosX;
|
||||
}
|
||||
|
||||
|
||||
TraceLog(INFO, "[%s] rBMF file loaded correctly as SpriteFont", fileName);
|
||||
|
||||
|
||||
fclose(rbmfFile);
|
||||
|
||||
|
||||
free(rbmfFileData); // Now we can free loaded data from RAM memory
|
||||
free(rbmfCharWidthData);
|
||||
free(rbmfCharWidthData);
|
||||
|
||||
return spriteFont;
|
||||
}
|
||||
@ -636,8 +636,8 @@ static SpriteFont LoadRBMF(const char *fileName)
|
||||
static SpriteFont GenerateFromTTF(const char *fileName, int fontSize)
|
||||
{
|
||||
SpriteFont font;
|
||||
|
||||
|
||||
// TODO: Load TTF and generate bitmap font and chars data
|
||||
|
||||
|
||||
return font;
|
||||
}
|
220
src/textures.c
220
src/textures.c
@ -3,20 +3,20 @@
|
||||
* raylib.textures
|
||||
*
|
||||
* Basic functions to load and draw Textures (2d)
|
||||
*
|
||||
*
|
||||
* Uses external lib:
|
||||
* stb_image - Multiple formats image loading (JPEG, PNG, BMP, TGA, PSD, GIF, PIC)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* 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
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||
* in the product documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||
@ -83,12 +83,12 @@ static ImageEx LoadDDS(const char *fileName);
|
||||
Image LoadImage(const char *fileName)
|
||||
{
|
||||
Image image;
|
||||
|
||||
|
||||
// Initial values
|
||||
image.pixels = NULL;
|
||||
image.width = 0;
|
||||
image.height = 0;
|
||||
|
||||
|
||||
if ((strcmp(GetExtension(fileName),"png") == 0) ||
|
||||
(strcmp(GetExtension(fileName),"bmp") == 0) ||
|
||||
(strcmp(GetExtension(fileName),"tga") == 0) ||
|
||||
@ -96,22 +96,22 @@ Image LoadImage(const char *fileName)
|
||||
(strcmp(GetExtension(fileName),"gif") == 0) ||
|
||||
(strcmp(GetExtension(fileName),"psd") == 0) ||
|
||||
(strcmp(GetExtension(fileName),"pic") == 0))
|
||||
{
|
||||
{
|
||||
int imgWidth;
|
||||
int imgHeight;
|
||||
int imgBpp;
|
||||
|
||||
|
||||
// NOTE: Using stb_image to load images (Supports: BMP, TGA, PNG, JPG, ...)
|
||||
// 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)
|
||||
{
|
||||
// Convert array to pixel array for working convenience
|
||||
image.pixels = (Color *)malloc(imgWidth * imgHeight * sizeof(Color));
|
||||
|
||||
|
||||
int pix = 0;
|
||||
|
||||
|
||||
for (int i = 0; i < (imgWidth * imgHeight * 4); i += 4)
|
||||
{
|
||||
image.pixels[pix].r = imgData[i];
|
||||
@ -120,12 +120,12 @@ Image LoadImage(const char *fileName)
|
||||
image.pixels[pix].a = imgData[i+3];
|
||||
pix++;
|
||||
}
|
||||
|
||||
|
||||
stbi_image_free(imgData);
|
||||
|
||||
|
||||
image.width = imgWidth;
|
||||
image.height = imgHeight;
|
||||
|
||||
|
||||
TraceLog(INFO, "[%s] Image loaded successfully", 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)
|
||||
{
|
||||
// NOTE: DDS uncompressed images can also be loaded (discarding mipmaps...)
|
||||
|
||||
|
||||
ImageEx imageDDS = LoadDDS(fileName);
|
||||
|
||||
|
||||
if (imageDDS.compFormat == 0)
|
||||
{
|
||||
image.pixels = (Color *)malloc(imageDDS.width * imageDDS.height * sizeof(Color));
|
||||
image.width = imageDDS.width;
|
||||
image.height = imageDDS.height;
|
||||
|
||||
|
||||
int pix = 0;
|
||||
|
||||
|
||||
for (int i = 0; i < (image.width * image.height * 4); i += 4)
|
||||
{
|
||||
image.pixels[pix].r = imageDDS.data[i];
|
||||
@ -152,16 +152,16 @@ Image LoadImage(const char *fileName)
|
||||
image.pixels[pix].a = imageDDS.data[i+3];
|
||||
pix++;
|
||||
}
|
||||
|
||||
|
||||
free(imageDDS.data);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
// 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.
|
||||
//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)
|
||||
{
|
||||
// TODO: rresName could be directly a char array with all the data! --> support it! :P
|
||||
|
||||
|
||||
Image image;
|
||||
bool found = false;
|
||||
|
||||
@ -180,9 +180,9 @@ Image LoadImageFromRES(const char *rresName, int resId)
|
||||
unsigned char version; // rRES file version and subversion
|
||||
char useless; // rRES header reserved data
|
||||
short numRes;
|
||||
|
||||
|
||||
ResInfoHeader infoHeader;
|
||||
|
||||
|
||||
FILE *rresFile = fopen(rresName, "rb");
|
||||
|
||||
if (!rresFile) 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(&version, sizeof(char), 1, rresFile);
|
||||
fread(&useless, sizeof(char), 1, rresFile);
|
||||
|
||||
|
||||
if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S'))
|
||||
{
|
||||
TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName);
|
||||
@ -204,15 +204,15 @@ Image LoadImageFromRES(const char *rresName, int resId)
|
||||
{
|
||||
// Read number of resources embedded
|
||||
fread(&numRes, sizeof(short), 1, rresFile);
|
||||
|
||||
|
||||
for (int i = 0; i < numRes; i++)
|
||||
{
|
||||
fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile);
|
||||
|
||||
|
||||
if (infoHeader.id == resId)
|
||||
{
|
||||
found = true;
|
||||
|
||||
|
||||
// Check data is of valid IMAGE type
|
||||
if (infoHeader.type == 0) // IMAGE data type
|
||||
{
|
||||
@ -221,25 +221,25 @@ Image LoadImageFromRES(const char *rresName, int resId)
|
||||
|
||||
short imgWidth, imgHeight;
|
||||
char colorFormat, mipmaps;
|
||||
|
||||
|
||||
fread(&imgWidth, sizeof(short), 1, rresFile); // Image width
|
||||
fread(&imgHeight, sizeof(short), 1, rresFile); // Image height
|
||||
fread(&colorFormat, 1, 1, rresFile); // Image data color format (default: RGBA 32 bit)
|
||||
fread(&mipmaps, 1, 1, rresFile); // Mipmap images included (default: 0)
|
||||
|
||||
|
||||
image.width = (int)imgWidth;
|
||||
image.height = (int)imgHeight;
|
||||
|
||||
|
||||
unsigned char *data = malloc(infoHeader.size);
|
||||
|
||||
fread(data, infoHeader.size, 1, rresFile);
|
||||
|
||||
|
||||
unsigned char *imgData = DecompressData(data, infoHeader.size, infoHeader.srcSize);
|
||||
|
||||
|
||||
image.pixels = (Color *)malloc(sizeof(Color)*imgWidth*imgHeight);
|
||||
|
||||
|
||||
int pix = 0;
|
||||
|
||||
|
||||
for (int i = 0; i < (imgWidth*imgHeight*4); i += 4)
|
||||
{
|
||||
image.pixels[pix].r = imgData[i];
|
||||
@ -248,11 +248,11 @@ Image LoadImageFromRES(const char *rresName, int resId)
|
||||
image.pixels[pix].a = imgData[i+3];
|
||||
pix++;
|
||||
}
|
||||
|
||||
|
||||
free(imgData);
|
||||
|
||||
|
||||
free(data);
|
||||
|
||||
|
||||
TraceLog(INFO, "[%s] Image loaded successfully from resource, size: %ix%i", rresName, image.width, image.height);
|
||||
}
|
||||
else
|
||||
@ -272,18 +272,18 @@ Image LoadImageFromRES(const char *rresName, int resId)
|
||||
case 4: break; // RAW: No parameters
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
// Jump DATA to read next infoHeader
|
||||
fseek(rresFile, infoHeader.size, SEEK_CUR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fclose(rresFile);
|
||||
}
|
||||
|
||||
|
||||
if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId);
|
||||
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
@ -295,7 +295,7 @@ Texture2D LoadTexture(const char *fileName)
|
||||
if (strcmp(GetExtension(fileName),"dds") == 0)
|
||||
{
|
||||
ImageEx image = LoadDDS(fileName);
|
||||
|
||||
|
||||
if (image.compFormat == 0)
|
||||
{
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
texture.width = image.width;
|
||||
texture.height = image.height;
|
||||
|
||||
|
||||
if (texture.id == 0) TraceLog(WARNING, "[%s] DDS texture could not be loaded", fileName);
|
||||
else TraceLog(INFO, "[%s] DDS texture loaded successfully", fileName);
|
||||
|
||||
|
||||
free(image.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Image image = LoadImage(fileName);
|
||||
|
||||
|
||||
if (image.pixels != NULL)
|
||||
{
|
||||
texture = CreateTexture(image, false);
|
||||
UnloadImage(image);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
@ -337,7 +337,7 @@ Texture2D LoadTextureFromRES(const char *rresName, int resId)
|
||||
Image image = LoadImageFromRES(rresName, resId);
|
||||
texture = CreateTexture(image, false);
|
||||
UnloadImage(image);
|
||||
|
||||
|
||||
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 destRec = { (int)position.x, (int)position.y, texture.width*scale, texture.height*scale };
|
||||
Vector2 origin = { 0, 0 };
|
||||
|
||||
|
||||
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 };
|
||||
Vector2 origin = { 0, 0 };
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
rlEnableTexture(texture.id);
|
||||
|
||||
|
||||
rlPushMatrix();
|
||||
rlTranslatef(destRec.x, destRec.y, 0);
|
||||
rlRotatef(rotation, 0, 0, 1);
|
||||
rlTranslatef(-origin.x, -origin.y, 0);
|
||||
|
||||
|
||||
rlBegin(RL_QUADS);
|
||||
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
|
||||
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
// Bottom-right corner for texture and quad
|
||||
rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
|
||||
rlVertex2f(0.0f, destRec.height);
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
// Top-left corner for texture and quad
|
||||
rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height);
|
||||
rlVertex2f(destRec.width, 0.0f);
|
||||
rlEnd();
|
||||
rlPopMatrix();
|
||||
|
||||
|
||||
rlDisableTexture();
|
||||
}
|
||||
|
||||
@ -425,25 +425,25 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V
|
||||
Texture2D CreateTexture(Image image, bool genMipmaps)
|
||||
{
|
||||
Texture2D texture;
|
||||
|
||||
|
||||
// Init texture to default values
|
||||
texture.id = 0;
|
||||
texture.width = 0;
|
||||
texture.height = 0;
|
||||
|
||||
|
||||
if (image.pixels != NULL)
|
||||
{
|
||||
unsigned char *imgData = malloc(image.width * image.height * 4);
|
||||
|
||||
|
||||
int j = 0;
|
||||
|
||||
|
||||
for (int i = 0; i < image.width * image.height * 4; i += 4)
|
||||
{
|
||||
imgData[i] = image.pixels[j].r;
|
||||
imgData[i+1] = image.pixels[j].g;
|
||||
imgData[i+2] = image.pixels[j].b;
|
||||
imgData[i+3] = image.pixels[j].a;
|
||||
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
@ -452,24 +452,24 @@ Texture2D CreateTexture(Image image, bool genMipmaps)
|
||||
|
||||
texture.width = image.width;
|
||||
texture.height = image.height;
|
||||
|
||||
|
||||
TraceLog(INFO, "[ID %i] Texture created successfully", texture.id);
|
||||
|
||||
|
||||
free(imgData);
|
||||
}
|
||||
else TraceLog(WARNING, "Texture could not be created, image data is not valid");
|
||||
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
// Loading DDS image data (compressed or uncompressed)
|
||||
// NOTE: Compressed data loading not supported on OpenGL 1.1
|
||||
ImageEx LoadDDS(const char *fileName)
|
||||
{
|
||||
{
|
||||
#define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII
|
||||
#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII
|
||||
#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII
|
||||
|
||||
|
||||
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
|
||||
#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
|
||||
#endif
|
||||
@ -481,7 +481,7 @@ ImageEx LoadDDS(const char *fileName)
|
||||
#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
|
||||
#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
|
||||
#endif
|
||||
|
||||
|
||||
// DDS Pixel Format
|
||||
typedef struct {
|
||||
unsigned int size;
|
||||
@ -493,7 +493,7 @@ ImageEx LoadDDS(const char *fileName)
|
||||
unsigned int bitMask;
|
||||
unsigned int aBitMask;
|
||||
} ddsPixelFormat;
|
||||
|
||||
|
||||
// DDS Header (124 bytes)
|
||||
typedef struct {
|
||||
unsigned int size;
|
||||
@ -511,12 +511,12 @@ ImageEx LoadDDS(const char *fileName)
|
||||
unsigned int caps4;
|
||||
unsigned int reserved2;
|
||||
} ddsHeader;
|
||||
|
||||
|
||||
ImageEx image;
|
||||
ddsHeader header;
|
||||
|
||||
FILE *ddsFile = fopen(fileName, "rb");
|
||||
|
||||
|
||||
if (ddsFile == NULL)
|
||||
{
|
||||
TraceLog(WARNING, "DDS File could not be opened");
|
||||
@ -525,16 +525,16 @@ ImageEx LoadDDS(const char *fileName)
|
||||
{
|
||||
// Verify the type of file
|
||||
char filecode[4];
|
||||
|
||||
|
||||
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");
|
||||
fclose(ddsFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
// Get the surface descriptor
|
||||
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 flags: 0x%x", fileName, header.ddspf.flags);
|
||||
TraceLog(DEBUG, "[%s] DDS file format: 0x%x", fileName, header.ddspf.fourCC);
|
||||
|
||||
|
||||
image.width = header.width;
|
||||
image.height = header.height;
|
||||
image.mipmaps = 1;
|
||||
image.compFormat = 0;
|
||||
|
||||
|
||||
if (header.ddspf.flags == 0x40 && header.ddspf.rgbBitCount == 24) // DDS_RGB, no compressed
|
||||
{
|
||||
image.data = (unsigned char *)malloc(header.width * header.height * 4);
|
||||
unsigned char *buffer = (unsigned char *)malloc(header.width * header.height * 3);
|
||||
|
||||
|
||||
fread(buffer, image.width*image.height*3, 1, ddsFile);
|
||||
|
||||
|
||||
unsigned char *src = buffer;
|
||||
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++;
|
||||
@ -568,49 +568,49 @@ ImageEx LoadDDS(const char *fileName)
|
||||
*dest++ = 255;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
else if (header.ddspf.flags == 0x41 && header.ddspf.rgbBitCount == 32) // DDS_RGBA, no compressed
|
||||
{
|
||||
image.data = (unsigned char *)malloc(header.width * header.height * 4);
|
||||
|
||||
|
||||
fread(image.data, image.width*image.height*4, 1, ddsFile);
|
||||
|
||||
|
||||
image.mipmaps = 1;
|
||||
image.compFormat = 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 compressed files require OpenGL 3.2+ or ES 2.0", fileName);
|
||||
fclose(ddsFile);
|
||||
#else
|
||||
int bufsize;
|
||||
|
||||
|
||||
// Calculate data size, including all mipmaps
|
||||
if (header.mipMapCount > 1) bufsize = header.pitchOrLinearSize * 2;
|
||||
else bufsize = header.pitchOrLinearSize;
|
||||
|
||||
image.data = (unsigned char*)malloc(bufsize * sizeof(unsigned char));
|
||||
|
||||
fread(image.data, 1, bufsize, ddsFile);
|
||||
|
||||
else bufsize = header.pitchOrLinearSize;
|
||||
|
||||
image.data = (unsigned char*)malloc(bufsize * sizeof(unsigned char));
|
||||
|
||||
fread(image.data, 1, bufsize, ddsFile);
|
||||
|
||||
// Close file pointer
|
||||
fclose(ddsFile);
|
||||
|
||||
|
||||
image.mipmaps = header.mipMapCount;
|
||||
image.compFormat = 0;
|
||||
|
||||
|
||||
switch(header.ddspf.fourCC)
|
||||
{
|
||||
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_DXT5: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_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_DXT5: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
// NOTE: Image num color components not required... for now...
|
||||
//if (fourCC == FOURCC_DXT1) image.components = 3;
|
||||
//else image.components = 4;
|
||||
@ -618,6 +618,6 @@ ImageEx LoadDDS(const char *fileName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return image;
|
||||
}
|
46
src/utils.c
46
src/utils.c
@ -3,21 +3,21 @@
|
||||
* raylib.utils
|
||||
*
|
||||
* Utils Functions Definitions
|
||||
*
|
||||
* Uses external libs:
|
||||
*
|
||||
* Uses external libs:
|
||||
* tinfl - zlib DEFLATE algorithm decompression lib
|
||||
* stb_image_write - PNG writting functions
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* 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
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||
* in the product documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||
@ -54,10 +54,10 @@ unsigned char *DecompressData(const unsigned char *data, unsigned long compSize,
|
||||
{
|
||||
int tempUncompSize;
|
||||
unsigned char *pUncomp;
|
||||
|
||||
|
||||
// Allocate buffer to hold decompressed data
|
||||
pUncomp = (mz_uint8 *)malloc((size_t)uncompSize);
|
||||
|
||||
|
||||
// Check correct memory allocation
|
||||
if (!pUncomp)
|
||||
{
|
||||
@ -67,13 +67,13 @@ unsigned char *DecompressData(const unsigned char *data, unsigned long compSize,
|
||||
{
|
||||
// Decompress data
|
||||
tempUncompSize = tinfl_decompress_mem_to_mem(pUncomp, (size_t)uncompSize, data, compSize, 1);
|
||||
|
||||
|
||||
if (tempUncompSize == -1)
|
||||
{
|
||||
TraceLog(WARNING, "Data decompression failed");
|
||||
free(pUncomp);
|
||||
}
|
||||
|
||||
|
||||
if (uncompSize != (int)tempUncompSize)
|
||||
{
|
||||
TraceLog(WARNING, "Expected uncompressed size do not match, data may be corrupted");
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
int filesize = 54 + 3*width*height;
|
||||
|
||||
|
||||
unsigned char bmpFileHeader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0}; // Standard BMP file header
|
||||
unsigned char bmpInfoHeader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0}; // Standard BMP info header
|
||||
|
||||
@ -111,11 +111,11 @@ void WriteBitmap(const char *fileName, unsigned char *imgData, int width, int he
|
||||
bmpInfoHeader[11] = (unsigned char)(height>>24);
|
||||
|
||||
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
|
||||
fwrite(bmpFileHeader, sizeof(unsigned char), 14, bmpFile); // Write BMP file header data
|
||||
fwrite(bmpInfoHeader, sizeof(unsigned char), 40, bmpFile); // Write BMP info header data
|
||||
|
||||
|
||||
// Write pixel data to file
|
||||
for (int y = 0; y < height ; y++)
|
||||
{
|
||||
@ -143,14 +143,14 @@ void TraceLog(int msgType, const char *text, ...)
|
||||
{
|
||||
va_list args;
|
||||
int traceDebugMsgs = 1;
|
||||
|
||||
|
||||
#ifdef DO_NOT_TRACE_DEBUG_MSGS
|
||||
traceDebugMsgs = 0;
|
||||
#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;
|
||||
|
||||
|
||||
switch(msgType)
|
||||
{
|
||||
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;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
if ((msgType != DEBUG) || ((msgType == DEBUG) && (traceDebugMsgs)))
|
||||
{
|
||||
va_start(args, text);
|
||||
vfprintf(logstream, text, args);
|
||||
va_end(args);
|
||||
|
||||
|
||||
fprintf(logstream, "\n");
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
const char *GetExtension(const char *fileName)
|
||||
const char *GetExtension(const char *fileName)
|
||||
{
|
||||
const char *dot = strrchr(fileName, '.');
|
||||
if(!dot || dot == fileName) return "";
|
||||
|
12
src/utils.h
12
src/utils.h
@ -3,17 +3,17 @@
|
||||
* raylib.utils
|
||||
*
|
||||
* Some utility functions: rRES files data decompression
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* 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
|
||||
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||
* in the product documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||
|
Loading…
Reference in New Issue
Block a user