Merge pull request #2 from raysan5/testing

Integrate raylib 1.1 changes into master
This commit is contained in:
Ray 2014-04-19 14:21:22 +02:00
commit 650a8f7f15
25 changed files with 25258 additions and 1886 deletions

73
external/glew/LICENSE.txt vendored Normal file
View file

@ -0,0 +1,73 @@
The OpenGL Extension Wrangler Library
Copyright (C) 2002-2007, Milan Ikits <milan ikits[]ieee org>
Copyright (C) 2002-2007, Marcelo E. Magallon <mmagallo[]debian org>
Copyright (C) 2002, Lev Povalahev
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
Mesa 3-D graphics library
Version: 7.0
Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Copyright (c) 2007 The Khronos Group Inc.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and/or associated documentation files (the
"Materials"), to deal in the Materials without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Materials, and to
permit persons to whom the Materials are furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Materials.
THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.

BIN
external/glew/glew32.dll vendored Normal file

Binary file not shown.

18062
external/glew/include/GL/glew.h vendored Normal file

File diff suppressed because it is too large Load diff

1669
external/glew/include/GL/glxew.h vendored Normal file

File diff suppressed because it is too large Load diff

1421
external/glew/include/GL/wglew.h vendored Normal file

File diff suppressed because it is too large Load diff

BIN
external/glew/lib/libglew32.a vendored Normal file

Binary file not shown.

BIN
external/glew/lib/libglew32.dll.a vendored Normal file

Binary file not shown.

View file

@ -37,7 +37,7 @@
#include "utils.h" // rRES data decompression utility function
//#include "stb_vorbis.h" // TODO: OGG loading functions
//#include "stb_vorbis.h" // OGG loading functions
//----------------------------------------------------------------------------------
// Defines and Macros
@ -47,6 +47,29 @@
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
// Sound source type (all file loaded in memory)
/*
struct Sound {
unsigned int source;
unsigned int buffer;
};
// Music type (file streamming from memory)
// NOTE: Anything longer than ~10 seconds should be Music...
struct Music {
stb_vorbis* stream;
stb_vorbis_info info;
ALuint id;
ALuint buffers[2];
ALuint source;
ALenum format;
int bufferSize;
int totalSamplesLeft;
bool loop;
};
*/
// Wave file data
typedef struct Wave {
@ -60,7 +83,8 @@ typedef struct Wave {
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
// Nop...
static bool musicIsPlaying;
static Music *currentMusic;
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
@ -68,6 +92,10 @@ typedef struct Wave {
static Wave LoadWAV(char *fileName);
static void UnloadWAV(Wave wave);
//static Ogg LoadOGG(char *fileName);
static bool MusicStream(Music music, ALuint buffer);
extern bool MusicStreamUpdate();
extern void PlayCurrentMusic();
//----------------------------------------------------------------------------------
// Module Functions Definition - Window and OpenGL Context Functions
@ -79,30 +107,27 @@ void InitAudioDevice()
// Open and initialize a device with default settings
ALCdevice *device = alcOpenDevice(NULL);
if(!device)
{
fprintf(stderr, "Could not open a device!\n");
exit(1);
}
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);
if(context != NULL) alcDestroyContext(context);
alcCloseDevice(device);
fprintf(stderr, "Could not set a context!\n");
exit(1);
TraceLog(ERROR, "Could not setup audio context");
}
printf("Opened \"%s\"\n", alcGetString(device, ALC_DEVICE_SPECIFIER));
TraceLog(INFO, "Audio device and context initialized: %s\n", alcGetString(device, ALC_DEVICE_SPECIFIER));
// Listener definition (just for 2D)
alListener3f(AL_POSITION, 0, 0, 0);
alListener3f(AL_VELOCITY, 0, 0, 0);
alListener3f(AL_ORIENTATION, 0, 0, -1);
musicIsPlaying = false;
}
// Close the audio device for the current context, and destroys the context
@ -111,7 +136,7 @@ void CloseAudioDevice()
ALCdevice *device;
ALCcontext *context = alcGetCurrentContext();
if (context == NULL) return;
if (context == NULL) TraceLog(WARNING, "Could not get current audio context for closing");
device = alcGetContextsDevice(context);
@ -131,7 +156,7 @@ Sound LoadSound(char *fileName)
// NOTE: Buffer space is allocated inside LoadWAV, Wave must be freed
Wave wave = LoadWAV(fileName);
ALenum format;
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)
{
@ -169,10 +194,8 @@ Sound LoadSound(char *fileName)
// Unallocate WAV data
UnloadWAV(wave);
printf("Sample rate: %i\n", wave.sampleRate);
printf("Channels: %i\n", wave.channels);
printf("Audio file loaded...!\n");
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;
@ -196,139 +219,136 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
FILE *rresFile = fopen(rresName, "rb");
if (!rresFile) printf("Error opening raylib Resource file\n");
// Read rres file (basic file check - id)
fread(&id[0], sizeof(char), 1, rresFile);
fread(&id[1], sizeof(char), 1, rresFile);
fread(&id[2], sizeof(char), 1, rresFile);
fread(&id[3], sizeof(char), 1, rresFile);
fread(&version, sizeof(char), 1, rresFile);
fread(&useless, sizeof(char), 1, rresFile);
if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S'))
if (!rresFile) TraceLog(WARNING, "[%s] Could not open raylib resource file", rresName);
else
{
printf("This is not a valid raylib Resource file!\n");
exit(1);
}
// Read number of resources embedded
fread(&numRes, sizeof(short), 1, rresFile);
for (int i = 0; i < numRes; i++)
{
fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile);
// Read rres file (basic file check - id)
fread(&id[0], sizeof(char), 1, rresFile);
fread(&id[1], sizeof(char), 1, rresFile);
fread(&id[2], sizeof(char), 1, rresFile);
fread(&id[3], sizeof(char), 1, rresFile);
fread(&version, sizeof(char), 1, rresFile);
fread(&useless, sizeof(char), 1, rresFile);
if (infoHeader.id == resId)
if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S'))
{
found = true;
// Check data is of valid SOUND type
if (infoHeader.type == 1) // SOUND data type
{
// TODO: Check data compression type
// NOTE: We suppose compression type 2 (DEFLATE - default)
// Reading SOUND parameters
Wave wave;
short sampleRate, bps;
char channels, reserved;
fread(&sampleRate, sizeof(short), 1, rresFile); // Sample rate (frequency)
fread(&bps, sizeof(short), 1, rresFile); // Bits per sample
fread(&channels, 1, 1, rresFile); // Channels (1 - mono, 2 - stereo)
fread(&reserved, 1, 1, rresFile); // <reserved>
printf("Sample rate: %i\n", (int)sampleRate);
printf("Bits per sample: %i\n", (int)bps);
printf("Channels: %i\n", (int)channels);
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;
// The OpenAL format is worked out by looking at the number of channels and the bits per sample
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)
{
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_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;
alGenBuffers(1, &buffer); // Generate pointer to buffer
// Upload sound data to buffer
alBufferData(buffer, format, (void*)wave.data, wave.dataSize, wave.sampleRate);
// Attach sound buffer to source
alSourcei(source, AL_BUFFER, buffer);
// Unallocate WAV data
UnloadWAV(wave);
printf("Audio file loaded...!\n");
sound.source = source;
sound.buffer = buffer;
}
else
{
printf("Required resource do not seem to be a valid IMAGE resource\n");
exit(2);
}
TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName);
}
else
{
// Depending on type, skip the right amount of parameters
switch (infoHeader.type)
{
case 0: fseek(rresFile, 6, SEEK_CUR); break; // IMAGE: Jump 6 bytes of parameters
case 1: fseek(rresFile, 6, SEEK_CUR); break; // SOUND: Jump 6 bytes of parameters
case 2: fseek(rresFile, 5, SEEK_CUR); break; // MODEL: Jump 5 bytes of parameters (TODO: Review)
case 3: break; // TEXT: No parameters
case 4: break; // RAW: No parameters
default: break;
}
// Read number of resources embedded
fread(&numRes, sizeof(short), 1, rresFile);
// Jump DATA to read next infoHeader
fseek(rresFile, infoHeader.size, SEEK_CUR);
}
for (int i = 0; i < numRes; i++)
{
fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile);
if (infoHeader.id == resId)
{
found = true;
// Check data is of valid SOUND type
if (infoHeader.type == 1) // SOUND data type
{
// TODO: Check data compression type
// NOTE: We suppose compression type 2 (DEFLATE - default)
// Reading SOUND parameters
Wave wave;
short sampleRate, bps;
char channels, reserved;
fread(&sampleRate, sizeof(short), 1, rresFile); // Sample rate (frequency)
fread(&bps, sizeof(short), 1, rresFile); // Bits per sample
fread(&channels, 1, 1, rresFile); // Channels (1 - mono, 2 - stereo)
fread(&reserved, 1, 1, rresFile); // <reserved>
wave.sampleRate = sampleRate;
wave.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.bitsPerSample == 8 ) format = AL_FORMAT_MONO8;
else if (wave.bitsPerSample == 16) format = AL_FORMAT_MONO16;
}
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_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;
alGenBuffers(1, &buffer); // Generate pointer to buffer
// Upload sound data to buffer
alBufferData(buffer, format, (void*)wave.data, wave.dataSize, wave.sampleRate);
// Attach sound buffer to source
alSourcei(source, AL_BUFFER, buffer);
// Unallocate WAV data
UnloadWAV(wave);
TraceLog(INFO, "[%s] Sound loaded successfully from resource, sample rate: %i", rresName, (int)sampleRate);
sound.source = source;
sound.buffer = buffer;
}
else
{
TraceLog(WARNING, "[%s] Required resource do not seem to be a valid SOUND resource", rresName);
}
}
else
{
// Depending on type, skip the right amount of parameters
switch (infoHeader.type)
{
case 0: fseek(rresFile, 6, SEEK_CUR); break; // IMAGE: Jump 6 bytes of parameters
case 1: fseek(rresFile, 6, SEEK_CUR); break; // SOUND: Jump 6 bytes of parameters
case 2: fseek(rresFile, 5, SEEK_CUR); break; // MODEL: Jump 5 bytes of parameters (TODO: Review)
case 3: break; // TEXT: No parameters
case 4: break; // RAW: No parameters
default: break;
}
// Jump DATA to read next infoHeader
fseek(rresFile, infoHeader.size, SEEK_CUR);
}
}
}
fclose(rresFile);
}
fclose(rresFile);
if (!found) printf("Required resource id could not be found in the raylib Resource file!\n");
if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId);
return sound;
}
@ -345,7 +365,7 @@ void PlaySound(Sound sound)
{
alSourcePlay(sound.source); // Play the sound
printf("Playing sound!\n");
TraceLog(INFO, "Playing sound");
// Find the current position of the sound being played
// NOTE: Only work when the entire file is in a single buffer
@ -390,7 +410,7 @@ void StopSound(Sound sound)
}
// Check if a sound is playing
bool IsPlaying(Sound sound)
bool SoundIsPlaying(Sound sound)
{
bool playing = false;
ALint state;
@ -401,6 +421,16 @@ bool IsPlaying(Sound sound)
return playing;
}
// Check if music is playing
bool MusicIsPlaying(Music music)
{
ALenum state;
alGetSourcei(music.source, AL_SOURCE_STATE, &state);
return (state == AL_PLAYING);
}
// Set volume for a sound
void SetVolume(Sound sound, float volume)
{
@ -450,61 +480,65 @@ static Wave LoadWAV(char *fileName)
if (!wavFile)
{
printf("Could not open WAV file.\n");
exit(1);
TraceLog(WARNING, "[%s] Could not open WAV file", 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'))
printf("Invalid RIFF or WAVE Header");
// 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] != ' ')
printf("Invalid Wave Format");
// 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')
printf("Invalid data header");
// Allocate memory for data
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;
else
{
// 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')))
{
TraceLog(WARNING, "[%s] Invalid RIFF or WAVE Header", fileName);
}
else
{
// Read in the 2nd chunk for the wave info
fread(&waveFormat, sizeof(WaveFormat), 1, wavFile);
// Check for fmt tag
if ((waveFormat.subChunkID[0] != 'f') || (waveFormat.subChunkID[1] != 'm') ||
(waveFormat.subChunkID[2] != 't') || (waveFormat.subChunkID[3] != ' '))
{
TraceLog(WARNING, "[%s] Invalid Wave format", fileName);
}
else
{
// 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'))
{
TraceLog(WARNING, "[%s] Invalid data header", fileName);
}
else
{
// Allocate memory for data
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);
}
}
}
fclose(wavFile);
fclose(wavFile);
}
return wave;
}
@ -516,5 +550,192 @@ static void UnloadWAV(Wave wave)
}
// TODO: Ogg data loading
//static Ogg LoadOGG(char *fileName) { }
Music LoadMusic(char *fileName)
{
Music music;
// Open audio stream
music.stream = stb_vorbis_open_filename(fileName, NULL, NULL);
if (music.stream == NULL) TraceLog(WARNING, "Could not open ogg audio file");
else
{
// Get file info
music.info = stb_vorbis_get_info(music.stream);
printf("Ogg sample rate: %i\n", music.info.sample_rate);
printf("Ogg channels: %i\n", music.info.channels);
printf("Temp memory required: %i\n", music.info.temp_memory_required);
if (music.info.channels == 2) music.format = AL_FORMAT_STEREO16;
else music.format = AL_FORMAT_MONO16;
music.bufferSize = 4096*8;
music.loop = true; // We loop by default
// Create an audio source
alGenSources(1, &music.source); // Generate pointer to audio source
alSourcef(music.source, AL_PITCH, 1);
alSourcef(music.source, AL_GAIN, 1);
alSource3f(music.source, AL_POSITION, 0, 0, 0);
alSource3f(music.source, AL_VELOCITY, 0, 0, 0);
alSourcei(music.source, AL_LOOPING, AL_TRUE); // We loop by default
// Convert loaded data to OpenAL buffers
alGenBuffers(2, music.buffers);
/*
if (!MusicStream(music, music.buffers[0])) exit(1);
if (!MusicStream(music, music.buffers[1])) exit(1);
alSourceQueueBuffers(music.source, 2, music.buffers);
PlayMusic(music);
*/
music.totalSamplesLeft = stb_vorbis_stream_length_in_samples(music.stream) * music.info.channels;
currentMusic = &music;
}
return music;
}
void UnloadMusic(Music music)
{
StopMusic(music);
alDeleteSources(1, &music.source);
alDeleteBuffers(2, music.buffers);
stb_vorbis_close(music.stream);
}
void PlayMusic(Music music)
{
//if (MusicIsPlaying(music)) return true;
if (!MusicStream(music, music.buffers[0])) TraceLog(WARNING, "MusicStream returned 0");
if (!MusicStream(music, music.buffers[1])) TraceLog(WARNING, "MusicStream returned 0");
alSourceQueueBuffers(music.source, 2, music.buffers);
alSourcePlay(music.source);
TraceLog(INFO, "Playing music");
}
extern void PlayCurrentMusic()
{
if (!MusicStream(*currentMusic, currentMusic->buffers[0])) TraceLog(WARNING, "MusicStream returned 0");
if (!MusicStream(*currentMusic, currentMusic->buffers[1])) TraceLog(WARNING, "MusicStream returned 0");
alSourceQueueBuffers(currentMusic->source, 2, currentMusic->buffers);
alSourcePlay(currentMusic->source);
}
// Stop reproducing music
void StopMusic(Music music)
{
alSourceStop(music.source);
musicIsPlaying = false;
}
static bool MusicStream(Music music, ALuint buffer)
{
//Uncomment this to avoid VLAs
//#define BUFFER_SIZE 4096*32
#ifndef BUFFER_SIZE//VLAs ftw
#define BUFFER_SIZE (music.bufferSize)
#endif
ALshort pcm[BUFFER_SIZE];
int size = 0;
int result = 0;
while (size < BUFFER_SIZE)
{
result = stb_vorbis_get_samples_short_interleaved(music.stream, music.info.channels, pcm+size, BUFFER_SIZE-size);
if (result > 0) size += (result*music.info.channels);
else break;
}
if (size == 0) return false;
alBufferData(buffer, music.format, pcm, size*sizeof(ALshort), music.info.sample_rate);
music.totalSamplesLeft -= size;
#undef BUFFER_SIZE
return true;
}
/*
extern bool MusicStreamUpdate()
{
ALint processed = 0;
alGetSourcei(currentMusic->source, AL_BUFFERS_PROCESSED, &processed);
while (processed--)
{
ALuint buffer = 0;
alSourceUnqueueBuffers(currentMusic->source, 1, &buffer);
if (!MusicStream(*currentMusic, buffer))
{
bool shouldExit = true;
if (currentMusic->loop)
{
stb_vorbis_seek_start(currentMusic->stream);
currentMusic->totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic->stream) * currentMusic->info.channels;
shouldExit = !MusicStream(*currentMusic, buffer);
}
if (shouldExit) return false;
}
alSourceQueueBuffers(currentMusic->source, 1, &buffer);
}
return true;
}
*/
extern bool MusicStreamUpdate()
{
int processed;
bool active = true;
alGetSourcei(currentMusic->source, AL_BUFFERS_PROCESSED, &processed);
printf("Data processed: %i\n", processed);
while (processed--)
{
ALuint buffer = 0;
alSourceUnqueueBuffers(currentMusic->source, 1, &buffer);
active = MusicStream(*currentMusic, buffer);
alSourceQueueBuffers(currentMusic->source, 1, &buffer);
}
return active;
}
void MusicStreamEmpty()
{
int queued;
alGetSourcei(currentMusic->source, AL_BUFFERS_QUEUED, &queued);
while(queued--)
{
ALuint buffer;
alSourceUnqueueBuffers(currentMusic->source, 1, &buffer);
}
}

View file

@ -28,15 +28,19 @@
#include "raylib.h"
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
#include <GLFW/glfw3.h> // GLFW3 lib: Windows, OpenGL context and Input management
//#include <GL/gl.h> // OpenGL functions (GLFW3 already includes gl.h)
#include <stdio.h> // Standard input / output lib
#include <stdlib.h> // Declares malloc() and free() for memory management, rand()
#include <time.h> // Useful to initialize random seed
#include <math.h> // Math related functions, tan() used to set perspective
#include "vector3.h" // Basic Vector3 functions
//#include "vector3.h" // Basic Vector3 functions, not required any more, replaced by raymath
#include "utils.h" // WritePNG() function
#include "raymath.h" // Required for data type Matrix and Matrix functions
//#define GLFW_DLL // Using GLFW DLL on Windows -> No, we use static version!
//----------------------------------------------------------------------------------
@ -47,7 +51,7 @@
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
typedef Color pixel;
// ...
//----------------------------------------------------------------------------------
// Global Variables Definition
@ -62,7 +66,7 @@ static double targetTime = 0; // Desired time for one frame, if 0
static int windowWidth, windowHeight; // Required to switch between windowed/fullscren mode (F11)
static const char *windowTitle; // Required to switch between windowed/fullscren mode (F11)
static int exitKey = GLFW_KEY_ESCAPE;
static int exitKey = GLFW_KEY_ESCAPE; // Default exit key (ESC)
static bool customCursor = false; // Tracks if custom cursor has been set
static bool cursorOnScreen = false; // Tracks if cursor is inside client area
@ -77,8 +81,10 @@ static char currentMouseState[3] = { 0 }; // Required to check if mouse btn pr
static char previousGamepadState[32] = {0}; // Required to check if gamepad btn pressed/released once
static char currentGamepadState[32] = {0}; // Required to check if gamepad btn pressed/released once
static int previousMouseWheelY = 0;
static int currentMouseWheelY = 0;
static int previousMouseWheelY = 0; // Required to track mouse wheel variation
static int currentMouseWheelY = 0; // Required to track mouse wheel variation
static Color background = { 0, 0, 0, 0 }; // Screen background color
//----------------------------------------------------------------------------------
// Other Modules Functions Declaration (required by core)
@ -86,16 +92,17 @@ static int currentMouseWheelY = 0;
extern void LoadDefaultFont(); // [Module: text] Loads default font on InitWindow()
extern void UnloadDefaultFont(); // [Module: text] Unloads default font from GPU memory
extern bool MusicStreamUpdate(); // [Module: audio] Updates buffers for music streamming
extern void PlayCurrentMusic(); // [Module: audio] Plays current music stream
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
static void InitGraphicsDevice(); // Initialize Graphics Device (OpenGL stuff)
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); // GLFW3 Srolling Callback, runs on mouse wheel
static void CursorEnterCallback(GLFWwindow* window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area
static void WindowSizeCallback(GLFWwindow* window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
static void CameraLookAt(Vector3 position, Vector3 target, Vector3 up); // Setup camera view (updates MODELVIEW matrix)
static void TakeScreenshot(); // Takes a bitmap (BMP) screenshot and saves it in the same folder as executable
//----------------------------------------------------------------------------------
@ -113,12 +120,20 @@ void InitWindowEx(int width, int height, const char* title, bool resizable, cons
{
glfwSetErrorCallback(ErrorCallback);
if (!glfwInit()) exit(1);
if (!glfwInit()) TraceLog(ERROR, "Failed to initialize GLFW");
//glfwDefaultWindowHints() // Set default windows hints
//glfwWindowHint(GLFW_SAMPLES, 4); // If called before windows creation, enables multisampling x4 (MSAA), default is 0
if (!resizable) glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); // Avoid window being resizable
#ifdef USE_OPENGL_33
//glfwWindowHint(GLFW_SAMPLES, 4); // Enables multisampling x4 (MSAA), default is 0
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_FALSE);
#endif
window = glfwCreateWindow(width, height, title, NULL, NULL);
windowWidth = width;
@ -128,7 +143,7 @@ void InitWindowEx(int width, int height, const char* title, bool resizable, cons
if (!window)
{
glfwTerminate();
exit(1);
TraceLog(ERROR, "Failed to initialize Window");
}
glfwSetWindowSizeCallback(window, WindowSizeCallback);
@ -140,21 +155,41 @@ void InitWindowEx(int width, int height, const char* title, bool resizable, cons
glfwSwapInterval(0); // Disables GPU v-sync (if set), so frames are not limited to screen refresh rate (60Hz -> 60 FPS)
// If not set, swap interval uses GPU v-sync configuration
// Framerate can be setup using SetTargetFPS()
InitGraphicsDevice();
//------------------------------------------------------
#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();
LoadDefaultFont(); // NOTE: External function (defined in module: text)
if (cursorImage != NULL) SetCustomCursor(cursorImage);
srand(time(NULL)); // Initialize random seed
srand(time(NULL)); // Initialize random seed
ClearBackground(RAYWHITE); // Default background color for raylib games :P
}
// Close Window and Terminate Context
void CloseWindow()
{
UnloadDefaultFont();
//------------------------------------------------------
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
rlglClose(); // De-init rlgl
#endif
//------------------------------------------------------
glfwDestroyWindow(window);
glfwTerminate();
@ -198,19 +233,30 @@ void ToggleFullscreen()
// TODO: WARNING! All loaded resources are lost, we loose Context!
// NOTE: Window aspect ratio is always windowWidth / windowHeight
if (fullscreen) window = glfwCreateWindow(windowWidth, windowHeight, windowTitle, glfwGetPrimaryMonitor(), NULL); // Fullscreen mode
if (fullscreen)
{
// TODO: Get desktop window size and adapt aspect-ratio (?)
//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);
if (!window)
{
glfwTerminate();
exit(1);
TraceLog(ERROR, "Failed to initialize Window when switching fullscreen mode");
}
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, KeyCallback);
InitGraphicsDevice();
int fbWidth, fbHeight;
glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window
rlglInitGraphicsDevice(fbWidth, fbHeight);
LoadDefaultFont();
}
@ -219,13 +265,12 @@ void ToggleFullscreen()
// Sets Background Color
void ClearBackground(Color color)
{
// Color values clamp to 0.0f(0) and 1.0f(255)
float r = (float)color.r / 255;
float g = (float)color.g / 255;
float b = (float)color.b / 255;
float a = (float)color.a / 255;
glClearColor(r, g, b, a);
if ((color.r != background.r) || (color.g != background.g) || (color.b != background.b) || (color.a != background.a))
{
rlClearColor(color.r, color.g, color.b, color.a);
background = color;
}
}
// Setup drawing canvas to start drawing
@ -235,11 +280,14 @@ void BeginDrawing()
updateTime = currentTime - previousTime;
previousTime = currentTime;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear used buffers, Depth Buffer is used for 3D
rlClearScreenBuffers();
glLoadIdentity(); // Reset current matrix (MODELVIEW)
glTranslatef(0.375, 0.375, 0); // HACK to have 2D pixel-perfect drawing on OpenGL
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
//#ifdef USE_OPENGL_11
// rlTranslatef(0.375, 0.375, 0); // HACK to have 2D pixel-perfect drawing on OpenGL
// NOTE: Not required with OpenGL 3.3+
//#endif
}
// End canvas drawing and Swap Buffers (Double Buffering)
@ -247,9 +295,19 @@ void EndDrawing()
{
if (customCursor && cursorOnScreen) DrawTexture(cursor, GetMouseX(), GetMouseY(), WHITE);
//------------------------------------------------------
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
rlglDraw(); // Draw Buffers
#endif
//------------------------------------------------------
glfwSwapBuffers(window); // Swap back and front buffers
glfwPollEvents(); // Register keyboard/mouse events
//MusicStreamUpdate();
//if (!MusicIsPlaying())
//PlayCurrentMusic();
currentTime = glfwGetTime();
drawTime = currentTime - previousTime;
previousTime = currentTime;
@ -271,34 +329,48 @@ void EndDrawing()
// Initializes 3D mode for drawing (Camera setup)
void Begin3dMode(Camera camera)
{
glMatrixMode(GL_PROJECTION); // Switch to projection matrix
//------------------------------------------------------
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
rlglDraw(); // Draw Buffers
#endif
//------------------------------------------------------
rlMatrixMode(RL_PROJECTION); // Switch to projection matrix
glPushMatrix(); // Save previous matrix, which contains the settings for the 2d ortho projection
glLoadIdentity(); // Reset current matrix (PROJECTION)
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;
glFrustum(-right, right, -top, top, 0.1f, 100.0f);
rlFrustum(-right, right, -top, top, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW); // Switch back to modelview matrix
glLoadIdentity(); // Reset current matrix (MODELVIEW)
rlMatrixMode(RL_MODELVIEW); // Switch back to modelview matrix
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
CameraLookAt(camera.position, camera.target, camera.up); // Setup Camera view
// Setup Camera view
Matrix matLookAt = MatrixLookAt(camera.position, camera.target, camera.up);
rlMultMatrixf(GetMatrixVector(matLookAt)); // Multiply MODELVIEW matrix by view matrix (camera)
}
// Ends 3D mode and returns to default 2D orthographic mode
void End3dMode()
{
glMatrixMode(GL_PROJECTION); // Switch to projection matrix
glPopMatrix(); // Restore previous matrix (PROJECTION) from matrix stack
//------------------------------------------------------
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
rlglDraw(); // Draw Buffers
#endif
//------------------------------------------------------
rlMatrixMode(RL_PROJECTION); // Switch to projection matrix
rlPopMatrix(); // Restore previous matrix (PROJECTION) from matrix stack
glMatrixMode(GL_MODELVIEW); // Get back to modelview matrix
glLoadIdentity(); // Reset current matrix (MODELVIEW)
rlMatrixMode(RL_MODELVIEW); // Get back to modelview matrix
rlLoadIdentity(); // Reset current matrix (MODELVIEW)
glTranslatef(0.375, 0.375, 0); // HACK to ensure pixel-perfect drawing on OpenGL (after exiting 3D mode)
//rlTranslatef(0.375, 0.375, 0); // HACK to ensure pixel-perfect drawing on OpenGL (after exiting 3D mode)
}
// Set target FPS for the game
@ -306,7 +378,7 @@ void SetTargetFPS(int fps)
{
targetTime = 1 / (float)fps;
printf("TargetTime per Frame: %f seconds\n", (float)targetTime);
TraceLog(INFO, "Target time per frame: %02.03f milliseconds", (float)targetTime*1000);
}
// Returns current FPS
@ -374,18 +446,18 @@ Color Fade(Color color, float alpha)
// Detect if a key has been pressed once
bool IsKeyPressed(int key)
{
bool ret = false;
bool pressed = false;
currentKeyState[key] = IsKeyDown(key);
if (currentKeyState[key] != previousKeyState[key])
{
if (currentKeyState[key]) ret = true;
if (currentKeyState[key]) pressed = true;
previousKeyState[key] = currentKeyState[key];
}
else ret = false;
else pressed = false;
return ret;
return pressed;
}
// Detect if a key is being pressed (key held down)
@ -398,18 +470,18 @@ bool IsKeyDown(int key)
// Detect if a key has been released once
bool IsKeyReleased(int key)
{
bool ret = false;
bool released = false;
currentKeyState[key] = IsKeyUp(key);
if (currentKeyState[key] != previousKeyState[key])
{
if (currentKeyState[key]) ret = true;
if (currentKeyState[key]) released = true;
previousKeyState[key] = currentKeyState[key];
}
else ret = false;
else released = false;
return ret;
return released;
}
// Detect if a key is NOT being pressed (key not held down)
@ -422,18 +494,18 @@ bool IsKeyUp(int key)
// Detect if a mouse button has been pressed once
bool IsMouseButtonPressed(int button)
{
bool ret = false;
bool pressed = false;
currentMouseState[button] = IsMouseButtonDown(button);
if (currentMouseState[button] != previousMouseState[button])
{
if (currentMouseState[button]) ret = true;
if (currentMouseState[button]) pressed = true;
previousMouseState[button] = currentMouseState[button];
}
else ret = false;
else pressed = false;
return ret;
return pressed;
}
// Detect if a mouse button is being pressed
@ -446,18 +518,18 @@ bool IsMouseButtonDown(int button)
// Detect if a mouse button has been released once
bool IsMouseButtonReleased(int button)
{
bool ret = false;
bool released = false;
currentMouseState[button] = IsMouseButtonUp(button);
if (currentMouseState[button] != previousMouseState[button])
{
if (currentMouseState[button]) ret = true;
if (currentMouseState[button]) released = true;
previousMouseState[button] = currentMouseState[button];
}
else ret = false;
else released = false;
return ret;
return released;
}
// Detect if a mouse button is NOT being pressed
@ -546,18 +618,18 @@ Vector2 GetGamepadMovement(int gamepad)
// Detect if a gamepad button is being pressed
bool IsGamepadButtonPressed(int gamepad, int button)
{
bool ret = false;
bool pressed = false;
currentGamepadState[button] = IsGamepadButtonDown(gamepad, button);
if (currentGamepadState[button] != previousGamepadState[button])
{
if (currentGamepadState[button]) ret = true;
if (currentGamepadState[button]) pressed = true;
previousGamepadState[button] = currentGamepadState[button];
}
else ret = false;
else pressed = false;
return ret;
return pressed;
}
bool IsGamepadButtonDown(int gamepad, int button)
@ -577,18 +649,18 @@ bool IsGamepadButtonDown(int gamepad, int button)
// Detect if a gamepad button is NOT being pressed
bool IsGamepadButtonReleased(int gamepad, int button)
{
bool ret = false;
bool released = false;
currentGamepadState[button] = IsGamepadButtonUp(gamepad, button);
if (currentGamepadState[button] != previousGamepadState[button])
{
if (currentGamepadState[button]) ret = true;
if (currentGamepadState[button]) released = true;
previousGamepadState[button] = currentGamepadState[button];
}
else ret = false;
else released = false;
return ret;
return released;
}
bool IsGamepadButtonUp(int gamepad, int button)
@ -612,8 +684,7 @@ bool IsGamepadButtonUp(int gamepad, int button)
// GLFW3 Error Callback, runs on GLFW3 error
static void ErrorCallback(int error, const char *description)
{
printf(description);
//fprintf(stderr, description);
TraceLog(WARNING, "GLFW3 Error: %s", description);
}
// GLFW3 Srolling Callback, runs on mouse wheel
@ -649,125 +720,32 @@ static void CursorEnterCallback(GLFWwindow* window, int enter)
// GLFW3 WindowSize Callback, runs when window is resized
static void WindowSizeCallback(GLFWwindow* window, int width, int height)
{
InitGraphicsDevice(); // If window is resized, graphics device is re-initialized
// NOTE: Aspect ratio does not change, so, image can be deformed
}
// Initialize Graphics Device (OpenGL stuff)
static void InitGraphicsDevice()
{
int fbWidth, fbHeight;
glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window
glViewport(0, 0, fbWidth, fbHeight); // Set viewport width and height
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear used buffers, depth buffer is used for 3D
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Set background color (black)
glClearDepth(1.0f); // Clear depth buffer
glEnable(GL_DEPTH_TEST); // Enables depth testing (required for 3D)
glDepthFunc(GL_LEQUAL); // Type of depth testing to apply
glEnable(GL_BLEND); // Enable color blending (required to work with transparencies)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Color blending function (how colors are mixed)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Improve quality of color and texture coordinate interpolation (Deprecated in OGL 3.0)
// Other options: GL_FASTEST, GL_DONT_CARE (default)
glMatrixMode(GL_PROJECTION); // Switch to PROJECTION matrix
glLoadIdentity(); // Reset current matrix (PROJECTION)
glOrtho(0, fbWidth, fbHeight, 0, 0, 1); // Config orthographic mode: top-left corner --> (0,0)
glMatrixMode(GL_MODELVIEW); // Switch back to MODELVIEW matrix
glLoadIdentity(); // Reset current matrix (MODELVIEW)
// TODO: Review all shapes/models are drawn CCW and enable backface culling
//glEnable(GL_CULL_FACE); // Enable backface culling (Disabled by default)
//glCullFace(GL_BACK); // Cull the Back face (default)
//glFrontFace(GL_CCW); // Front face are defined counter clockwise (default)
glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation)
// Possible options: GL_SMOOTH (Color interpolation) or GL_FLAT (no interpolation)
}
// Setup camera view (updates MODELVIEW matrix)
static void CameraLookAt(Vector3 position, Vector3 target, Vector3 up)
{
float rotMatrix[16]; // Matrix to store camera rotation
Vector3 rotX, rotY, rotZ; // Vectors to calculate camera rotations X, Y, Z (Euler)
// Construct rotation matrix from vectors
rotZ = VectorSubtract(position, target);
VectorNormalize(&rotZ);
rotY = up; // Y rotation vector
rotX = VectorCrossProduct(rotY, rotZ); // X rotation vector = Y cross Z
rotY = VectorCrossProduct(rotZ, rotX); // Recompute Y rotation = Z cross X
VectorNormalize(&rotX); // X rotation vector normalization
VectorNormalize(&rotY); // Y rotation vector normalization
rotMatrix[0] = rotX.x;
rotMatrix[1] = rotY.x;
rotMatrix[2] = rotZ.x;
rotMatrix[3] = 0.0f;
rotMatrix[4] = rotX.y;
rotMatrix[5] = rotY.y;
rotMatrix[6] = rotZ.y;
rotMatrix[7] = 0.0f;
rotMatrix[8] = rotX.z;
rotMatrix[9] = rotY.z;
rotMatrix[10] = rotZ.z;
rotMatrix[11] = 0.0f;
rotMatrix[12] = 0.0f;
rotMatrix[13] = 0.0f;
rotMatrix[14] = 0.0f;
rotMatrix[15] = 1.0f;
glMultMatrixf(rotMatrix); // Multiply MODELVIEW matrix by rotation matrix
glTranslatef(-position.x, -position.y, -position.z); // Translate eye to position
// If window is resized, graphics device is re-initialized
// NOTE: Aspect ratio does not change, so, image can be deformed
rlglInitGraphicsDevice(fbWidth, fbHeight);
}
// Takes a bitmap (BMP) screenshot and saves it in the same folder as executable
static void TakeScreenshot()
{
static int shotNum = 0; // Screenshot number, increments every screenshot take during program execution
char buffer[20]; // Buffer to store file name
int fbWidth, fbHeight;
unsigned char *imgData; // Pixel image data array
int fbWidth, fbHeight; // Frame buffer width and height
glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window
imgData = (unsigned char *)malloc(fbWidth * fbHeight * sizeof(unsigned char) * 4);
unsigned char *imgData = rlglReadScreenPixels(fbWidth, fbHeight);
// NOTE: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer
glReadPixels(0, 0, fbWidth, fbHeight, GL_RGBA, GL_UNSIGNED_BYTE, imgData);
// TODO: Flip image vertically!
unsigned char *imgDataFlip = (unsigned char *)malloc(fbWidth * fbHeight * sizeof(unsigned char) * 4);
for (int y = fbHeight-1; y >= 0; y--)
{
for (int x = 0; x < (fbWidth*4); x++)
{
imgDataFlip[x + (fbHeight - y - 1)*fbWidth*4] = imgData[x + (y*fbWidth*4)];
}
}
free(imgData);
sprintf(buffer, "screenshot%03i.png", shotNum);
// NOTE: BMP directly stores data flipped vertically
//WriteBitmap(buffer, imgDataPixel, fbWidth, fbHeight); // Writes pixel data array into a bitmap (BMP) file
WritePNG(buffer, imgDataFlip, fbWidth, fbHeight);
free(imgDataFlip);
WritePNG(buffer, imgData, fbWidth, fbHeight);
free(imgData);
shotNum++;
}

File diff suppressed because it is too large Load diff

View file

@ -1,15 +1,17 @@
/*********************************************************************************************
*
* raylib 1.0.6 (www.raylib.com)
* raylib 1.1 (www.raylib.com)
*
* A simple and easy-to-use library to learn videogames programming
*
* Features:
* Library written in plain C code (C99)
* Uses C# PascalCase/camelCase notation
* Hardware accelerated with OpenGL 1.1
* Hardware accelerated with OpenGL (1.1, 3.3+ or ES2)
* Unique OpenGL abstraction layer [rlgl]
* Powerful fonts module with SpriteFonts support
* Basic 3d support for Shapes and Models
* Basic 3d support for Shapes, Models, Heightmaps and Billboards
* Powerful math module for Vector and Matrix operations [raymath]
* Audio loading and playing
*
* Used external libs:
@ -23,8 +25,9 @@
* 32bit Textures - All loaded images are converted automatically to RGBA textures
* SpriteFonts - All loaded sprite-font images are converted to RGBA and POT textures
* One custom default font is loaded automatically when InitWindow()
* If using OpenGL 3.3+, one default shader is loaded automatically (internally defined)
*
* -- LICENSE (raylib v1.0, November 2013) --
* -- LICENSE (raylib v1.1, March 2014) --
*
* 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:
@ -51,6 +54,8 @@
#ifndef RAYLIB_H
#define RAYLIB_H
#include "stb_vorbis.h"
//----------------------------------------------------------------------------------
// Some basic Defines
//----------------------------------------------------------------------------------
@ -150,6 +155,19 @@
// Boolean type
typedef enum { false, true } bool;
// Vector2 type
typedef struct Vector2 {
float x;
float y;
} Vector2;
// Vector3 type
typedef struct Vector3 {
float x;
float y;
float z;
} Vector3;
// Color type, RGBA (32bit)
typedef struct Color {
unsigned char r;
@ -182,29 +200,6 @@ typedef struct Texture2D {
int height;
} Texture2D;
// SpriteFont one Character (Glyph) data, defined in text module
typedef struct Character Character;
// SpriteFont type, includes texture and charSet array data
typedef struct SpriteFont {
Texture2D texture;
int numChars;
Character *charSet;
} SpriteFont;
// Vector2 type
typedef struct Vector2 {
float x;
float y;
} Vector2;
// Vector3 type
typedef struct Vector3 {
float x;
float y;
float z;
} Vector3;
// Camera type, defines a camera position/orientation in 3d space
typedef struct Camera {
Vector3 position;
@ -212,20 +207,42 @@ typedef struct Camera {
Vector3 up;
} Camera;
// Basic 3d Model type
typedef struct Model {
int numVertices;
Vector3 *vertices;
Vector2 *texcoords;
Vector3 *normals;
} Model;
typedef struct Character Character;
// Basic Sound source and buffer
// SpriteFont type
typedef struct SpriteFont {
Texture2D texture;
int numChars;
Character *charSet;
} SpriteFont;
// 3d Model type
// NOTE: If using OpenGL 1.1 loaded in CPU; if OpenGL 3.3+ loaded in GPU
typedef struct Model Model; // Defined in module: rlgl
// Sound source type
typedef struct Sound {
unsigned int source;
unsigned int buffer;
} Sound;
typedef struct OggStream OggStream;
// Music type (streamming)
typedef struct Music {
stb_vorbis *stream;
stb_vorbis_info info;
unsigned int source;
unsigned int buffers[2];
int format;
int bufferSize;
int totalSamplesLeft;
bool loop;
} Music;
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
@ -357,15 +374,17 @@ const char *FormatText(const char *text, ...);
void DrawCube(Vector3 position, float width, float height, float lenght, Color color); // Draw cube
void DrawCubeV(Vector3 position, Vector3 size, Color color); // Draw cube (Vector version)
void DrawCubeWires(Vector3 position, float width, float height, float lenght, Color color); // Draw cube wires
void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float lenght, Color color); // Draw cube textured
void DrawSphere(Vector3 centerPos, float radius, Color color); // Draw sphere
void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere with extended parameters
void DrawSphereWires(Vector3 centerPos, float radius, Color color); // Draw sphere wires
void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color); // Draw sphere wires
void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone
void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color); // Draw a cylinder/cone wires
void DrawPlane(Vector3 centerPos, Vector2 size, Vector3 rotation, Color color); // Draw a plane
void DrawPlaneEx(Vector3 centerPos, Vector2 size, Vector3 rotation, int slicesX, int slicesZ, Color color); // Draw a plane with divisions
void DrawGrid(int slices, float spacing); // Draw a grid (centered at (0, 0, 0))
void DrawGizmo(Vector3 position, bool orbits); // Draw gizmo (with or without orbits)
void DrawGizmo(Vector3 position); // Draw simple gizmo
void DrawGizmoEx(Vector3 position, Vector3 rot, float scale, bool orbits); // Draw gizmo with extended parameters
//DrawTorus(), DrawTeapot() are useless...
//------------------------------------------------------------------------------------
@ -389,13 +408,18 @@ void CloseAudioDevice(); // Close the aud
Sound LoadSound(char *fileName); // Load sound to memory
Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource)
void UnloadSound(Sound sound); // Unload sound
Music LoadMusic(char *fileName);
void UnloadMusic(Music music);
void PlaySound(Sound sound); // Play a sound
void PauseSound(Sound sound); // Pause a sound
void StopSound(Sound sound); // Stop playing a sound
bool IsPlaying(Sound sound); // Check if a sound is currently playing
bool SoundIsPlaying(Sound sound); // Check if a sound is currently playing
void SetVolume(Sound sound, float volume); // Set volume for a sound (1.0 is base level)
void SetPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level)
void PlayMusic(Music music);
void StopMusic(Music music);
bool MusicIsPlaying();
#ifdef __cplusplus
}

View file

@ -199,6 +199,28 @@ Vector3 VectorReflect(Vector3 vector, Vector3 normal)
return result;
}
// Transforms a Vector3 with a given Matrix
void VectorTransform(Vector3 *v, Matrix mat)
{
float x = v->x;
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;
};
// Return a Vector3 init to zero
Vector3 VectorZero()
{
Vector3 zero = { 0.0, 0.0, 0.0 };
return zero;
}
//----------------------------------------------------------------------------------
// Module Functions Definition - Matrix math
//----------------------------------------------------------------------------------
@ -234,17 +256,17 @@ float MatrixDeterminant(Matrix mat)
float result;
// 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 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;
result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 +
a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 +
a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 +
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;
result = a30*a21*a12*a03 - a20*a31*a12*a03 - a30*a11*a22*a03 + a10*a31*a22*a03 +
a20*a11*a32*a03 - a10*a21*a32*a03 - a30*a21*a02*a13 + a20*a31*a02*a13 +
a30*a01*a22*a13 - a00*a31*a22*a13 - a20*a01*a32*a13 + a00*a21*a32*a13 +
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;
}
@ -261,21 +283,21 @@ void MatrixTranspose(Matrix *mat)
Matrix temp;
temp.m0 = mat->m0;
temp.m1 = mat->m4;
temp.m2 = mat->m8;
temp.m3 = mat->m12;
temp.m4 = mat->m1;
temp.m5 = mat->m5;
temp.m6 = mat->m9;
temp.m7 = mat->m13;
temp.m8 = mat->m2;
temp.m9 = mat->m6;
temp.m10 = mat->m10;
temp.m11 = mat->m14;
temp.m12 = mat->m3;
temp.m13 = mat->m7;
temp.m14 = mat->m11;
temp.m15 = mat->m15;
temp.m1 = mat->m4;
temp.m2 = mat->m8;
temp.m3 = mat->m12;
temp.m4 = mat->m1;
temp.m5 = mat->m5;
temp.m6 = mat->m9;
temp.m7 = mat->m13;
temp.m8 = mat->m2;
temp.m9 = mat->m6;
temp.m10 = mat->m10;
temp.m11 = mat->m14;
temp.m12 = mat->m3;
temp.m13 = mat->m7;
temp.m14 = mat->m11;
temp.m15 = mat->m15;
*mat = temp;
}
@ -285,50 +307,50 @@ void MatrixInvert(Matrix *mat)
{
Matrix temp;
// Cache the matrix values (speed optimization)
// Cache the matrix values (speed optimization)
float a00 = mat->m0, a01 = mat->m1, a02 = mat->m2, a03 = mat->m3;
float 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;
float b03 = a01*a12 - a02*a11;
float b04 = a01*a13 - a03*a11;
float b05 = a02*a13 - a03*a12;
float b06 = a20*a31 - a21*a30;
float b07 = a20*a32 - a22*a30;
float b08 = a20*a33 - a23*a30;
float b09 = a21*a32 - a22*a31;
float b10 = a21*a33 - a23*a31;
float b11 = a22*a33 - a23*a32;
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;
// Calculate the invert determinant (inlined to avoid double-caching)
float invDet = 1/(b00*b11 - b01*b10 + b02*b09 + b03*b08 - b04*b07 + b05*b06);
float b00 = a00*a11 - a01*a10;
float b01 = a00*a12 - a02*a10;
float b02 = a00*a13 - a03*a10;
float b03 = a01*a12 - a02*a11;
float b04 = a01*a13 - a03*a11;
float b05 = a02*a13 - a03*a12;
float b06 = a20*a31 - a21*a30;
float b07 = a20*a32 - a22*a30;
float b08 = a20*a33 - a23*a30;
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;
temp.m3 = (-a21*b05 + a22*b04 - a23*b03)*invDet;
temp.m4 = (-a10*b11 + a12*b08 - a13*b07)*invDet;
temp.m5 = (a00*b11 - a02*b08 + a03*b07)*invDet;
temp.m6 = (-a30*b05 + a32*b02 - a33*b01)*invDet;
temp.m7 = (a20*b05 - a22*b02 + a23*b01)*invDet;
temp.m8 = (a10*b10 - a11*b08 + a13*b06)*invDet;
temp.m9 = (-a00*b10 + a01*b08 - a03*b06)*invDet;
temp.m10 = (a30*b04 - a31*b02 + a33*b00)*invDet;
temp.m11 = (-a20*b04 + a21*b02 - a23*b00)*invDet;
temp.m12 = (-a10*b09 + a11*b07 - a12*b06)*invDet;
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;
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;
temp.m3 = (-a21*b05 + a22*b04 - a23*b03)*invDet;
temp.m4 = (-a10*b11 + a12*b08 - a13*b07)*invDet;
temp.m5 = (a00*b11 - a02*b08 + a03*b07)*invDet;
temp.m6 = (-a30*b05 + a32*b02 - a33*b01)*invDet;
temp.m7 = (a20*b05 - a22*b02 + a23*b01)*invDet;
temp.m8 = (a10*b10 - a11*b08 + a13*b06)*invDet;
temp.m9 = (-a00*b10 + a01*b08 - a03*b06)*invDet;
temp.m10 = (a30*b04 - a31*b02 + a33*b00)*invDet;
temp.m11 = (-a20*b04 + a21*b02 - a23*b00)*invDet;
temp.m12 = (-a10*b09 + a11*b07 - a12*b06)*invDet;
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;
*mat = temp;
}
// Normalize provided matrix
@ -337,21 +359,21 @@ void MatrixNormalize(Matrix *mat)
float det = MatrixDeterminant(*mat);
mat->m0 /= det;
mat->m1 /= det;
mat->m2 /= det;
mat->m3 /= det;
mat->m4 /= det;
mat->m5 /= det;
mat->m6 /= det;
mat->m7 /= det;
mat->m8 /= det;
mat->m9 /= det;
mat->m10 /= det;
mat->m11 /= det;
mat->m12 /= det;
mat->m13 /= det;
mat->m14 /= det;
mat->m15 /= det;
mat->m1 /= det;
mat->m2 /= det;
mat->m3 /= det;
mat->m4 /= det;
mat->m5 /= det;
mat->m6 /= det;
mat->m7 /= det;
mat->m8 /= det;
mat->m9 /= det;
mat->m10 /= det;
mat->m11 /= det;
mat->m12 /= det;
mat->m13 /= det;
mat->m14 /= det;
mat->m15 /= det;
}
// Returns identity matrix
@ -368,21 +390,21 @@ 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;
result.m3 = left.m3 + right.m3;
result.m4 = left.m4 + right.m4;
result.m5 = left.m5 + right.m5;
result.m6 = left.m6 + right.m6;
result.m7 = left.m7 + right.m7;
result.m8 = left.m8 + right.m8;
result.m9 = left.m9 + right.m9;
result.m10 = left.m10 + right.m10;
result.m11 = left.m11 + right.m11;
result.m12 = left.m12 + right.m12;
result.m13 = left.m13 + right.m13;
result.m14 = left.m14 + right.m14;
result.m15 = left.m15 + right.m15;
result.m1 = left.m1 + right.m1;
result.m2 = left.m2 + right.m2;
result.m3 = left.m3 + right.m3;
result.m4 = left.m4 + right.m4;
result.m5 = left.m5 + right.m5;
result.m6 = left.m6 + right.m6;
result.m7 = left.m7 + right.m7;
result.m8 = left.m8 + right.m8;
result.m9 = left.m9 + right.m9;
result.m10 = left.m10 + right.m10;
result.m11 = left.m11 + right.m11;
result.m12 = left.m12 + right.m12;
result.m13 = left.m13 + right.m13;
result.m14 = left.m14 + right.m14;
result.m15 = left.m15 + right.m15;
return result;
}
@ -393,21 +415,21 @@ 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;
result.m3 = left.m3 - right.m3;
result.m4 = left.m4 - right.m4;
result.m5 = left.m5 - right.m5;
result.m6 = left.m6 - right.m6;
result.m7 = left.m7 - right.m7;
result.m8 = left.m8 - right.m8;
result.m9 = left.m9 - right.m9;
result.m10 = left.m10 - right.m10;
result.m11 = left.m11 - right.m11;
result.m12 = left.m12 - right.m12;
result.m13 = left.m13 - right.m13;
result.m14 = left.m14 - right.m14;
result.m15 = left.m15 - right.m15;
result.m1 = left.m1 - right.m1;
result.m2 = left.m2 - right.m2;
result.m3 = left.m3 - right.m3;
result.m4 = left.m4 - right.m4;
result.m5 = left.m5 - right.m5;
result.m6 = left.m6 - right.m6;
result.m7 = left.m7 - right.m7;
result.m8 = left.m8 - right.m8;
result.m9 = left.m9 - right.m9;
result.m10 = left.m10 - right.m10;
result.m11 = left.m11 - right.m11;
result.m12 = left.m12 - right.m12;
result.m13 = left.m13 - right.m13;
result.m14 = left.m14 - right.m14;
result.m15 = left.m15 - right.m15;
return result;
}
@ -476,51 +498,51 @@ Matrix MatrixFromAxisAngle(Vector3 axis, float angle)
Matrix mat = MatrixIdentity();
float x = axis.x, y = axis.y, z = axis.z;
float x = axis.x, y = axis.y, z = axis.z;
float length = sqrt(x*x + y*y + z*z);
float length = sqrt(x*x + y*y + z*z);
if ((length != 1) && (length != 0))
if ((length != 1) && (length != 0))
{
length = 1 / length;
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;
result.m2 = a02*b00 + a12*b01 + a22*b02;
result.m3 = a03*b00 + a13*b01 + a23*b02;
result.m4 = a00*b10 + a10*b11 + a20*b12;
result.m5 = a01*b10 + a11*b11 + a21*b12;
result.m6 = a02*b10 + a12*b11 + a22*b12;
result.m7 = a03*b10 + a13*b11 + a23*b12;
result.m8 = a00*b20 + a10*b21 + a20*b22;
result.m9 = a01*b20 + a11*b21 + a21*b22;
result.m10 = a02*b20 + a12*b21 + a22*b22;
result.m11 = a03*b20 + a13*b21 + a23*b22;
result.m12 = mat.m12;
result.m13 = mat.m13;
result.m14 = mat.m14;
result.m15 = mat.m15;
length = 1 / length;
x *= length;
y *= length;
z *= length;
}
return result;
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;
result.m2 = a02*b00 + a12*b01 + a22*b02;
result.m3 = a03*b00 + a13*b01 + a23*b02;
result.m4 = a00*b10 + a10*b11 + a20*b12;
result.m5 = a01*b10 + a11*b11 + a21*b12;
result.m6 = a02*b10 + a12*b11 + a22*b12;
result.m7 = a03*b10 + a13*b11 + a23*b12;
result.m8 = a00*b20 + a10*b21 + a20*b22;
result.m9 = a01*b20 + a11*b21 + a21*b22;
result.m10 = a02*b20 + a12*b21 + a22*b22;
result.m11 = a03*b20 + a13*b21 + a23*b22;
result.m12 = mat.m12;
result.m13 = mat.m13;
result.m14 = mat.m14;
result.m15 = mat.m15;
return result;
};
// Create rotation matrix from axis and angle
@ -645,35 +667,35 @@ Matrix MatrixMultiply(Matrix left, Matrix right)
{
Matrix result;
// Cache the matrix values (speed optimization)
float a00 = left.m0, a01 = left.m1, a02 = left.m2, a03 = left.m3;
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;
result.m3 = b00*a03 + b01*a13 + b02*a23 + b03*a33;
result.m4 = b10*a00 + b11*a10 + b12*a20 + b13*a30;
result.m5 = b10*a01 + b11*a11 + b12*a21 + b13*a31;
result.m6 = b10*a02 + b11*a12 + b12*a22 + b13*a32;
result.m7 = b10*a03 + b11*a13 + b12*a23 + b13*a33;
result.m8 = b20*a00 + b21*a10 + b22*a20 + b23*a30;
result.m9 = b20*a01 + b21*a11 + b22*a21 + b23*a31;
result.m10 = b20*a02 + b21*a12 + b22*a22 + b23*a32;
result.m11 = b20*a03 + b21*a13 + b22*a23 + b23*a33;
result.m12 = b30*a00 + b31*a10 + b32*a20 + b33*a30;
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;
// Cache the matrix values (speed optimization)
float a00 = left.m0, a01 = left.m1, a02 = left.m2, a03 = left.m3;
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;
result.m3 = b00*a03 + b01*a13 + b02*a23 + b03*a33;
result.m4 = b10*a00 + b11*a10 + b12*a20 + b13*a30;
result.m5 = b10*a01 + b11*a11 + b12*a21 + b13*a31;
result.m6 = b10*a02 + b11*a12 + b12*a22 + b13*a32;
result.m7 = b10*a03 + b11*a13 + b12*a23 + b13*a33;
result.m8 = b20*a00 + b21*a10 + b22*a20 + b23*a30;
result.m9 = b20*a01 + b21*a11 + b22*a21 + b23*a31;
result.m10 = b20*a02 + b21*a12 + b22*a22 + b23*a32;
result.m11 = b20*a03 + b21*a13 + b22*a23 + b23*a33;
result.m12 = b30*a00 + b31*a10 + b32*a20 + b33*a30;
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
@ -681,28 +703,28 @@ Matrix MatrixFrustum(double left, double right, double bottom, double top, doubl
{
Matrix result;
float rl = (right - left);
float tb = (top - bottom);
float fn = (far - near);
float rl = (right - left);
float tb = (top - bottom);
float fn = (far - near);
result.m0 = (near*2) / rl;
result.m1 = 0;
result.m2 = 0;
result.m3 = 0;
result.m4 = 0;
result.m5 = (near*2) / tb;
result.m6 = 0;
result.m7 = 0;
result.m8 = (right + left) / rl;
result.m9 = (top + bottom) / tb;
result.m10 = -(far + near) / fn;
result.m11 = -1;
result.m12 = 0;
result.m13 = 0;
result.m14 = -(far*near*2) / fn;
result.m15 = 0;
result.m0 = (near*2) / rl;
result.m1 = 0;
result.m2 = 0;
result.m3 = 0;
result.m4 = 0;
result.m5 = (near*2) / tb;
result.m6 = 0;
result.m7 = 0;
result.m8 = (right + left) / rl;
result.m9 = (top + bottom) / tb;
result.m10 = -(far + near) / fn;
result.m11 = -1;
result.m12 = 0;
result.m13 = 0;
result.m14 = -(far*near*2) / fn;
result.m15 = 0;
return result;
return result;
}
// Returns perspective projection matrix
@ -720,25 +742,25 @@ Matrix MatrixOrtho(double left, double right, double bottom, double top, double
Matrix result;
float rl = (right - left);
float tb = (top - bottom);
float fn = (far - near);
float tb = (top - bottom);
float fn = (far - near);
result.m0 = 2 / rl;
result.m1 = 0;
result.m2 = 0;
result.m3 = 0;
result.m4 = 0;
result.m5 = 2 / tb;
result.m6 = 0;
result.m7 = 0;
result.m8 = 0;
result.m9 = 0;
result.m10 = -2 / fn;
result.m11 = 0;
result.m12 = -(left + right) / rl;
result.m13 = -(top + bottom) / tb;
result.m14 = -(far + near) / fn;
result.m15 = 1;
result.m1 = 0;
result.m2 = 0;
result.m3 = 0;
result.m4 = 0;
result.m5 = 2 / tb;
result.m6 = 0;
result.m7 = 0;
result.m8 = 0;
result.m9 = 0;
result.m10 = -2 / fn;
result.m11 = 0;
result.m12 = -(left + right) / rl;
result.m13 = -(top + bottom) / tb;
result.m14 = -(far + near) / fn;
result.m15 = 1;
return result;
}
@ -747,7 +769,7 @@ 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);
@ -793,7 +815,7 @@ void PrintMatrix(Matrix m)
// Calculates the length of a quaternion
float QuaternionLength(Quaternion quat)
{
return sqrt(quat.x*quat.x + quat.y*quat.y + quat.z*quat.z + quat.w*quat.w);
return sqrt(quat.x*quat.x + quat.y*quat.y + quat.z*quat.z + quat.w*quat.w);
}
// Normalize provided quaternion
@ -818,15 +840,15 @@ 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;
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
@ -834,9 +856,9 @@ 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;
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
{
float halfTheta = acos(cosHalfTheta);
@ -859,9 +881,9 @@ Quaternion QuaternionSlerp(Quaternion q1, Quaternion q2, float amount)
result.z = (q1.z*ratioA + q2.z*ratioB);
result.w = (q1.w*ratioA + q2.w*ratioB);
}
}
}
return result;
return result;
}
// Returns a quaternion from a given rotation matrix
@ -947,42 +969,42 @@ Matrix QuaternionToMatrix(Quaternion q)
{
Matrix result;
float x = q.x, y = q.y, z = q.z, w = q.w;
float x = q.x, y = q.y, z = q.z, w = q.w;
float x2 = x + x;
float y2 = y + y;
float z2 = z + z;
float x2 = x + x;
float y2 = y + y;
float z2 = z + z;
float xx = x*x2;
float xy = x*y2;
float xz = x*z2;
float xx = x*x2;
float xy = x*y2;
float xz = x*z2;
float yy = y*y2;
float yz = y*z2;
float zz = z*z2;
float yy = y*y2;
float yz = y*z2;
float zz = z*z2;
float wx = w*x2;
float wy = w*y2;
float wz = w*z2;
float wx = w*x2;
float wy = w*y2;
float wz = w*z2;
result.m0 = 1 - (yy + zz);
result.m1 = xy - wz;
result.m2 = xz + wy;
result.m3 = 0;
result.m4 = xy + wz;
result.m5 = 1 - (xx + zz);
result.m6 = yz - wx;
result.m7 = 0;
result.m8 = xz - wy;
result.m9 = yz + wx;
result.m10 = 1 - (xx + yy);
result.m11 = 0;
result.m12 = 0;
result.m13 = 0;
result.m14 = 0;
result.m15 = 1;
return result;
result.m0 = 1 - (yy + zz);
result.m1 = xy - wz;
result.m2 = xz + wy;
result.m3 = 0;
result.m4 = xy + wz;
result.m5 = 1 - (xx + zz);
result.m6 = yz - wx;
result.m7 = 0;
result.m8 = xz - wy;
result.m9 = yz + wx;
result.m10 = 1 - (xx + yy);
result.m11 = 0;
result.m12 = 0;
result.m13 = 0;
result.m14 = 0;
result.m15 = 1;
return result;
}
// Returns the axis and the angle for a given quaternion

View file

@ -91,6 +91,8 @@ void VectorNormalize(Vector3 *v); // Normalize provided ve
float VectorDistance(Vector3 v1, Vector3 v2); // Calculate distance between two points
Vector3 VectorLerp(Vector3 v1, Vector3 v2, float amount); // Calculate linear interpolation between two vectors
Vector3 VectorReflect(Vector3 vector, Vector3 normal); // Calculate reflected vector to normal
void VectorTransform(Vector3 *v, Matrix mat); // Transforms a Vector3 with a given Matrix
Vector3 VectorZero(); // Return a Vector3 init to zero
//------------------------------------------------------------------------------------
// Functions Declaration to work with Matrix

1572
src/rlgl.c Normal file

File diff suppressed because it is too large Load diff

153
src/rlgl.h Normal file
View file

@ -0,0 +1,153 @@
/*********************************************************************************************
*
* 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
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
#ifndef RLGL_H
#define RLGL_H
//#define RLGL_STANDALONE // NOTE: To use rlgl as standalone lib, just uncomment this line
#ifndef RLGL_STANDALONE
#include "raylib.h" // Required for typedef: Model
#include "utils.h" // Required for function TraceLog()
#endif
#include "raymath.h" // Required for data type Matrix and Matrix functions
// Select desired OpenGL version
//#define USE_OPENGL_11
#define USE_OPENGL_33
//#define USE_OPENGL_ES2
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
#define MAX_LINES_BATCH 8192 // 1024
#define MAX_TRIANGLES_BATCH 2048
#define MAX_QUADS_BATCH 8192
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
typedef unsigned char byte;
typedef enum { RL_PROJECTION, RL_MODELVIEW, RL_TEXTURE } MatrixMode;
typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode;
#ifdef RLGL_STANDALONE
typedef struct Model Model;
#endif
typedef struct {
int numVertices;
float *vertices; // 3 components per vertex
float *texcoords; // 2 components per vertex
float *normals; // 3 components per vertex
} VertexData;
#ifdef USE_OPENGL_11
struct Model {
VertexData data;
};
#else
struct Model {
unsigned int vaoId;
Matrix transform;
int numVertices;
};
#endif
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
//------------------------------------------------------------------------------------
// Functions Declaration - Matrix operations
//------------------------------------------------------------------------------------
void rlMatrixMode(int mode); // Choose the current matrix to be transformed
void rlPushMatrix(); // TODO: REVIEW: Required? - Push the current matrix to stack
void rlPopMatrix(); // TODO: REVIEW: Required? - Pop lattest inserted matrix from stack
void rlLoadIdentity(); // Reset current matrix to identity matrix
void rlTranslatef(float x, float y, float z); // Multiply the current matrix by a translation matrix
void rlRotatef(float angleDeg, float x, float y, float z); // Multiply the current matrix by a rotation matrix
void rlScalef(float x, float y, float z); // Multiply the current matrix by a scaling matrix
void rlMultMatrixf(float *mat); // Multiply the current matrix by another matrix
void rlFrustum(double left, double right, double bottom, double top, double near, double far);
void rlOrtho(double left, double right, double bottom, double top, double near, double far);
//------------------------------------------------------------------------------------
// Functions Declaration - Vertex level operations
//------------------------------------------------------------------------------------
void rlBegin(int mode); // Initialize drawing mode (how to organize vertex)
void rlEnd(); // Finish vertex providing
void rlVertex2i(int x, int y); // Define one vertex (position) - 2 int
void rlVertex2f(float x, float y); // Define one vertex (position) - 2 float
void rlVertex3f(float x, float y, float z); // Define one vertex (position) - 3 float
void rlTexCoord2f(float x, float y); // Define one vertex (texture coordinate) - 2 float
void rlNormal3f(float x, float y, float z); // Define one vertex (normal) - 3 float
void rlColor4ub(byte r, byte g, byte b, byte a); // Define one vertex (color) - 4 byte
void rlColor3f(float x, float y, float z); // Define one vertex (color) - 3 float
void rlColor4f(float x, float y, float z, float w); // Define one vertex (color) - 4 float
//------------------------------------------------------------------------------------
// Functions Declaration - OpenGL equivalent functions (common to 1.1, 3.3+, ES2)
// NOTE: This functions are used to completely abstract raylib code from OpenGL layer
//------------------------------------------------------------------------------------
void rlEnableTexture(unsigned int id); // Enable texture usage
void rlDisableTexture(); // Disable texture usage
void rlDeleteTextures(unsigned int id); // Delete OpenGL texture from GPU
void rlDeleteVertexArrays(unsigned int id); // Unload vertex data from GPU memory
void rlClearColor(byte r, byte g, byte b, byte a); // Clear color buffer with color
void rlClearScreenBuffers(); // Clear used screen buffers (color and depth)
//------------------------------------------------------------------------------------
// Functions Declaration - rlgl functionality
//------------------------------------------------------------------------------------
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
void rlglInit(); // Initialize rlgl (shaders, VAO, VBO...)
void rlglClose(); // De-init rlgl
void rlglDraw(); // Draw VAOs
unsigned int rlglLoadModel(VertexData data);
unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int format);
#endif
void rlglDrawModel(Model model, Vector3 position, float scale, bool wires); // Draw model
void rlglInitGraphicsDevice(int fbWidth, int fbHeight); // Initialize Graphics Device (OpenGL stuff)
unsigned int rlglLoadTexture(int width, int height, unsigned char *pixels); // Load in GPU OpenGL texture
byte *rlglReadScreenPixels(int width, int height); // Read screen pixel data (color buffer)
#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
void PrintProjectionMatrix(); // DEBUG: Print projection matrix
void PrintModelviewMatrix(); // DEBUG: Print modelview matrix
#endif
#ifdef __cplusplus
}
#endif
#endif // RLGL_H

View file

@ -25,10 +25,11 @@
#include "raylib.h"
#include <GL/gl.h> // OpenGL functions
#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
//----------------------------------------------------------------------------------
// Defines and Macros
@ -57,149 +58,108 @@
// Draw a pixel
void DrawPixel(int posX, int posY, Color color)
{
glBegin(GL_POINTS);
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2i(posX, posY);
glEnd();
// NOTE1: Alternative method to draw a pixel (GL_LINES)
/*
glBegin(GL_LINES);
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2i(posX, posY);
glVertex2i(posX+1, posY+1);
glEnd();
*/
// NOTE2: Alternative method to draw a pixel (glPoint())
/*
glEnable(GL_POINT_SMOOTH);
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); // Deprecated on OGL 3.0
glPointSize(1.0f);
glPoint((float)posX, (float)posY, 0.0f);
*/
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2i(posX, posY);
rlVertex2i(posX + 1, posY + 1);
rlEnd();
}
// Draw a pixel (Vector version)
void DrawPixelV(Vector2 position, Color color)
{
glBegin(GL_POINTS);
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2f(position.x, position.y);
glEnd();
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(position.x, position.y);
rlVertex2i(position.x + 1, position.y + 1);
rlEnd();
}
// Draw a line
void DrawLine(int startPosX, int startPosY, int endPosX, int endPosY, Color color)
{
glBegin(GL_LINES);
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2i(startPosX, startPosY);
glVertex2i(endPosX, endPosY);
glEnd();
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2i(startPosX, startPosY);
rlVertex2i(endPosX, endPosY);
rlEnd();
}
// Draw a line (Vector version)
void DrawLineV(Vector2 startPos, Vector2 endPos, Color color)
{
glBegin(GL_LINES);
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2f(startPos.x, startPos.y);
glVertex2f(endPos.x, endPos.y);
glEnd();
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(startPos.x, startPos.y);
rlVertex2f(endPos.x, endPos.y);
rlEnd();
}
// Draw a color-filled circle
// TODO: Review, on some GPUs is drawn with a weird transparency (GL_POLYGON_SMOOTH issue?)
void DrawCircle(int centerX, int centerY, float radius, Color color)
{
glEnable(GL_POLYGON_SMOOTH);
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); // Deprecated on OGL 3.0
DrawPoly((Vector2){centerX, centerY}, 360, radius, 0, color);
glDisable(GL_POLYGON_SMOOTH);
// NOTE: Alternative method to draw a circle (point)
/*
glEnable(GL_POINT_SMOOTH);
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); // Deprecated on OGL 3.0
glPointSize(radius);
glPoint((float)centerX, (float)centerY, 0.0f);
*/
}
// Draw a gradient-filled circle
// NOTE: Gradient goes from center (color1) to border (color2)
void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Color color2)
{
glBegin(GL_TRIANGLE_FAN);
glColor4ub(color1.r, color1.g, color1.b, color1.a);
glVertex2i(centerX, centerY);
glColor4ub(color2.r, color2.g, color2.b, color2.a);
for (int i=0; i <= 360; i++) //i++ --> Step = 1.0 pixels
rlBegin(RL_TRIANGLES);
for (int i=0; i < 360; i += 2)
{
glVertex2f(centerX + sin(DEG2RAD*i) * radius, centerY + cos(DEG2RAD*i) * radius);
rlColor4ub(color1.r, color1.g, color1.b, color1.a);
rlVertex2i(centerX, centerY);
rlColor4ub(color2.r, color2.g, color2.b, color2.a);
rlVertex2f(centerX + sin(DEG2RAD*i) * radius, centerY + cos(DEG2RAD*i) * radius);
rlVertex2f(centerX + sin(DEG2RAD*(i+2)) * radius, centerY + cos(DEG2RAD*(i+2)) * radius);
}
glEnd();
rlEnd();
}
// Draw a color-filled circle (Vector version)
void DrawCircleV(Vector2 center, float radius, Color color)
{
glEnable(GL_POLYGON_SMOOTH);
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
glBegin(GL_TRIANGLE_FAN);
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2f(center.x, center.y);
for (int i=0; i <= 360; i++) //i++ --> Step = 1.0 pixels
rlBegin(RL_TRIANGLES);
for (int i=0; i < 360; i += 2)
{
glVertex2f(center.x + sin(DEG2RAD*i) * radius, center.y + cos(DEG2RAD*i) * radius);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2i(center.x, center.y);
rlVertex2f(center.x + sin(DEG2RAD*i) * radius, center.y + cos(DEG2RAD*i) * radius);
rlVertex2f(center.x + sin(DEG2RAD*(i+2)) * radius, center.y + cos(DEG2RAD*(i+2)) * radius);
}
glEnd();
glDisable(GL_POLYGON_SMOOTH);
rlEnd();
}
// Draw circle outline
void DrawCircleLines(int centerX, int centerY, float radius, Color color)
{
glEnable(GL_LINE_SMOOTH); // Smoothies circle outline (anti-aliasing applied)
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); // Best quality for line smooth (anti-aliasing best algorithm)
glBegin(GL_LINE_LOOP);
glColor4ub(color.r, color.g, color.b, color.a);
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++)
{
glVertex2f(centerX + sin(DEG2RAD*i) * radius, centerY + cos(DEG2RAD*i) * radius);
rlVertex2f(centerX + sin(DEG2RAD*i) * radius, centerY + cos(DEG2RAD*i) * radius);
rlVertex2f(centerX + sin(DEG2RAD*(i+1)) * radius, centerY + cos(DEG2RAD*(i+1)) * radius);
}
glEnd();
// NOTE: Alternative method to draw circle outline
/*
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
DrawCircle(centerX, centerY, radius, color);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
*/
glDisable(GL_LINE_SMOOTH);
rlEnd();
}
// Draw a color-filled rectangle
void DrawRectangle(int posX, int posY, int width, int height, Color color)
{
glBegin(GL_QUADS);
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2i(posX, posY);
glVertex2i(posX + width, posY);
glVertex2i(posX + width, posY + height);
glVertex2i(posX, posY + height);
glEnd();
rlBegin(RL_QUADS);
rlColor4ub(color.r, color.g, color.b, color.a);
rlTexCoord2f(0.0f, 0.0f);
rlVertex2i(posX, posY);
rlTexCoord2f(0.0f, 1.0f);
rlVertex2i(posX, posY + height);
rlTexCoord2f(1.0f, 1.0f);
rlVertex2i(posX + width, posY + height);
rlTexCoord2f(1.0f, 0.0f);
rlVertex2i(posX + width, posY);
rlEnd();
}
// Draw a color-filled rectangle
@ -212,73 +172,73 @@ void DrawRectangleRec(Rectangle rec, Color color)
// NOTE: Gradient goes from bottom (color1) to top (color2)
void DrawRectangleGradient(int posX, int posY, int width, int height, Color color1, Color color2)
{
glBegin(GL_QUADS);
glColor4ub(color1.r, color1.g, color1.b, color1.a);
glVertex2i(posX, posY);
glVertex2i(posX + width, posY);
glColor4ub(color2.r, color2.g, color2.b, color2.a);
glVertex2i(posX + width, posY + height);
glVertex2i(posX, posY + height);
glEnd();
rlBegin(RL_QUADS);
rlColor4ub(color1.r, color1.g, color1.b, color1.a);
rlVertex2i(posX, posY);
rlColor4ub(color1.r, color1.g, color1.b, color1.a);
rlVertex2i(posX, posY + height);
rlColor4ub(color2.r, color2.g, color2.b, color2.a);
rlVertex2i(posX + width, posY + height);
rlColor4ub(color2.r, color2.g, color2.b, color2.a);
rlVertex2i(posX + width, posY);
rlEnd();
}
// Draw a color-filled rectangle (Vector version)
void DrawRectangleV(Vector2 position, Vector2 size, Color color)
{
glBegin(GL_QUADS);
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2i(position.x, position.y);
glVertex2i(position.x + size.x, position.y);
glVertex2i(position.x + size.x, position.y + size.y);
glVertex2i(position.x, position.y + size.y);
glEnd();
rlBegin(RL_QUADS);
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 + size.x, position.y);
rlEnd();
}
// Draw rectangle outline
void DrawRectangleLines(int posX, int posY, int width, int height, Color color)
{
//glEnable(GL_LINE_SMOOTH); // Smoothies circle outline (anti-aliasing applied)
//glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); // Best quality for line smooth (anti-aliasing best algorithm)
// NOTE: Lines are rasterized using the "Diamond Exit" rule so, it's nearly impossible to obtain a pixel-perfect engine
// NOTE: Recommended trying to avoid using lines, at least >1.0f pixel lines with anti-aliasing (glLineWidth function)
glBegin(GL_LINE_LOOP);
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2i(posX, posY);
glVertex2i(posX + width - 1, posY);
glVertex2i(posX + width - 1, posY + height - 1);
glVertex2i(posX, posY + height - 1);
glEnd();
// NOTE: Alternative method to draw rectangle outline
/*
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
DrawRectangle(posX, posY, width - 1, height - 1, color);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
*/
//glDisable(GL_LINE_SMOOTH);
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2i(posX, posY);
rlVertex2i(posX + width - 1, posY);
rlVertex2i(posX + width - 1, posY);
rlVertex2i(posX + width - 1, posY + height - 1);
rlVertex2i(posX + width - 1, posY + height - 1);
rlVertex2i(posX, posY + height - 1);
rlVertex2i(posX, posY + height - 1);
rlVertex2i(posX, posY);
rlEnd();
}
// Draw a triangle
void DrawTriangle(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
{
glBegin(GL_TRIANGLES);
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2f(v1.x, v1.y);
glVertex2f(v2.x, v2.y);
glVertex2f(v3.x, v3.y);
glEnd();
rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(v1.x, v1.y);
rlVertex2f(v2.x, v2.y);
rlVertex2f(v3.x, v3.y);
rlEnd();
}
void DrawTriangleLines(Vector2 v1, Vector2 v2, Vector2 v3, Color color)
{
glBegin(GL_LINE_LOOP);
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2f(v1.x, v1.y);
glVertex2f(v2.x, v2.y);
glVertex2f(v3.x, v3.y);
glEnd();
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(v1.x, v1.y);
rlVertex2f(v2.x, v2.y);
rlVertex2f(v2.x, v2.y);
rlVertex2f(v3.x, v3.y);
rlVertex2f(v3.x, v3.y);
rlVertex2f(v1.x, v1.y);
rlEnd();
}
// Draw a regular polygon of n sides (Vector version)
@ -286,20 +246,21 @@ void DrawPoly(Vector2 center, int sides, float radius, float rotation, Color col
{
if (sides < 3) sides = 3;
glPushMatrix();
glTranslatef(center.x, center.y, 0);
glRotatef(rotation, 0, 0, 1);
rlPushMatrix();
rlTranslatef(center.x, center.y, 0.0);
rlRotatef(rotation, 0, 0, 1);
glBegin(GL_TRIANGLE_FAN);
glColor4ub(color.r, color.g, color.b, color.a);
glVertex2f(0, 0);
for (int i=0; i <= sides; i++)
{
glVertex2f(radius*cos(i*2*PI/sides), radius*sin(i*2*PI/sides));
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);
}
glEnd();
glPopMatrix();
rlEnd();
rlPopMatrix();
}
// Draw a closed polygon defined by points
@ -308,19 +269,16 @@ void DrawPolyEx(Vector2 *points, int numPoints, Color color)
{
if (numPoints >= 3)
{
glEnable(GL_POLYGON_SMOOTH);
glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
glBegin(GL_POLYGON);
glColor4ub(color.r, color.g, color.b, color.a);
rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 0; i < numPoints; i++)
for (int i = 0; i < numPoints - 2; i++)
{
glVertex2f(points[i].x, points[i].y);
rlVertex2f(points[i].x, points[i].y);
rlVertex2f(points[i+1].x, points[i+1].y);
rlVertex2f(points[i+2].x, points[i+2].y);
}
glEnd();
glDisable(GL_POLYGON_SMOOTH);
rlEnd();
}
}
@ -330,22 +288,22 @@ void DrawPolyExLines(Vector2 *points, int numPoints, Color color)
{
if (numPoints >= 2)
{
//glEnable(GL_LINE_SMOOTH); // Smoothies circle outline (anti-aliasing applied)
//glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); // Best quality for line smooth (anti-aliasing best algorithm)
glBegin(GL_LINE_LOOP);
glColor4ub(color.r, color.g, color.b, color.a);
rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a);
for (int i = 0; i < numPoints; i++)
for (int i = 0; i < numPoints - 1; i++)
{
glVertex2f(points[i].x, points[i].y);
rlVertex2f(points[i].x, points[i].y);
rlVertex2f(points[i+1].x, points[i+1].y);
}
glEnd();
//glDisable(GL_LINE_SMOOTH);
rlEnd();
}
}
//----------------------------------------------------------------------------------
// Module Functions Definition - Collision Detection functions
//----------------------------------------------------------------------------------
// Check if point is inside rectangle
bool CheckCollisionPointRec(Vector2 point, Rectangle rec)
{

View file

@ -11,5 +11,4 @@ void main()
{
// Output pixel color
pixelColor = texture(texture0, fragTexCoord) * fragColor;
//pixelColor = fragColor;
}

View file

@ -11,6 +11,7 @@
// Get the latest version and other information at:
// http://nothings.org/stb_vorbis/
// Todo:
//
// - seeking (note you can seek yourself using the pushdata API)
@ -25,6 +26,9 @@
//
// All of these limitations may be removed in future versions.
#include "stb_vorbis.h"
#ifndef STB_VORBIS_HEADER_ONLY
// global configuration settings (e.g. set these in the project/makefile),

View file

@ -11,6 +11,7 @@
// Get the latest version and other information at:
// http://nothings.org/stb_vorbis/
// Todo:
//
// - seeking (note you can seek yourself using the pushdata API)
@ -25,12 +26,6 @@
//
// All of these limitations may be removed in future versions.
//////////////////////////////////////////////////////////////////////////////
//
// HEADER BEGINS HERE
//
#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H
#define STB_VORBIS_INCLUDE_STB_VORBIS_H
@ -349,4 +344,4 @@ enum STBVorbisError
}
#endif
#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H
#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H

View file

@ -28,12 +28,13 @@
#include "raylib.h"
#include <GL/gl.h> // OpenGL functions
#include <stdlib.h> // Declares malloc() and free() for memory management
#include <string.h> // String management functions (just strlen() is used)
#include <stdarg.h> // Used for functions with variable number of parameters (FormatText())
#include "stb_image.h" // Used to read image data (multiple formats support)
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
@ -49,13 +50,22 @@
typedef unsigned char byte;
// SpriteFont one Character (Glyph) data
struct Character {
typedef struct Character {
int value; //char value = ' '; (int)value = 32;
int x;
int y;
int w;
int h;
} Character;
// SpriteFont type, includes texture and charSet array data
/*
struct SpriteFont {
Texture2D texture;
int numChars;
Character *charSet;
};
*/
//----------------------------------------------------------------------------------
// Global variables
@ -63,6 +73,11 @@ struct Character {
static SpriteFont defaultFont; // Default font provided by raylib
// NOTE: defaultFont is loaded on InitWindow and disposed on CloseWindow [module: core]
//----------------------------------------------------------------------------------
// Other Modules Functions Declaration (required by text)
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
@ -78,9 +93,11 @@ static const char *GetExtension(const char *fileName);
extern void LoadDefaultFont()
{
defaultFont.numChars = 96; // We know our default font has 94 chars
defaultFont.texture.width = 128; // We know our default font texture is 128 pixels width
defaultFont.texture.height = 64; // We know our default font texture is 64 pixels height
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
@ -115,7 +132,31 @@ extern void LoadDefaultFont()
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)
{
for (int j = 31; j >= 0; j--)
{
if (BIT_CHECK(defaultFontData[counter], j)) image.pixels[i+j] = WHITE;
}
counter++;
if (counter > 256) counter = 0; // Security check...
}
defaultFont.texture = CreateTexture(image); // 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
@ -146,52 +187,12 @@ extern void LoadDefaultFont()
else currentPosX = testPosX;
}
// Re-construct image from defaultFontData and generate OpenGL texture
//----------------------------------------------------------------------
Color *imgDataPixel = (Color *)malloc(defaultFont.texture.width * defaultFont.texture.height * sizeof(Color));
for (int i = 0; i < defaultFont.texture.width * defaultFont.texture.height; i++) imgDataPixel[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 < defaultFont.texture.width * defaultFont.texture.height; i += 32)
{
for (int j = 31; j >= 0; j--)
{
if (BIT_CHECK(defaultFontData[counter], j)) imgDataPixel[i+j] = WHITE;
}
counter++;
if (counter > 256) counter = 0; // Security check...
}
// Convert loaded data to OpenGL texture
//----------------------------------------
GLuint id;
glGenTextures(1, &id); // Generate pointer to the texture
glBindTexture(GL_TEXTURE_2D, id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); // Set texture to clamp on x-axis
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); // Set texture to clamp on y-axis
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, defaultFont.texture.width, defaultFont.texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgDataPixel);
// NOTE: Not using mipmappings (texture for 2D drawing)
// At this point we have the image converted to texture and uploaded to GPU
free(imgDataPixel); // Now we can free loaded data from RAM memory
defaultFont.texture.glId = id;
TraceLog(INFO, "Default font loaded successfully");
}
extern void UnloadDefaultFont()
{
glDeleteTextures(1, &defaultFont.texture.glId);
rlDeleteTextures(defaultFont.texture.glId);
free(defaultFont.charSet);
}
@ -206,6 +207,8 @@ SpriteFont LoadSpriteFont(const char* fileName)
{
SpriteFont spriteFont;
Image image;
// Check file extension
if (strcmp(GetExtension(fileName),"rbmf") == 0) spriteFont = LoadRBMF(fileName);
else
@ -240,8 +243,8 @@ SpriteFont LoadSpriteFont(const char* fileName)
// spriteFont.charSet data is filled inside the function and memory is allocated!
int numChars = ParseImageData(imgDataPixel, imgWidth, imgHeight, &spriteFont.charSet);
fprintf(stderr, "SpriteFont data parsed correctly!\n");
fprintf(stderr, "SpriteFont num chars: %i\n", numChars);
TraceLog(INFO, "[%s] SpriteFont data parsed correctly", fileName);
TraceLog(INFO, "[%s] SpriteFont num chars detected: %i", numChars);
spriteFont.numChars = numChars;
@ -265,29 +268,18 @@ SpriteFont LoadSpriteFont(const char* fileName)
}
}
fprintf(stderr, "SpriteFont texture converted to POT: %i %i\n", potWidth, potHeight);
TraceLog(WARNING, "SpriteFont texture converted to POT: %ix%i", potWidth, potHeight);
}
free(imgDataPixel);
// Convert loaded data to OpenGL texture
//----------------------------------------
GLuint id;
glGenTextures(1, &id); // Generate pointer to the texture
image.pixels = imgDataPixelPOT;
image.width = potWidth;
image.height = potHeight;
glBindTexture(GL_TEXTURE_2D, id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, potWidth, potHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgDataPixelPOT);
// NOTE: Not using mipmappings (texture for 2D drawing)
// At this point we have the image converted to texture and uploaded to GPU
free(imgDataPixelPOT); // Now we can free loaded data from RAM memory
spriteFont.texture.glId = id;
spriteFont.texture.width = potWidth;
spriteFont.texture.height = potHeight;
spriteFont.texture = CreateTexture(image); // Convert loaded image to OpenGL texture
UnloadImage(image);
}
return spriteFont;
@ -296,7 +288,7 @@ SpriteFont LoadSpriteFont(const char* fileName)
// Unload SpriteFont from GPU memory
void UnloadSpriteFont(SpriteFont spriteFont)
{
glDeleteTextures(1, &spriteFont.texture.glId);
rlDeleteTextures(spriteFont.texture.glId);
free(spriteFont.charSet);
}
@ -330,28 +322,33 @@ void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, int f
if (fontSize <= spriteFont.charSet[0].h) scaleFactor = 1.0f;
else scaleFactor = (float)fontSize / spriteFont.charSet[0].h;
glEnable(GL_TEXTURE_2D);
rlEnableTexture(spriteFont.texture.glId);
glBindTexture(GL_TEXTURE_2D, spriteFont.texture.glId);
// Optimized to use one draw call per string
glBegin(GL_QUADS);
rlBegin(RL_QUADS);
for(int i = 0; i < length; i++)
{
c = spriteFont.charSet[(int)text[i] - FONT_FIRST_CHAR];
glColor4ub(tint.r, tint.g, tint.b, tint.a);
glNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
glTexCoord2f((float)c.x / spriteFont.texture.width, (float)c.y / spriteFont.texture.height); glVertex2f(positionX, position.y);
glTexCoord2f((float)c.x / spriteFont.texture.width, (float)(c.y + c.h) / spriteFont.texture.height); glVertex2f(positionX, position.y + (c.h) * scaleFactor);
glTexCoord2f((float)(c.x + c.w) / spriteFont.texture.width, (float)(c.y + c.h) / spriteFont.texture.height); glVertex2f(positionX + (c.w) * scaleFactor, position.y + (c.h) * scaleFactor);
glTexCoord2f((float)(c.x + c.w) / spriteFont.texture.width, (float)c.y / spriteFont.texture.height); glVertex2f(positionX + (c.w) * scaleFactor, position.y);
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);
rlVertex2f(positionX, position.y);
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);
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);
rlVertex2f(positionX + (c.w) * scaleFactor, position.y);
positionX += ((spriteFont.charSet[(int)text[i] - FONT_FIRST_CHAR].w) * scaleFactor + spacing);
}
glEnd();
glDisable(GL_TEXTURE_2D);
rlEnd();
rlDisableTexture();
}
// Formatting of text with variables to 'embed'
@ -361,7 +358,7 @@ const char *FormatText(const char *text, ...)
va_list args;
va_start(args, text);
vsprintf(buffer, text, args); // NOTE: We use vsprintf() defined in <stdarg.h>
vsprintf(buffer, text, args);
va_end(args);
return buffer;
@ -417,21 +414,18 @@ void DrawFPS(int posX, int posY)
char buffer[20];
if (counter < refreshRate)
{
sprintf(buffer, "%2.0f FPS", fps);
DrawText(buffer, posX, posY, 20, LIME);
{
counter++;
}
else
{
fps = GetFPS();
refreshRate = fps;
sprintf(buffer, "%2.0f FPS", fps);
DrawText(buffer, posX, posY, 20, LIME);
counter = 0;
}
sprintf(buffer, "%2.0f FPS", fps);
DrawText(buffer, posX, posY, 20, LIME);
}
//----------------------------------------------------------------------------------
@ -564,7 +558,7 @@ static SpriteFont LoadRBMF(const char *fileName)
fread(&rbmfHeader, sizeof(rbmfInfoHeader), 1, rbmfFile);
//printf("rBMF info: %i %i %i %i\n", rbmfHeader.imgWidth, rbmfHeader.imgHeight, rbmfHeader.numChars, rbmfHeader.charHeight);
TraceLog(INFO, "[%s] Loading rBMF file, size: %ix%i, numChars: %i, charHeight: %i", fileName, rbmfHeader.imgWidth, rbmfHeader.imgHeight, rbmfHeader.numChars, rbmfHeader.charHeight);
spriteFont.numChars = (int)rbmfHeader.numChars;
@ -581,8 +575,6 @@ static SpriteFont LoadRBMF(const char *fileName)
for(int i = 0; i < spriteFont.numChars; i++) fread(&rbmfCharWidthData[i], sizeof(unsigned char), 1, rbmfFile);
printf("Just read image data and width data... Starting image reconstruction...");
// Re-construct image from rbmfFileData
//-----------------------------------------
image.pixels = (Color *)malloc(image.width * image.height * sizeof(Color));
@ -602,13 +594,13 @@ static SpriteFont LoadRBMF(const char *fileName)
counter++;
}
printf("Image reconstructed correctly... now converting it to texture...");
TraceLog(INFO, "[%s] Image reconstructed correctly, now converting it to texture", fileName);
spriteFont.texture = CreateTexture(image);
UnloadImage(image); // Unload image data
printf("Starting charSet reconstruction...\n");
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
@ -637,11 +629,9 @@ static SpriteFont LoadRBMF(const char *fileName)
spriteFont.charSet[i].y = charsDivisor + currentLine * (rbmfHeader.charHeight + charsDivisor);
}
else currentPosX = testPosX;
//printf("Char %i data: %i %i %i %i\n", spriteFont.charSet[i].value, spriteFont.charSet[i].x, spriteFont.charSet[i].y, spriteFont.charSet[i].w, spriteFont.charSet[i].h);
}
printf("CharSet reconstructed correctly... Data should be ready...\n");
TraceLog(INFO, "[%s] rBMF file loaded correctly as SpriteFont", fileName);
fclose(rbmfFile);
@ -651,6 +641,7 @@ static SpriteFont LoadRBMF(const char *fileName)
return spriteFont;
}
// Get the extension for a filename
static const char *GetExtension(const char *fileName)
{
const char *dot = strrchr(fileName, '.');

View file

@ -28,12 +28,13 @@
#include "raylib.h"
#include <GL/gl.h> // OpenGL functions
#include <stdlib.h> // Declares malloc() and free() for memory management
#include <string.h> // Required for strcmp(), strrchr(), strncmp()
#include "stb_image.h" // Used to read image data (multiple formats support)
#include "utils.h" // rRES data decompression utility function
#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
//----------------------------------------------------------------------------------
// Defines and Macros
//----------------------------------------------------------------------------------
@ -44,15 +45,29 @@
//----------------------------------------------------------------------------------
typedef unsigned char byte;
typedef struct {
unsigned char *data;
int width;
int height;
int mipmaps;
int format;
} ImageDDS;
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
// It's lonely here...
//----------------------------------------------------------------------------------
// Other Modules Functions Declaration (required by text)
//----------------------------------------------------------------------------------
//...
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
// No private (static) functions in this module (.c file)
static const char *GetExtension(const char *fileName);
static ImageDDS LoadDDS(const char *fileName);
//----------------------------------------------------------------------------------
// Module Functions Definition
@ -63,32 +78,44 @@ Image LoadImage(const char *fileName)
{
Image image;
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);
// 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];
image.pixels[pix].g = imgData[i+1];
image.pixels[pix].b = imgData[i+2];
image.pixels[pix].a = imgData[i+3];
pix++;
if ((strcmp(GetExtension(fileName),"png") == 0) ||
(strcmp(GetExtension(fileName),"bmp") == 0) ||
(strcmp(GetExtension(fileName),"tga") == 0) ||
(strcmp(GetExtension(fileName),"jpg") == 0) ||
(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);
// 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];
image.pixels[pix].g = imgData[i+1];
image.pixels[pix].b = imgData[i+2];
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);
}
stbi_image_free(imgData);
image.width = imgWidth;
image.height = imgHeight;
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,
// to do that struct data alignment should be the right one (4 byte); it is.
@ -113,103 +140,104 @@ Image LoadImageFromRES(const char *rresName, int resId)
FILE *rresFile = fopen(rresName, "rb");
if (!rresFile) printf("Error opening raylib Resource file\n");
// Read rres file (basic file check - id)
fread(&id[0], sizeof(char), 1, rresFile);
fread(&id[1], sizeof(char), 1, rresFile);
fread(&id[2], sizeof(char), 1, rresFile);
fread(&id[3], sizeof(char), 1, rresFile);
fread(&version, sizeof(char), 1, rresFile);
fread(&useless, sizeof(char), 1, rresFile);
if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S'))
if (!rresFile) TraceLog(WARNING, "[%s] Could not open raylib resource file", rresName);
else
{
printf("This is not a valid raylib Resource file!\n");
exit(1);
}
// Read number of resources embedded
fread(&numRes, sizeof(short), 1, rresFile);
for (int i = 0; i < numRes; i++)
{
fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile);
// Read rres file (basic file check - id)
fread(&id[0], sizeof(char), 1, rresFile);
fread(&id[1], sizeof(char), 1, rresFile);
fread(&id[2], sizeof(char), 1, rresFile);
fread(&id[3], sizeof(char), 1, rresFile);
fread(&version, sizeof(char), 1, rresFile);
fread(&useless, sizeof(char), 1, rresFile);
if (infoHeader.id == resId)
if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S'))
{
found = true;
// Check data is of valid IMAGE type
if (infoHeader.type == 0) // IMAGE data type
{
// TODO: Check data compression type
// NOTE: We suppose compression type 2 (DEFLATE - default)
short imgWidth, imgHeight;
char colorFormat, mipmaps;
fread(&imgWidth, sizeof(short), 1, rresFile); // Image width
fread(&imgHeight, sizeof(short), 1, rresFile); // Image height
fread(&colorFormat, 1, 1, rresFile); // Image data color format (default: RGBA 32 bit)
fread(&mipmaps, 1, 1, rresFile); // Mipmap images included (default: 0)
printf("Image width: %i\n", (int)imgWidth);
printf("Image height: %i\n", (int)imgHeight);
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];
image.pixels[pix].g = imgData[i+1];
image.pixels[pix].b = imgData[i+2];
image.pixels[pix].a = imgData[i+3];
pix++;
}
free(imgData);
free(data);
}
else
{
printf("Required resource do not seem to be a valid IMAGE resource\n");
exit(2);
}
TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName);
}
else
{
// Depending on type, skip the right amount of parameters
switch (infoHeader.type)
{
case 0: fseek(rresFile, 6, SEEK_CUR); break; // IMAGE: Jump 6 bytes of parameters
case 1: fseek(rresFile, 6, SEEK_CUR); break; // SOUND: Jump 6 bytes of parameters
case 2: fseek(rresFile, 5, SEEK_CUR); break; // MODEL: Jump 5 bytes of parameters (TODO: Review)
case 3: break; // TEXT: No parameters
case 4: break; // RAW: No parameters
default: break;
}
// Read number of resources embedded
fread(&numRes, sizeof(short), 1, rresFile);
// Jump DATA to read next infoHeader
fseek(rresFile, infoHeader.size, SEEK_CUR);
}
for (int i = 0; i < numRes; i++)
{
fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile);
if (infoHeader.id == resId)
{
found = true;
// Check data is of valid IMAGE type
if (infoHeader.type == 0) // IMAGE data type
{
// TODO: Check data compression type
// NOTE: We suppose compression type 2 (DEFLATE - default)
short imgWidth, imgHeight;
char colorFormat, mipmaps;
fread(&imgWidth, sizeof(short), 1, rresFile); // Image width
fread(&imgHeight, sizeof(short), 1, rresFile); // Image height
fread(&colorFormat, 1, 1, rresFile); // Image data color format (default: RGBA 32 bit)
fread(&mipmaps, 1, 1, rresFile); // Mipmap images included (default: 0)
image.width = (int)imgWidth;
image.height = (int)imgHeight;
unsigned char *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];
image.pixels[pix].g = imgData[i+1];
image.pixels[pix].b = imgData[i+2];
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
{
TraceLog(WARNING, "[%s] Required resource do not seem to be a valid IMAGE resource", rresName);
}
}
else
{
// Depending on type, skip the right amount of parameters
switch (infoHeader.type)
{
case 0: fseek(rresFile, 6, SEEK_CUR); break; // IMAGE: Jump 6 bytes of parameters
case 1: fseek(rresFile, 6, SEEK_CUR); break; // SOUND: Jump 6 bytes of parameters
case 2: fseek(rresFile, 5, SEEK_CUR); break; // MODEL: Jump 5 bytes of parameters (TODO: Review)
case 3: break; // TEXT: No parameters
case 4: break; // RAW: No parameters
default: break;
}
// Jump DATA to read next infoHeader
fseek(rresFile, infoHeader.size, SEEK_CUR);
}
}
}
fclose(rresFile);
}
fclose(rresFile);
if (!found) printf("Required resource id could not be found in the raylib Resource file!\n");
if (!found) TraceLog(WARNING, "[%s] Required resource id [%i] could not be found in the raylib resource file", rresName, resId);
return image;
}
@ -218,11 +246,33 @@ Image LoadImageFromRES(const char *rresName, int resId)
Texture2D LoadTexture(const char *fileName)
{
Texture2D texture;
Image image;
image = LoadImage(fileName);
texture = CreateTexture(image);
UnloadImage(image);
if (strcmp(GetExtension(fileName),"dds") == 0)
{
#ifdef USE_OPENGL_11
TraceLog(WARNING, "[%s] DDS file loading requires OpenGL 3.2+ or ES 2.0", fileName);
#else
ImageDDS image = LoadDDS(fileName);
texture.glId = rlglLoadCompressedTexture(image.data, image.width, image.height, image.mipmaps, image.format);
texture.width = image.width;
texture.height = image.height;
if (texture.glId == 0) TraceLog(WARNING, "Compressed texture could not be loaded");
else TraceLog(INFO, "Compressed texture loaded succesfully");
#endif
}
else
{
Image image = LoadImage(fileName);
if (image.pixels != NULL)
{
texture = CreateTexture(image);
UnloadImage(image);
}
}
return texture;
}
@ -238,43 +288,6 @@ Texture2D LoadTextureFromRES(const char *rresName, int resId)
return texture;
}
// Create a Texture2D from Image data
// NOTE: Image is not unloaded, it should be done manually...
Texture2D CreateTexture(Image image)
{
Texture2D texture;
// Convert image data to OpenGL texture
//----------------------------------------
GLuint id;
glGenTextures(1, &id); // Generate Pointer to the Texture
glBindTexture(GL_TEXTURE_2D, id);
// NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used!
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repead on x-axis
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repead on y-axis
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Filter for pixel-perfect drawing, alternative: GL_LINEAR
// Trilinear filtering
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Activate use of mipmaps (must be available)
//glGenerateMipmap(GL_TEXTURE_2D); // OpenGL 3.3!
// Upload texture to GPU
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image.pixels);
// NOTE: Not using mipmappings (texture for 2D drawing)
// At this point we have the image converted to texture and uploaded to GPU
texture.glId = id;
texture.width = image.width;
texture.height = image.height;
return texture;
}
// Unload image from CPU memory (RAM)
void UnloadImage(Image image)
{
@ -284,13 +297,13 @@ void UnloadImage(Image image)
// Unload texture from GPU memory
void UnloadTexture(Texture2D texture)
{
glDeleteTextures(1, &texture.glId);
rlDeleteTextures(texture.glId);
}
// Draw a Texture2D
void DrawTexture(Texture2D texture, int posX, int posY, Color tint)
{
DrawTextureEx(texture, (Vector2){ (float)posX, (float)posY}, 0, 1.0f, tint);
DrawTextureEx(texture, (Vector2){ (float)posX, (float)posY }, 0, 1.0f, tint);
}
// Draw a Texture2D with position defined as Vector2
@ -302,101 +315,233 @@ void DrawTextureV(Texture2D texture, Vector2 position, Color tint)
// Draw a Texture2D with extended parameters
void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint)
{
glEnable(GL_TEXTURE_2D); // Enable textures usage
rlEnableTexture(texture.glId);
glBindTexture(GL_TEXTURE_2D, texture.glId);
// NOTE: Rotation is applied before translation and scaling, even being called in inverse order...
// NOTE: Rotation point is upper-left corner
rlPushMatrix();
//rlTranslatef(position.x, position.y, 0.0);
rlRotatef(rotation, 0, 0, 1);
rlScalef(scale, scale, 1.0f);
glPushMatrix();
// NOTE: Rotation is applied before translation and scaling, even being called in inverse order...
// NOTE: Rotation point is upper-left corner
glTranslatef(position.x, position.y, 0);
glScalef(scale, scale, 1.0f);
glRotatef(rotation, 0, 0, 1);
glBegin(GL_QUADS);
glColor4ub(tint.r, tint.g, tint.b, tint.a);
glNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer
glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f, 0.0f); // Bottom-left corner for texture and quad
glTexCoord2f(1.0f, 0.0f); glVertex2f(texture.width, 0.0f); // Bottom-right corner for texture and quad
glTexCoord2f(1.0f, 1.0f); glVertex2f(texture.width, texture.height); // Top-right corner for texture and quad
glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f, texture.height); // Top-left corner for texture and quad
glEnd();
glPopMatrix();
rlBegin(RL_QUADS);
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer
rlTexCoord2f(0.0f, 0.0f);
rlVertex2f(position.x, position.y); // Bottom-left corner for texture and quad
rlTexCoord2f(0.0f, 1.0f);
rlVertex2f(position.x, position.y + texture.height); // Bottom-right corner for texture and quad
rlTexCoord2f(1.0f, 1.0f);
rlVertex2f(position.x + texture.width, position.y + texture.height); // Top-right corner for texture and quad
rlTexCoord2f(1.0f, 0.0f);
rlVertex2f(position.x + texture.width, position.y); // Top-left corner for texture and quad
rlEnd();
rlPopMatrix();
glDisable(GL_TEXTURE_2D); // Disable textures usage
rlDisableTexture();
}
// Draw a part of a texture (defined by a rectangle)
void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint)
{
glEnable(GL_TEXTURE_2D); // Enable textures usage
rlEnableTexture(texture.glId);
glBindTexture(GL_TEXTURE_2D, texture.glId);
glPushMatrix();
glTranslatef(position.x, position.y, 0);
//glScalef(1.0f, 1.0f, 1.0f);
//glRotatef(rotation, 0, 0, 1);
rlBegin(RL_QUADS);
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
rlNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer
glBegin(GL_QUADS);
glColor4ub(tint.r, tint.g, tint.b, tint.a);
glNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer
// Bottom-left corner for texture and quad
glTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height);
glVertex2f(0.0f, 0.0f);
// Bottom-right corner for texture and quad
glTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height);
glVertex2f(sourceRec.width, 0.0f);
// Top-right corner for texture and quad
glTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
glVertex2f(sourceRec.width, sourceRec.height);
// Top-left corner for texture and quad
glTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
glVertex2f(0.0f, sourceRec.height);
glEnd();
glPopMatrix();
// Bottom-left corner for texture and quad
rlTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height);
rlVertex2f(position.x, position.y);
// Bottom-right corner for texture and quad
rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
rlVertex2f(position.x, position.y + sourceRec.height);
// Top-right corner for texture and quad
rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
rlVertex2f(position.x + sourceRec.width, position.y + sourceRec.height);
// Top-left corner for texture and quad
rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height);
rlVertex2f(position.x + sourceRec.width, position.y);
rlEnd();
glDisable(GL_TEXTURE_2D); // Disable textures usage
rlDisableTexture();
}
// Draw a part of a texture (defined by a rectangle) with 'pro' parameters
// TODO: Test this function...
void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint)
{
glEnable(GL_TEXTURE_2D); // Enable textures usage
rlEnableTexture(texture.glId);
glBindTexture(GL_TEXTURE_2D, texture.glId);
glPushMatrix();
glTranslatef(-origin.x, -origin.y, 0);
glRotatef(rotation, 0, 0, 1);
glTranslatef(destRec.x + origin.x, destRec.y + origin.y, 0);
glBegin(GL_QUADS);
glColor4ub(tint.r, tint.g, tint.b, tint.a);
glNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer
// NOTE: First we translate texture to origin to apply rotation and translation from there
rlPushMatrix();
rlTranslatef(-origin.x, -origin.y, 0);
rlRotatef(rotation, 0, 0, 1);
rlTranslatef(destRec.x + origin.x, destRec.y + 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
glTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height);
glVertex2f(0.0f, 0.0f);
rlTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height);
rlVertex2f(0.0f, 0.0f);
// Bottom-right corner for texture and quad
glTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height);
glVertex2f(destRec.width, 0.0f);
rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height);
rlVertex2f(destRec.width, 0.0f);
// Top-right corner for texture and quad
glTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
glVertex2f(destRec.width, destRec.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
glTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
glVertex2f(0.0f, destRec.height);
glEnd();
glPopMatrix();
rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
rlVertex2f(0.0f, destRec.height);
rlEnd();
rlPopMatrix();
glDisable(GL_TEXTURE_2D); // Disable textures usage
rlDisableTexture();
}
Texture2D CreateTexture(Image image)
{
Texture2D texture;
unsigned char *img = malloc(image.width * image.height * 4);
int j = 0;
for (int i = 0; i < image.width * image.height * 4; i += 4)
{
img[i] = image.pixels[j].r;
img[i+1] = image.pixels[j].g;
img[i+2] = image.pixels[j].b;
img[i+3] = image.pixels[j].a;
j++;
}
texture.glId = rlglLoadTexture(image.width, image.height, img);
texture.width = image.width;
texture.height = image.height;
TraceLog(INFO, "Texture created succesfully");
free(img);
return texture;
}
// Get the extension for a filename
static const char *GetExtension(const char *fileName)
{
const char *dot = strrchr(fileName, '.');
if(!dot || dot == fileName) return "";
return (dot + 1);
}
// Loading DDS image compressed data
ImageDDS LoadDDS(const char *fileName)
{
// TODO: Review and expand DDS file loading to support uncompressed formats and new formats
// DDS Pixel Format
typedef struct {
unsigned int size;
unsigned int flags;
unsigned int fourCC;
unsigned int rgbBitCount;
unsigned int rBitMask;
unsigned int gBitMask;
unsigned int bitMask;
unsigned int aBitMask;
} ddsPixelFormat;
// DDS Header (124 bytes)
typedef struct {
unsigned int size;
unsigned int flags;
unsigned int height;
unsigned int width;
unsigned int pitchOrLinearSize;
unsigned int depth;
unsigned int mipMapCount;
unsigned int reserved1[11];
ddsPixelFormat ddspf;
unsigned int caps;
unsigned int caps2;
unsigned int caps3;
unsigned int caps4;
unsigned int reserved2;
} ddsHeader;
ImageDDS image;
ddsHeader header;
FILE *ddsFile = fopen(fileName, "rb");
if (ddsFile == NULL)
{
TraceLog(WARNING, "DDS File could not be opened");
}
else
{
// Verify the type of file
char filecode[4];
fread(filecode, 1, 4, ddsFile);
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);
int height = header.height;
int width = header.width;
int linearSize = header.pitchOrLinearSize;
int mipMapCount = header.mipMapCount;
int fourCC = header.ddspf.fourCC;
TraceLog(DEBUG, "[%s] DDS file header size: %i", fileName, sizeof(ddsHeader));
TraceLog(DEBUG, "[%s] DDS file pixel format size: %i", fileName, header.ddspf.size);
TraceLog(DEBUG, "[%s] DDS file pixel format flags: 0x%x", fileName, header.ddspf.flags);
TraceLog(DEBUG, "[%s] DDS file format: 0x%x", fileName, fourCC);
int bufsize;
// Calculate data size, including all mipmaps
bufsize = mipMapCount > 1 ? linearSize * 2 : linearSize;
image.data = (unsigned char*)malloc(bufsize * sizeof(unsigned char));
fread(image.data, 1, bufsize, ddsFile);
// Close file pointer
fclose(ddsFile);
//int components = (fourCC == FOURCC_DXT1) ? 3 : 4; // Not required
image.width = width;
image.height = height;
image.mipmaps = mipMapCount;
image.format = fourCC;
}
}
return image;
}

View file

@ -29,7 +29,8 @@
#include "utils.h"
#include <stdlib.h> // malloc(), free()
#include <stdio.h> // printf()
#include <stdio.h> // printf(), fprintf()
#include <stdarg.h> // Used for functions with variable number of parameters (TraceLog())
//#include <string.h> // String management functions: strlen(), strrchr(), strcmp()
#define STB_IMAGE_WRITE_IMPLEMENTATION
@ -37,6 +38,15 @@
#include "stb_image_write.h" // Create PNG file
#include "tinfl.c"
//----------------------------------------------------------------------------------
// Global Variables Definition
//----------------------------------------------------------------------------------
static FILE *logstream = NULL;
//----------------------------------------------------------------------------------
// Module Functions Definition - Utilities
//----------------------------------------------------------------------------------
// Data decompression function
// NOTE: Allocated data MUST be freed!
unsigned char *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize)
@ -50,28 +60,28 @@ unsigned char *DecompressData(const unsigned char *data, unsigned long compSize,
// Check correct memory allocation
if (!pUncomp)
{
printf("Out of memory!\n");
return NULL;
TraceLog(WARNING, "Out of memory while decompressing data");
}
// Decompress data
tempUncompSize = tinfl_decompress_mem_to_mem(pUncomp, (size_t)uncompSize, data, compSize, 1);
if (tempUncompSize == -1)
else
{
printf("Decompression failed!\n");
free(pUncomp);
return NULL;
}
if (uncompSize != (int)tempUncompSize)
{
printf("WARNING! Expected uncompressed size do not match! Data may be corrupted!\n");
printf(" -- Expected uncompressed size: %i\n", uncompSize);
printf(" -- Returned uncompressed size: %i\n", tempUncompSize);
}
// Decompress data
tempUncompSize = tinfl_decompress_mem_to_mem(pUncomp, (size_t)uncompSize, data, compSize, 1);
if (tempUncompSize == -1)
{
TraceLog(WARNING, "Data decompression failed");
free(pUncomp);
}
if (uncompSize != (int)tempUncompSize)
{
TraceLog(WARNING, "Expected uncompressed size do not match, data may be corrupted");
TraceLog(WARNING, " -- Expected uncompressed size: %i", uncompSize);
TraceLog(WARNING, " -- Returned uncompressed size: %i", tempUncompSize);
}
printf("Decompressed from %u bytes to %u bytes\n", (mz_uint32)compSize, (mz_uint32)tempUncompSize);
TraceLog(INFO, "Data decompressed successfully from %u bytes to %u bytes", (mz_uint32)compSize, (mz_uint32)tempUncompSize);
}
return pUncomp;
}
@ -124,4 +134,100 @@ void WriteBitmap(const char *fileName, unsigned char *imgData, int width, int he
void WritePNG(const char *fileName, unsigned char *imgData, int width, int height)
{
stbi_write_png(fileName, width, height, 4, imgData, width*4); // It WORKS!!!
}
}
// Outputs a trace log message (INFO, ERROR, WARNING)
// NOTE: If a file has been init, output log is written there
void TraceLog(int msgType, const char *text, ...)
{
// TODO: This function requires some refactoring...
// NOTE: If trace log file has been set, stdout is being redirected to a file
va_list args;
int traceDebugMsgs = 1;
#ifdef DO_NOT_TRACE_DEBUG_MSGS
traceDebugMsgs = 0;
#endif
if (logstream != NULL)
{
switch(msgType)
{
case 0: fprintf(logstream, "INFO: "); break;
case 1: fprintf(logstream, "ERROR: "); break;
case 2: fprintf(logstream, "WARNING: "); break;
case 3: if (traceDebugMsgs) fprintf(logstream, "DEBUG: "); break;
default: break;
}
if (msgType == 3)
{
if (traceDebugMsgs)
{
va_start(args, text);
vfprintf(logstream, text, args);
va_end(args);
fprintf(logstream, "\n");
}
}
else
{
va_start(args, text);
vfprintf(logstream, text, args);
va_end(args);
fprintf(logstream, "\n");
}
}
else
{
switch(msgType)
{
case 0: fprintf(stdout, "INFO: "); break;
case 1: fprintf(stdout, "ERROR: "); break;
case 2: fprintf(stdout, "WARNING: "); break;
case 3: if (traceDebugMsgs) fprintf(stdout, "DEBUG: "); break;
default: break;
}
if (msgType == 3)
{
if (traceDebugMsgs)
{
va_start(args, text);
vfprintf(stdout, text, args);
va_end(args);
fprintf(stdout, "\n");
}
}
else
{
va_start(args, text);
vfprintf(stdout, text, args);
va_end(args);
fprintf(stdout, "\n");
}
}
if (msgType == 1) exit(1); // If ERROR message, exit program
}
// Inits a trace log file
void InitTraceLogFile(const char *logFileName)
{
// stdout redirected to stream file
FILE *logstream = fopen(logFileName, "w");
if (logstream == NULL) TraceLog(WARNING, "Unable to open log file");
}
// Closes the trace log file
void CloseTraceLogFile()
{
if (logstream != NULL) fclose(logstream);
}

View file

@ -32,13 +32,15 @@
//----------------------------------------------------------------------------------
// Some basic Defines
//----------------------------------------------------------------------------------
//...
//#define DO_NOT_TRACE_DEBUG_MSGS // Use this define to avoid DEBUG tracing
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
typedef enum { IMAGE, SOUND, MODEL, TEXT, RAW } DataType;
typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
// One resource info header, every resource includes this header (8 byte)
typedef struct {
unsigned short id; // Resource unique identifier (2 byte)
@ -61,9 +63,14 @@ extern "C" { // Prevents name mangling of functions
// Module Functions Declaration
//----------------------------------------------------------------------------------
unsigned char *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize);
void WriteBitmap(const char *fileName, unsigned char *imgData, int width, int height);
void WritePNG(const char *fileName, unsigned char *imgData, int width, int height);
void TraceLog(int msgType, const char *text, ...); // Outputs a trace log message
void InitTraceLogFile(const char *logFileName); // Inits a trace log file
void CloseTraceLogFile(); // Closes the trace log file
#ifdef __cplusplus
}
#endif

View file

@ -1,140 +0,0 @@
/*********************************************************************************************
*
* raylib.vector3
*
* Vector3 Functions Definition
*
* 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
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
#include "vector3.h"
#include <math.h> // Used for fabs(), sqrt()
// Add two vectors
Vector3 VectorAdd(Vector3 v1, Vector3 v2)
{
Vector3 out;
out.x = v1.x + v2.x;
out.y = v1.y + v2.y;
out.z = v1.z + v2.z;
return out;
}
// Substract two vectors
Vector3 VectorSubtract(Vector3 v1, Vector3 v2)
{
Vector3 out;
out.x = v1.x - v2.x;
out.y = v1.y - v2.y;
out.z = v1.z - v2.z;
return out;
}
// Calculate two vectors cross product
Vector3 VectorCrossProduct(Vector3 v1, Vector3 v2)
{
Vector3 cross;
cross.x = v1.y*v2.z - v1.z*v2.y;
cross.y = v1.z*v2.x - v1.x*v2.z;
cross.z = v1.x*v2.y - v1.y*v2.x;
return cross;
}
// Calculate one vector perpendicular vector
Vector3 VectorPerpendicular(Vector3 v)
{
Vector3 out;
float min = fabs(v.x);
Vector3 cardinalAxis = {1.0, 0.0, 0.0};
if (fabs(v.y) < min)
{
min = fabs(v.y);
cardinalAxis = (Vector3){0.0, 1.0, 0.0};
}
if(fabs(v.z) < min)
{
cardinalAxis = (Vector3){0.0, 0.0, 1.0};
}
out = VectorCrossProduct(v, cardinalAxis);
return out;
}
// Calculate two vectors dot product
float VectorDotProduct(Vector3 v1, Vector3 v2)
{
float dot;
dot = v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
return dot;
}
// Calculate vector lenght
float VectorLength(const Vector3 v)
{
float length;
length = sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
return length;
}
// Scale provided vector
void VectorScale(Vector3 *v, float scale)
{
v->x *= scale;
v->y *= scale;
v->z *= scale;
}
// Invert provided vector (direction)
void VectorInverse(Vector3 *v)
{
v->x = -v->x;
v->y = -v->y;
v->z = -v->z;
}
// Normalize provided vector
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;
}

View file

@ -1,57 +0,0 @@
/*********************************************************************************************
*
* raylib.vector3
*
* Some useful functions to work with Vector3
*
* 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
* will the authors be held liable for any damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose, including commercial
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not claim that you
* wrote the original software. If you use this software in a product, an acknowledgment
* in the product documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
* as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
**********************************************************************************************/
#ifndef VECTOR3_H
#define VECTOR3_H
#include "raylib.h" // Defines Vector3 structure
#ifdef __cplusplus
extern "C" { // Prevents name mangling of functions
#endif
//------------------------------------------------------------------------------------
// Global Variables Definition
//------------------------------------------------------------------------------------
// It's lonely here...
//------------------------------------------------------------------------------------
// Functions Declaration to work with Vector3
//------------------------------------------------------------------------------------
Vector3 VectorAdd(Vector3 v1, Vector3 v2); // Add two vectors
Vector3 VectorSubtract(Vector3 v1, Vector3 v2); // Substract two vectors
Vector3 VectorCrossProduct(Vector3 v1, Vector3 v2); // Calculate two vectors cross product
Vector3 VectorPerpendicular(Vector3 v); // Calculate one vector perpendicular vector
float VectorDotProduct(Vector3 v1, Vector3 v2); // Calculate two vectors dot product
float VectorLength(const Vector3 v); // Calculate vector lenght
void VectorScale(Vector3 *v, float scale); // Scale provided vector
void VectorInverse(Vector3 *v); // Invert provided vector (direction)
void VectorNormalize(Vector3 *v); // Normalize provided vector
#ifdef __cplusplus
}
#endif
#endif // VECTOR3_H