aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRay <raysan5@gmail.com>2014-04-19 14:21:22 +0200
committerRay <raysan5@gmail.com>2014-04-19 14:21:22 +0200
commit650a8f7f159d3ce2addb1b0fdb31c3f460005391 (patch)
tree01f1a6968b784d07d63f6bf741c1527145cea25c /src
parent1c8dce429ee5a58d535fcca0e29fe3711aa3fcb5 (diff)
parente6b82cb111c3485c5e6131fe29791f938305bce3 (diff)
downloadraylib-650a8f7f159d3ce2addb1b0fdb31c3f460005391.tar.gz
raylib-650a8f7f159d3ce2addb1b0fdb31c3f460005391.zip
Merge pull request #2 from raysan5/testing
Integrate raylib 1.1 changes into master
Diffstat (limited to 'src')
-rw-r--r--src/audio.c611
-rw-r--r--src/core.c320
-rw-r--r--src/models.c1145
-rw-r--r--src/raylib.h98
-rw-r--r--src/raymath.c562
-rw-r--r--src/raymath.h2
-rw-r--r--src/rlgl.c1572
-rw-r--r--src/rlgl.h153
-rw-r--r--src/shapes.c304
-rw-r--r--src/simple150.frag1
-rw-r--r--src/stb_vorbis.c4
-rw-r--r--src/stb_vorbis.h9
-rw-r--r--src/text.c187
-rw-r--r--src/textures.c593
-rw-r--r--src/utils.c148
-rw-r--r--src/utils.h9
-rw-r--r--src/vector3.c140
-rw-r--r--src/vector3.h57
18 files changed, 4031 insertions, 1884 deletions
diff --git a/src/audio.c b/src/audio.c
index 4b75942f..35874b59 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -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;
+ TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName);
+ }
+ else
+ {
+ // Read number of resources embedded
+ fread(&numRes, sizeof(short), 1, rresFile);
- 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;
+ for (int i = 0; i < numRes; i++)
+ {
+ fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile);
- // The OpenAL format is worked out by looking at the number of channels and the bits per sample
- if (wave.channels == 1)
+ if (infoHeader.id == resId)
{
- 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;
+ 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);
+ }
}
-
-
- // 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);
+ 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);
+ }
}
}
- 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);
+ }
+} \ No newline at end of file
diff --git a/src/core.c b/src/core.c
index bd373c7c..79866a2f 100644
--- a/src/core.c
+++ b/src/core.c
@@ -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
-
- glLoadIdentity(); // Reset current matrix (MODELVIEW)
+ rlClearScreenBuffers();
- 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
@@ -650,124 +721,31 @@ 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++;
} \ No newline at end of file
diff --git a/src/models.c b/src/models.c
index e21ff894..84ef43fa 100644
--- a/src/models.c
+++ b/src/models.c
@@ -29,7 +29,9 @@
#include <stdio.h> // Standard input/output functions, used to read model files data
#include <stdlib.h> // Declares malloc() and free() for memory management
#include <math.h> // Used for sin, cos, tan
-#include "vector3.h" // Basic Vector3 functions
+
+#include "raymath.h" // Required for data type Matrix and Matrix functions
+#include "rlgl.h" // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
//----------------------------------------------------------------------------------
// Defines and Macros
@@ -39,14 +41,7 @@
//----------------------------------------------------------------------------------
// Types and Structures Definition
//----------------------------------------------------------------------------------
-
-// Matrix type (OpenGL style 4x4 - right handed)
-typedef struct Matrix {
- float m0, m4, m8, m12;
- float m1, m5, m9, m13;
- float m2, m6, m10, m14;
- float m3, m7, m11, m15;
-} Matrix;
+// ...
//----------------------------------------------------------------------------------
// Global Variables Definition
@@ -57,8 +52,6 @@ typedef struct Matrix {
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
static float GetHeightValue(Color pixel);
-static void MatrixTranspose(Matrix *mat);
-static Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up);
//----------------------------------------------------------------------------------
// Module Functions Definition
@@ -68,52 +61,75 @@ static Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up);
// NOTE: Cube position is the center position
void DrawCube(Vector3 position, float width, float height, float lenght, Color color)
{
- glPushMatrix();
- glTranslatef(position.x, position.y, position.z);
- //glRotatef(rotation, 0.0f, 1.0f, 0.0f);
- //glScalef(1.0f, 1.0f, 1.0f);
+ float x = position.x;
+ float y = position.y;
+ float z = position.z;
+
+ rlPushMatrix();
- glBegin(GL_QUADS);
- glColor4ub(color.r, color.g, color.b, color.a);
+ // NOTE: Be careful! Function order matters (scale, translate, rotate)
+ //rlScalef(2.0f, 2.0f, 2.0f);
+ //rlTranslatef(0.0f, 0.0f, 0.0f);
+ //rlRotatef(45, 0, 1, 0);
+
+ rlBegin(RL_TRIANGLES);
+ rlColor4ub(color.r, color.g, color.b, color.a);
- // Front Face
- glNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
- glTexCoord2f(0.0f, 0.0f); glVertex3f(-width/2, -height/2, lenght/2); // Bottom Left Of The Texture and Quad
- glTexCoord2f(1.0f, 0.0f); glVertex3f( width/2, -height/2, lenght/2); // Bottom Right Of The Texture and Quad
- glTexCoord2f(1.0f, 1.0f); glVertex3f( width/2, height/2, lenght/2); // Top Right Of The Texture and Quad
- glTexCoord2f(0.0f, 1.0f); glVertex3f(-width/2, height/2, lenght/2); // Top Left Of The Texture and Quad
- // Back Face
- glNormal3f( 0.0f, 0.0f,-1.0f); // Normal Pointing Away From Viewer
- glTexCoord2f(1.0f, 0.0f); glVertex3f(-width/2, -height/2, -lenght/2); // Bottom Right Of The Texture and Quad
- glTexCoord2f(1.0f, 1.0f); glVertex3f(-width/2, height/2, -lenght/2); // Top Right Of The Texture and Quad
- glTexCoord2f(0.0f, 1.0f); glVertex3f( width/2, height/2, -lenght/2); // Top Left Of The Texture and Quad
- glTexCoord2f(0.0f, 0.0f); glVertex3f( width/2, -height/2, -lenght/2); // Bottom Left Of The Texture and Quad
- // Top Face
- glNormal3f( 0.0f, 1.0f, 0.0f); // Normal Pointing Up
- glTexCoord2f(0.0f, 1.0f); glVertex3f(-width/2, height/2, -lenght/2); // Top Left Of The Texture and Quad
- glTexCoord2f(0.0f, 0.0f); glVertex3f(-width/2, height/2, lenght/2); // Bottom Left Of The Texture and Quad
- glTexCoord2f(1.0f, 0.0f); glVertex3f( width/2, height/2, lenght/2); // Bottom Right Of The Texture and Quad
- glTexCoord2f(1.0f, 1.0f); glVertex3f( width/2, height/2, -lenght/2); // Top Right Of The Texture and Quad
- // Bottom Face
- glNormal3f( 0.0f,-1.0f, 0.0f); // Normal Pointing Down
- glTexCoord2f(1.0f, 1.0f); glVertex3f(-width/2, -height/2, -lenght/2); // Top Right Of The Texture and Quad
- glTexCoord2f(0.0f, 1.0f); glVertex3f( width/2, -height/2, -lenght/2); // Top Left Of The Texture and Quad
- glTexCoord2f(0.0f, 0.0f); glVertex3f( width/2, -height/2, lenght/2); // Bottom Left Of The Texture and Quad
- glTexCoord2f(1.0f, 0.0f); glVertex3f(-width/2, -height/2, lenght/2); // Bottom Right Of The Texture and Quad
- // Right face
- glNormal3f( 1.0f, 0.0f, 0.0f); // Normal Pointing Right
- glTexCoord2f(1.0f, 0.0f); glVertex3f( width/2, -height/2, -lenght/2); // Bottom Right Of The Texture and Quad
- glTexCoord2f(1.0f, 1.0f); glVertex3f( width/2, height/2, -lenght/2); // Top Right Of The Texture and Quad
- glTexCoord2f(0.0f, 1.0f); glVertex3f( width/2, height/2, lenght/2); // Top Left Of The Texture and Quad
- glTexCoord2f(0.0f, 0.0f); glVertex3f( width/2, -height/2, lenght/2); // Bottom Left Of The Texture and Quad
- // Left Face
- glNormal3f(-1.0f, 0.0f, 0.0f); // Normal Pointing Left
- glTexCoord2f(0.0f, 0.0f); glVertex3f(-width/2, -height/2, -lenght/2); // Bottom Left Of The Texture and Quad
- glTexCoord2f(1.0f, 0.0f); glVertex3f(-width/2, -height/2, lenght/2); // Bottom Right Of The Texture and Quad
- glTexCoord2f(1.0f, 1.0f); glVertex3f(-width/2, height/2, lenght/2); // Top Right Of The Texture and Quad
- glTexCoord2f(0.0f, 1.0f); glVertex3f(-width/2, height/2, -lenght/2); // Top Left Of The Texture and Quad
- glEnd();
- glPopMatrix();
+ // Front Face -----------------------------------------------------
+ rlVertex3f(x-width/2, y-height/2, z+lenght/2); // Bottom Left
+ rlVertex3f(x+width/2, y-height/2, z+lenght/2); // Bottom Right
+ rlVertex3f(x-width/2, y+height/2, z+lenght/2); // Top Left
+
+ rlVertex3f(x+width/2, y+height/2, z+lenght/2); // Top Right
+ rlVertex3f(x-width/2, y+height/2, z+lenght/2); // Top Left
+ rlVertex3f(x+width/2, y-height/2, z+lenght/2); // Bottom Right
+
+ // Back Face ------------------------------------------------------
+ rlVertex3f(x-width/2, y-height/2, z-lenght/2); // Bottom Left
+ rlVertex3f(x-width/2, y+height/2, z-lenght/2); // Top Left
+ rlVertex3f(x+width/2, y-height/2, z-lenght/2); // Bottom Right
+
+ rlVertex3f(x+width/2, y+height/2, z-lenght/2); // Top Right
+ rlVertex3f(x+width/2, y-height/2, z-lenght/2); // Bottom Right
+ rlVertex3f(x-width/2, y+height/2, z-lenght/2); // Top Left
+
+ // Top Face -------------------------------------------------------
+ rlVertex3f(x-width/2, y+height/2, z-lenght/2); // Top Left
+ rlVertex3f(x-width/2, y+height/2, z+lenght/2); // Bottom Left
+ rlVertex3f(x+width/2, y+height/2, z+lenght/2); // Bottom Right
+
+ rlVertex3f(x+width/2, y+height/2, z-lenght/2); // Top Right
+ rlVertex3f(x-width/2, y+height/2, z-lenght/2); // Top Left
+ rlVertex3f(x+width/2, y+height/2, z+lenght/2); // Bottom Right
+
+ // Bottom Face ----------------------------------------------------
+ rlVertex3f(x-width/2, y-height/2, z-lenght/2); // Top Left
+ rlVertex3f(x+width/2, y-height/2, z+lenght/2); // Bottom Right
+ rlVertex3f(x-width/2, y-height/2, z+lenght/2); // Bottom Left
+
+ rlVertex3f(x+width/2, y-height/2, z-lenght/2); // Top Right
+ rlVertex3f(x+width/2, y-height/2, z+lenght/2); // Bottom Right
+ rlVertex3f(x-width/2, y-height/2, z-lenght/2); // Top Left
+
+ // Right face -----------------------------------------------------
+ rlVertex3f(x+width/2, y-height/2, z-lenght/2); // Bottom Right
+ rlVertex3f(x+width/2, y+height/2, z-lenght/2); // Top Right
+ rlVertex3f(x+width/2, y+height/2, z+lenght/2); // Top Left
+
+ rlVertex3f(x+width/2, y-height/2, z+lenght/2); // Bottom Left
+ rlVertex3f(x+width/2, y-height/2, z-lenght/2); // Bottom Right
+ rlVertex3f(x+width/2, y+height/2, z+lenght/2); // Top Left
+
+ // Left Face ------------------------------------------------------
+ rlVertex3f(x-width/2, y-height/2, z-lenght/2); // Bottom Right
+ rlVertex3f(x-width/2, y+height/2, z+lenght/2); // Top Left
+ rlVertex3f(x-width/2, y+height/2, z-lenght/2); // Top Right
+
+ rlVertex3f(x-width/2, y-height/2, z+lenght/2); // Bottom Left
+ rlVertex3f(x-width/2, y+height/2, z+lenght/2); // Top Left
+ rlVertex3f(x-width/2, y-height/2, z-lenght/2); // Bottom Right
+ rlEnd();
+ rlPopMatrix();
}
// Draw cube (Vector version)
@@ -125,9 +141,130 @@ void DrawCubeV(Vector3 position, Vector3 size, Color color)
// Draw cube wires
void DrawCubeWires(Vector3 position, float width, float height, float lenght, Color color)
{
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- DrawCube(position, width, height, lenght, color);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ float x = position.x;
+ float y = position.y;
+ float z = position.z;
+
+ rlPushMatrix();
+
+ //rlRotatef(45, 0, 1, 0);
+
+ rlBegin(RL_LINES);
+ rlColor4ub(color.r, color.g, color.b, color.a);
+
+ // Front Face -----------------------------------------------------
+ // Bottom Line
+ rlVertex3f(x-width/2, y-height/2, z+lenght/2); // Bottom Left
+ rlVertex3f(x+width/2, y-height/2, z+lenght/2); // Bottom Right
+
+ // Left Line
+ rlVertex3f(x+width/2, y-height/2, z+lenght/2); // Bottom Right
+ rlVertex3f(x+width/2, y+height/2, z+lenght/2); // Top Right
+
+ // Top Line
+ rlVertex3f(x+width/2, y+height/2, z+lenght/2); // Top Right
+ rlVertex3f(x-width/2, y+height/2, z+lenght/2); // Top Left
+
+ // Right Line
+ rlVertex3f(x-width/2, y+height/2, z+lenght/2); // Top Left
+ rlVertex3f(x-width/2, y-height/2, z+lenght/2); // Bottom Left
+
+ // Back Face ------------------------------------------------------
+ // Bottom Line
+ rlVertex3f(x-width/2, y-height/2, z-lenght/2); // Bottom Left
+ rlVertex3f(x+width/2, y-height/2, z-lenght/2); // Bottom Right
+
+ // Left Line
+ rlVertex3f(x+width/2, y-height/2, z-lenght/2); // Bottom Right
+ rlVertex3f(x+width/2, y+height/2, z-lenght/2); // Top Right
+
+ // Top Line
+ rlVertex3f(x+width/2, y+height/2, z-lenght/2); // Top Right
+ rlVertex3f(x-width/2, y+height/2, z-lenght/2); // Top Left
+
+ // Right Line
+ rlVertex3f(x-width/2, y+height/2, z-lenght/2); // Top Left
+ rlVertex3f(x-width/2, y-height/2, z-lenght/2); // Bottom Left
+
+ // Top Face -------------------------------------------------------
+ // Left Line
+ rlVertex3f(x-width/2, y+height/2, z+lenght/2); // Top Left Front
+ rlVertex3f(x-width/2, y+height/2, z-lenght/2); // Top Left Back
+
+ // Right Line
+ rlVertex3f(x+width/2, y+height/2, z+lenght/2); // Top Right Front
+ rlVertex3f(x+width/2, y+height/2, z-lenght/2); // Top Right Back
+
+ // Bottom Face ---------------------------------------------------
+ // Left Line
+ rlVertex3f(x-width/2, y-height/2, z+lenght/2); // Top Left Front
+ rlVertex3f(x-width/2, y-height/2, z-lenght/2); // Top Left Back
+
+ // Right Line
+ rlVertex3f(x+width/2, y-height/2, z+lenght/2); // Top Right Front
+ rlVertex3f(x+width/2, y-height/2, z-lenght/2); // Top Right Back
+ rlEnd();
+ rlPopMatrix();
+}
+
+// Draw cube
+// NOTE: Cube position is the center position
+void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float height, float lenght, Color color)
+{
+ float x = position.x;
+ float y = position.y;
+ float z = position.z;
+
+ rlEnableTexture(texture.glId);
+
+ rlPushMatrix();
+ // NOTE: Be careful! Function order matters (scale, translate, rotate)
+ //rlScalef(2.0f, 2.0f, 2.0f);
+ //rlTranslatef(2.0f, 0.0f, 0.0f);
+ //rlRotatef(45, 0, 1, 0);
+
+ rlBegin(RL_QUADS);
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ // Front Face
+ rlNormal3f(0.0f, 0.0f, 1.0f); // Normal Pointing Towards Viewer
+ rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x-width/2, y-height/2, z+lenght/2); // Bottom Left Of The Texture and Quad
+ rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x+width/2, y-height/2, z+lenght/2); // Bottom Right Of The Texture and Quad
+ rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x+width/2, y+height/2, z+lenght/2); // Top Right Of The Texture and Quad
+ rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z+lenght/2); // Top Left Of The Texture and Quad
+ // Back Face
+ rlNormal3f( 0.0f, 0.0f,-1.0f); // Normal Pointing Away From Viewer
+ rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x-width/2, y-height/2, z-lenght/2); // Bottom Right Of The Texture and Quad
+ rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z-lenght/2); // Top Right Of The Texture and Quad
+ rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x+width/2, y+height/2, z-lenght/2); // Top Left Of The Texture and Quad
+ rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x+width/2, y-height/2, z-lenght/2); // Bottom Left Of The Texture and Quad
+ // Top Face
+ rlNormal3f( 0.0f, 1.0f, 0.0f); // Normal Pointing Up
+ rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z-lenght/2); // Top Left Of The Texture and Quad
+ rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x-width/2, y+height/2, z+lenght/2); // Bottom Left Of The Texture and Quad
+ rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x+width/2, y+height/2, z+lenght/2); // Bottom Right Of The Texture and Quad
+ rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x+width/2, y+height/2, z-lenght/2); // Top Right Of The Texture and Quad
+ // Bottom Face
+ rlNormal3f( 0.0f,-1.0f, 0.0f); // Normal Pointing Down
+ rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x-width/2, y-height/2, z-lenght/2); // Top Right Of The Texture and Quad
+ rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x+width/2, y-height/2, z-lenght/2); // Top Left Of The Texture and Quad
+ rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x+width/2, y-height/2, z+lenght/2); // Bottom Left Of The Texture and Quad
+ rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x-width/2, y-height/2, z+lenght/2); // Bottom Right Of The Texture and Quad
+ // Right face
+ rlNormal3f( 1.0f, 0.0f, 0.0f); // Normal Pointing Right
+ rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x+width/2, y-height/2, z-lenght/2); // Bottom Right Of The Texture and Quad
+ rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x+width/2, y+height/2, z-lenght/2); // Top Right Of The Texture and Quad
+ rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x+width/2, y+height/2, z+lenght/2); // Top Left Of The Texture and Quad
+ rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x+width/2, y-height/2, z+lenght/2); // Bottom Left Of The Texture and Quad
+ // Left Face
+ rlNormal3f(-1.0f, 0.0f, 0.0f); // Normal Pointing Left
+ rlTexCoord2f(0.0f, 0.0f); rlVertex3f(x-width/2, y-height/2, z-lenght/2); // Bottom Left Of The Texture and Quad
+ rlTexCoord2f(1.0f, 0.0f); rlVertex3f(x-width/2, y-height/2, z+lenght/2); // Bottom Right Of The Texture and Quad
+ rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z+lenght/2); // Top Right Of The Texture and Quad
+ rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z-lenght/2); // Top Left Of The Texture and Quad
+ rlEnd();
+ rlPopMatrix();
+
+ rlDisableTexture();
}
// Draw sphere
@@ -139,200 +276,197 @@ void DrawSphere(Vector3 centerPos, float radius, Color color)
// Draw sphere with extended parameters
void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color color)
{
- float lat0, z0, zr0;
- float lat1, z1, zr1;
- float lng, x, y;
-
- glPushMatrix();
- glTranslatef(centerPos.x, centerPos.y, centerPos.z);
- glRotatef(90, 1, 0, 0);
- glScalef(radius, radius, radius);
+ rlPushMatrix();
+ rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
+ //rlRotatef(rotation, 0, 1, 0);
+ rlScalef(radius, radius, radius);
- glBegin(GL_QUAD_STRIP);
-
- 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 <= rings; i++)
+ for(int i = 0; i < 2 * rings + 1; i ++)
{
- lat0 = PI * (-0.5 + (float)(i - 1) / rings);
- z0 = sin(lat0);
- zr0 = cos(lat0);
-
- lat1 = PI * (-0.5 + (float)i / rings);
- z1 = sin(lat1);
- zr1 = cos(lat1);
-
- for(int j = 0; j <= slices; j++)
+ for(int j = 0; j < slices; j++)
{
- lng = 2 * PI * (float)(j - 1) / slices;
- x = cos(lng);
- y = sin(lng);
-
- glNormal3f(x * zr0, y * zr0, z0);
- glVertex3f(x * zr0, y * zr0, z0);
-
- glNormal3f(x * zr1, y * zr1, z1);
- glVertex3f(x * zr1, y * zr1, z1);
+ rlVertex3f(cos(DEG2RAD*(270+(90/rings)*i)) * sin(DEG2RAD*(j*360/slices)) * radius,
+ sin(DEG2RAD*(270+(90/rings)*i)) * radius,
+ cos(DEG2RAD*(270+(90/rings)*i)) * cos(DEG2RAD*(j*360/slices)) * radius);
+ rlVertex3f(cos(DEG2RAD*(270+(90/rings)*(i+1))) * sin(DEG2RAD*((j+1)*360/slices)) * radius,
+ sin(DEG2RAD*(270+(90/rings)*(i+1))) * radius,
+ cos(DEG2RAD*(270+(90/rings)*(i+1))) * cos(DEG2RAD*((j+1)*360/slices)) * radius);
+ rlVertex3f(cos(DEG2RAD*(270+(90/rings)*(i+1))) * sin(DEG2RAD*(j*360/slices)) * radius,
+ sin(DEG2RAD*(270+(90/rings)*(i+1))) * radius,
+ cos(DEG2RAD*(270+(90/rings)*(i+1))) * cos(DEG2RAD*(j*360/slices)) * radius);
+
+ rlVertex3f(cos(DEG2RAD*(270+(90/rings)*i)) * sin(DEG2RAD*(j*360/slices)) * radius,
+ sin(DEG2RAD*(270+(90/rings)*i)) * radius,
+ cos(DEG2RAD*(270+(90/rings)*i)) * cos(DEG2RAD*(j*360/slices)) * radius);
+ rlVertex3f(cos(DEG2RAD*(270+(90/rings)*(i))) * sin(DEG2RAD*((j+1)*360/slices)) * radius,
+ sin(DEG2RAD*(270+(90/rings)*(i))) * radius,
+ cos(DEG2RAD*(270+(90/rings)*(i))) * cos(DEG2RAD*((j+1)*360/slices)) * radius);
+ rlVertex3f(cos(DEG2RAD*(270+(90/rings)*(i+1))) * sin(DEG2RAD*((j+1)*360/slices)) * radius,
+ sin(DEG2RAD*(270+(90/rings)*(i+1))) * radius,
+ cos(DEG2RAD*(270+(90/rings)*(i+1))) * cos(DEG2RAD*((j+1)*360/slices)) * radius);
}
}
- glEnd();
- glPopMatrix();
+ rlEnd();
+ rlPopMatrix();
}
// Draw sphere wires
-void DrawSphereWires(Vector3 centerPos, float radius, Color color)
-{
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- DrawSphere(centerPos, radius, color);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-}
-
-// Draw a cylinder/cone
-void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color) // Could be used for pyramid and cone!
+void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color)
{
- Vector3 a = { position.x, position.y + height, position.z };
- Vector3 d = { 0.0f, 1.0f, 0.0f };
- Vector3 p;
- Vector3 c = { a.x + (-d.x * height), a.y + (-d.y * height), a.z + (-d.z * height) }; //= a + (-d * h);
- Vector3 e0 = VectorPerpendicular(d);
- Vector3 e1 = VectorCrossProduct(e0, d);
- float angInc = 360.0 / slices * DEG2RAD;
-
- if (radiusTop == 0) // Draw pyramid or cone
- {
- //void drawCone(const Vector3 &d, const Vector3 &a, const float h, const float rd, const int n)
- //d – axis defined as a normalized vector from base to apex
- //a – position of apex (top point)
- //h – height
- //rd – radius of directrix
- //n – number of radial "slices"
+ rlPushMatrix();
+ rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
+ //rlRotatef(rotation, 0, 1, 0);
+ rlScalef(radius, radius, radius);
- glPushMatrix();
- //glTranslatef(centerPos.x, centerPos.y, centerPos.z);
- //glRotatef(degrees, 0.0f, 1.0f, 0.0f);
- //glScalef(1.0f, 1.0f, 1.0f);
-
- // Draw cone top
- glBegin(GL_TRIANGLE_FAN);
- glColor4ub(color.r, color.g, color.b, color.a);
- glVertex3f(a.x, a.y, a.z);
- for (int i = 0; i <= slices; i++)
- {
- float rad = angInc * i;
- p.x = c.x + (((e0.x * cos(rad)) + (e1.x * sin(rad))) * radiusBottom);
- p.y = c.y + (((e0.y * cos(rad)) + (e1.y * sin(rad))) * radiusBottom);
- p.z = c.z + (((e0.z * cos(rad)) + (e1.z * sin(rad))) * radiusBottom);
- glVertex3f(p.x, p.y, p.z);
- }
- glEnd();
-
- // Draw cone bottom
- glBegin(GL_TRIANGLE_FAN);
- glColor4ub(color.r, color.g, color.b, color.a);
- glVertex3f(c.x, c.y, c.z);
- for (int i = slices; i >= 0; i--)
- {
- float rad = angInc * i;
- p.x = c.x + (((e0.x * cos(rad)) + (e1.x * sin(rad))) * radiusBottom);
- p.y = c.y + (((e0.y * cos(rad)) + (e1.y * sin(rad))) * radiusBottom);
- p.z = c.z + (((e0.z * cos(rad)) + (e1.z * sin(rad))) * radiusBottom);
- glVertex3f(p.x, p.y, p.z);
- }
- glEnd();
+ rlBegin(RL_LINES);
+ rlColor4ub(color.r, color.g, color.b, color.a);
- glPopMatrix();
- }
- else // Draw cylinder
- {
- glPushMatrix();
- //glTranslatef(centerPos.x, centerPos.y, centerPos.z);
- //glRotatef(degrees, 0.0f, 1.0f, 0.0f);
- //glScalef(1.0f, 1.0f, 1.0f);
-
- // Draw cylinder top (pointed cap)
- glBegin(GL_TRIANGLE_FAN);
- glColor4ub(color.r, color.g, color.b, color.a);
- glVertex3f(c.x, c.y + height, c.z);
- for (int i = slices; i >= 0; i--)
+ for(int i = 0; i < 2 * rings + 1; i ++)
+ {
+ for(int j = 0; j < slices; j++)
{
- float rad = angInc * i;
- p.x = c.x + (((e0.x * cos(rad)) + (e1.x * sin(rad))) * radiusTop);
- p.y = c.y + (((e0.y * cos(rad)) + (e1.y * sin(rad))) * radiusTop) + height;
- p.z = c.z + (((e0.z * cos(rad)) + (e1.z * sin(rad))) * radiusTop);
- glVertex3f(p.x, p.y, p.z);
+ rlVertex3f(cos(DEG2RAD*(270+(90/rings)*i)) * sin(DEG2RAD*(j*360/slices)) * radius,
+ sin(DEG2RAD*(270+(90/rings)*i)) * radius,
+ cos(DEG2RAD*(270+(90/rings)*i)) * cos(DEG2RAD*(j*360/slices)) * radius);
+ rlVertex3f(cos(DEG2RAD*(270+(90/rings)*(i+1))) * sin(DEG2RAD*((j+1)*360/slices)) * radius,
+ sin(DEG2RAD*(270+(90/rings)*(i+1))) * radius,
+ cos(DEG2RAD*(270+(90/rings)*(i+1))) * cos(DEG2RAD*((j+1)*360/slices)) * radius);
+
+ rlVertex3f(cos(DEG2RAD*(270+(90/rings)*(i+1))) * sin(DEG2RAD*((j+1)*360/slices)) * radius,
+ sin(DEG2RAD*(270+(90/rings)*(i+1))) * radius,
+ cos(DEG2RAD*(270+(90/rings)*(i+1))) * cos(DEG2RAD*((j+1)*360/slices)) * radius);
+ rlVertex3f(cos(DEG2RAD*(270+(90/rings)*(i+1))) * sin(DEG2RAD*(j*360/slices)) * radius,
+ sin(DEG2RAD*(270+(90/rings)*(i+1))) * radius,
+ cos(DEG2RAD*(270+(90/rings)*(i+1))) * cos(DEG2RAD*(j*360/slices)) * radius);
+
+ rlVertex3f(cos(DEG2RAD*(270+(90/rings)*(i+1))) * sin(DEG2RAD*(j*360/slices)) * radius,
+ sin(DEG2RAD*(270+(90/rings)*(i+1))) * radius,
+ cos(DEG2RAD*(270+(90/rings)*(i+1))) * cos(DEG2RAD*(j*360/slices)) * radius);
+ rlVertex3f(cos(DEG2RAD*(270+(90/rings)*i)) * sin(DEG2RAD*(j*360/slices)) * radius,
+ sin(DEG2RAD*(270+(90/rings)*i)) * radius,
+ cos(DEG2RAD*(270+(90/rings)*i)) * cos(DEG2RAD*(j*360/slices)) * radius);
}
- glEnd();
-
- // Draw cylinder sides
- glBegin(GL_TRIANGLE_STRIP);
- glColor4ub(color.r, color.g, color.b, color.a);
- for (int i = slices; i >= 0; i--)
+ }
+ rlEnd();
+ rlPopMatrix();
+}
+
+// Draw a cylinder
+// NOTE: It could be also used for pyramid and cone
+void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
+{
+ if (sides < 3) sides = 3;
+
+ rlPushMatrix();
+ rlTranslatef(position.x, position.y, position.z);
+
+ rlBegin(RL_TRIANGLES);
+ rlColor4ub(color.r, color.g, color.b, color.a);
+
+ if (radiusTop > 0)
+ {
+ // Draw Body -------------------------------------------------------------------------------------
+ for(int i = 0; i < 360; i += 360/sides)
{
- float rad = angInc * i;
- p.x = c.x + (((e0.x * cos(rad)) + (e1.x * sin(rad))) * radiusTop);
- p.y = c.y + (((e0.y * cos(rad)) + (e1.y * sin(rad))) * radiusTop) + height;
- p.z = c.z + (((e0.z * cos(rad)) + (e1.z * sin(rad))) * radiusTop);
- glVertex3f(p.x, p.y, p.z);
+ rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom); //Bottom Left
+ rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom); //Bottom Right
+ rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusTop, height, cos(DEG2RAD*(i+360/sides)) * radiusTop); //Top Right
- p.x = c.x + (((e0.x * cos(rad)) + (e1.x * sin(rad))) * radiusBottom);
- p.y = c.y + (((e0.y * cos(rad)) + (e1.y * sin(rad))) * radiusBottom);
- p.z = c.z + (((e0.z * cos(rad)) + (e1.z * sin(rad))) * radiusBottom);
- glVertex3f(p.x, p.y, p.z);
+ rlVertex3f(sin(DEG2RAD*i) * radiusTop, height, cos(DEG2RAD*i) * radiusTop); //Top Left
+ rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom); //Bottom Left
+ rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusTop, height, cos(DEG2RAD*(i+360/sides)) * radiusTop); //Top Right
}
- glEnd();
-
- // Draw cylinder bottom
- glBegin(GL_TRIANGLE_FAN);
- glColor4ub(color.r, color.g, color.b, color.a);
- glVertex3f(c.x, c.y, c.z);
- for (int i = slices; i >= 0; i--)
+
+ // Draw Cap --------------------------------------------------------------------------------------
+ for(int i = 0; i < 360; i += 360/sides)
{
- float rad = angInc * i;
- p.x = c.x + (((e0.x * cos(rad)) + (e1.x * sin(rad))) * radiusBottom);
- p.y = c.y + (((e0.y * cos(rad)) + (e1.y * sin(rad))) * radiusBottom);
- p.z = c.z + (((e0.z * cos(rad)) + (e1.z * sin(rad))) * radiusBottom);
- glVertex3f(p.x, p.y, p.z);
+ rlVertex3f(0, height, 0);
+ rlVertex3f(sin(DEG2RAD*i) * radiusTop, height, cos(DEG2RAD*i) * radiusTop);
+ rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusTop, height, cos(DEG2RAD*(i+360/sides)) * radiusTop);
}
- glEnd();
+ }
+ else
+ {
+ // Draw Cone -------------------------------------------------------------------------------------
+ for(int i = 0; i < 360; i += 360/sides)
+ {
+ rlVertex3f(0, height, 0);
+ rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom);
+ rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom);
+ }
+ }
- glPopMatrix();
- }
+ // Draw Base -----------------------------------------------------------------------------------------
+ for(int i = 0; i < 360; i += 360/sides)
+ {
+ rlVertex3f(0, 0, 0);
+ rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom);
+ rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom);
+ }
+ rlEnd();
+ rlPopMatrix();
}
-// Draw a cylinder/cone wires
-void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int slices, Color color)
+// Draw a wired cylinder
+// NOTE: It could be also used for pyramid and cone
+void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
{
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- DrawCylinder(position, radiusTop, radiusBottom, height, slices, color);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ if(sides < 3) sides = 3;
+
+ rlPushMatrix();
+ rlTranslatef(position.x, position.y, position.z);
+
+ rlBegin(RL_LINES);
+ rlColor4ub(color.r, color.g, color.b, color.a);
+
+ for(int i = 0; i < 360; i += 360/sides)
+ {
+ rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom);
+ rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom);
+
+ rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusBottom, 0, cos(DEG2RAD*(i+360/sides)) * radiusBottom);
+ rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusTop, height, cos(DEG2RAD*(i+360/sides)) * radiusTop);
+
+ rlVertex3f(sin(DEG2RAD*(i+360/sides)) * radiusTop, height, cos(DEG2RAD*(i+360/sides)) * radiusTop);
+ rlVertex3f(sin(DEG2RAD*i) * radiusTop, height, cos(DEG2RAD*i) * radiusTop);
+
+ rlVertex3f(sin(DEG2RAD*i) * radiusTop, height, cos(DEG2RAD*i) * radiusTop);
+ rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom);
+ }
+ rlEnd();
+ rlPopMatrix();
}
// Draw a plane
+// TODO: Test this function
void DrawPlane(Vector3 centerPos, Vector2 size, Vector3 rotation, Color color)
{
// NOTE: Plane is always created on XZ ground and then rotated
- glPushMatrix();
- glTranslatef(centerPos.x, centerPos.y, centerPos.z);
+ rlPushMatrix();
+ rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
// TODO: Review multiples rotations Gimbal-Lock... use matrix or quaternions...
- glRotatef(rotation.x, 1, 0, 0);
- glRotatef(rotation.y, 0, 1, 0);
- glRotatef(rotation.z, 0, 0, 1);
- glScalef(size.x, 1.0f, size.y);
-
- glBegin(GL_QUADS);
- glColor4ub(color.r, color.g, color.b, color.a);
- glNormal3f(0.0f, 1.0f, 0.0f);
- glTexCoord2f(0.0f, 0.0f); glVertex3f(-0.5f, 0.0f, -0.5f);
- glTexCoord2f(1.0f, 0.0f); glVertex3f(0.5f, 0.0f, -0.5f);
- glTexCoord2f(1.0f, 1.0f); glVertex3f(0.5f, 0.0f, 0.5f);
- glTexCoord2f(0.0f, 1.0f); glVertex3f(-0.5f, 0.0f, 0.5f);
- glEnd();
-
- glPopMatrix();
+ rlRotatef(rotation.x, 1, 0, 0);
+ rlRotatef(rotation.y, 0, 1, 0);
+ rlRotatef(rotation.z, 0, 0, 1);
+ rlScalef(size.x, 1.0f, size.y);
+
+ rlBegin(RL_QUADS);
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlNormal3f(0.0f, 1.0f, 0.0f);
+ rlTexCoord2f(0.0f, 0.0f); rlVertex3f(-0.5f, 0.0f, -0.5f);
+ rlTexCoord2f(1.0f, 0.0f); rlVertex3f(0.5f, 0.0f, -0.5f);
+ rlTexCoord2f(1.0f, 1.0f); rlVertex3f(0.5f, 0.0f, 0.5f);
+ rlTexCoord2f(0.0f, 1.0f); rlVertex3f(-0.5f, 0.0f, 0.5f);
+ rlEnd();
+ rlPopMatrix();
}
// Draw a plane with divisions
+// TODO: Test this function
void DrawPlaneEx(Vector3 centerPos, Vector2 size, Vector3 rotation, int slicesX, int slicesZ, Color color)
{
float quadWidth = size.x / slicesX;
@@ -342,129 +476,178 @@ void DrawPlaneEx(Vector3 centerPos, Vector2 size, Vector3 rotation, int slicesX,
float texPieceH = 1 / size.y;
// NOTE: Plane is always created on XZ ground and then rotated
- glPushMatrix();
- glTranslatef(-size.x / 2, 0.0f, -size.y / 2);
- glTranslatef(centerPos.x, centerPos.y, centerPos.z);
+ rlPushMatrix();
+ rlTranslatef(-size.x / 2, 0.0f, -size.y / 2);
+ rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
// TODO: Review multiples rotations Gimbal-Lock... use matrix or quaternions...
- glRotatef(rotation.x, 1, 0, 0);
- glRotatef(rotation.y, 0, 1, 0);
- glRotatef(rotation.z, 0, 0, 1);
+ rlRotatef(rotation.x, 1, 0, 0);
+ rlRotatef(rotation.y, 0, 1, 0);
+ rlRotatef(rotation.z, 0, 0, 1);
- glBegin(GL_QUADS);
- glColor4ub(color.r, color.g, color.b, color.a);
- glNormal3f(0.0f, 1.0f, 0.0f);
+ rlBegin(RL_QUADS);
+ rlColor4ub(color.r, color.g, color.b, color.a);
+ rlNormal3f(0.0f, 1.0f, 0.0f);
for (int z = 0; z < slicesZ; z++)
{
for (int x = 0; x < slicesX; x++)
{
// Draw the plane quad by quad (with textcoords)
- glTexCoord2f((float)x * texPieceW, (float)z * texPieceH);
- glVertex3f((float)x * quadWidth, 0.0f, (float)z * quadLenght);
+ rlTexCoord2f((float)x * texPieceW, (float)z * texPieceH);
+ rlVertex3f((float)x * quadWidth, 0.0f, (float)z * quadLenght);
- glTexCoord2f((float)x * texPieceW + texPieceW, (float)z * texPieceH);
- glVertex3f((float)x * quadWidth + quadWidth, 0.0f, (float)z * quadLenght);
+ rlTexCoord2f((float)x * texPieceW + texPieceW, (float)z * texPieceH);
+ rlVertex3f((float)x * quadWidth + quadWidth, 0.0f, (float)z * quadLenght);
- glTexCoord2f((float)x * texPieceW + texPieceW, (float)z * texPieceH + texPieceH);
- glVertex3f((float)x * quadWidth + quadWidth, 0.0f, (float)z * quadLenght + quadLenght);
+ rlTexCoord2f((float)x * texPieceW + texPieceW, (float)z * texPieceH + texPieceH);
+ rlVertex3f((float)x * quadWidth + quadWidth, 0.0f, (float)z * quadLenght + quadLenght);
- glTexCoord2f((float)x * texPieceW, (float)z * texPieceH + texPieceH);
- glVertex3f((float)x * quadWidth, 0.0f, (float)z * quadLenght + quadLenght);
+ rlTexCoord2f((float)x * texPieceW, (float)z * texPieceH + texPieceH);
+ rlVertex3f((float)x * quadWidth, 0.0f, (float)z * quadLenght + quadLenght);
}
}
- glEnd();
+ rlEnd();
- glPopMatrix();
+ rlPopMatrix();
}
// Draw a grid centered at (0, 0, 0)
void DrawGrid(int slices, float spacing)
{
int halfSlices = slices / 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)
- glPushMatrix();
- glScalef(spacing, 1.0f, spacing);
-
- glBegin(GL_LINES);
- for(int i = -halfSlices; i <= halfSlices; i++)
+ rlBegin(RL_LINES);
+ for(int i = -halfSlices; i <= halfSlices; i++)
+ {
+ if (i == 0)
{
- if (i == 0) glColor3f(0.5f, 0.5f, 0.5f);
- else glColor3f(0.75f, 0.75f, 0.75f);
-
- glVertex3f((float)i, 0.0f, (float)-halfSlices);
- glVertex3f((float)i, 0.0f, (float)halfSlices);
-
- glVertex3f((float)-halfSlices, 0.0f, (float)i);
- glVertex3f((float)halfSlices, 0.0f, (float)i);
+ rlColor3f(0.5f, 0.5f, 0.5f);
+ rlColor3f(0.5f, 0.5f, 0.5f);
+ rlColor3f(0.5f, 0.5f, 0.5f);
+ rlColor3f(0.5f, 0.5f, 0.5f);
}
- glEnd();
-
- glPopMatrix();
-
- //glDisable(GL_LINE_SMOOTH);
+ else
+ {
+ rlColor3f(0.75f, 0.75f, 0.75f);
+ rlColor3f(0.75f, 0.75f, 0.75f);
+ rlColor3f(0.75f, 0.75f, 0.75f);
+ rlColor3f(0.75f, 0.75f, 0.75f);
+ }
+
+ rlVertex3f((float)i*spacing, 0.0f, (float)-halfSlices*spacing);
+ rlVertex3f((float)i*spacing, 0.0f, (float)halfSlices*spacing);
+
+ rlVertex3f((float)-halfSlices*spacing, 0.0f, (float)i*spacing);
+ rlVertex3f((float)halfSlices*spacing, 0.0f, (float)i*spacing);
+ }
+ rlEnd();
}
-// Draw gizmo (with or without orbits)
-void DrawGizmo(Vector3 position, bool orbits)
+// Draw gizmo
+void DrawGizmo(Vector3 position)
{
// NOTE: RGB = XYZ
float lenght = 1.0f;
- float radius = 1.0f;
-
- //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)
-
- glPushMatrix();
- glTranslatef(position.x, position.y, position.z);
- //glRotatef(rotation, 0, 1, 0);
- glScalef(lenght, lenght, lenght);
+
+ rlPushMatrix();
+ rlTranslatef(position.x, position.y, position.z);
+ //rlRotatef(rotation, 0, 1, 0);
+ rlScalef(lenght, lenght, lenght);
- glBegin(GL_LINES);
- glColor3f(1.0f, 0.0f, 0.0f);
- glVertex3f(0.0f, 0.0f, 0.0f);
- glVertex3f(1.0f, 0.0f, 0.0f);
+ rlBegin(RL_LINES);
+ rlColor3f(1.0f, 0.0f, 0.0f); rlVertex3f(0.0f, 0.0f, 0.0f);
+ rlColor3f(1.0f, 0.0f, 0.0f); rlVertex3f(1.0f, 0.0f, 0.0f);
- glColor3f(0.0f, 1.0f, 0.0f);
- glVertex3f(0.0f, 0.0f, 0.0f);
- glVertex3f(0.0f, 1.0f, 0.0f);
+ rlColor3f(0.0f, 1.0f, 0.0f); rlVertex3f(0.0f, 0.0f, 0.0f);
+ rlColor3f(0.0f, 1.0f, 0.0f); rlVertex3f(0.0f, 1.0f, 0.0f);
- glColor3f(0.0f, 0.0f, 1.0f);
- glVertex3f(0.0f, 0.0f, 0.0f);
- glVertex3f(0.0f, 0.0f, 1.0f);
- glEnd();
-
- if (orbits)
- {
- glBegin(GL_LINE_LOOP);
- glColor4f(1.0f, 0.0f, 0.0f, 0.4f);
- for (int i=0; i < 360; i++) glVertex3f(sin(DEG2RAD*i) * radius, 0, cos(DEG2RAD*i) * radius);
- glEnd();
-
- glBegin(GL_LINE_LOOP);
- glColor4f(0.0f, 1.0f, 0.0f, 0.4f);
- for (int i=0; i < 360; i++) glVertex3f(sin(DEG2RAD*i) * radius, cos(DEG2RAD*i) * radius, 0);
- glEnd();
-
- glBegin(GL_LINE_LOOP);
- glColor4f(0.0f, 0.0f, 1.0f, 0.4f);
- for (int i=0; i < 360; i++) glVertex3f(0, sin(DEG2RAD*i) * radius, cos(DEG2RAD*i) * radius);
- glEnd();
- }
-
- glPopMatrix();
+ rlColor3f(0.0f, 0.0f, 1.0f); rlVertex3f(0.0f, 0.0f, 0.0f);
+ rlColor3f(0.0f, 0.0f, 1.0f); rlVertex3f(0.0f, 0.0f, 1.0f);
+ rlEnd();
+ rlPopMatrix();
+}
+
+void DrawGizmoEx(Vector3 position, Vector3 rot, float scale, bool orbits)
+{
+ static float rotation = 0;
+ // NOTE: RGB = XYZ
+ rlPushMatrix();
+ rlTranslatef(position.x, position.y, position.z);
+ rlRotatef(rotation, 0, 1, 0);
+ rlScalef(scale, scale, scale);
+
+ rlBegin(RL_LINES);
+ // X Axis
+ rlColor4ub(200, 0, 0, 255); rlVertex3f(position.x, position.y, position.z);
+ rlColor4ub(200, 0, 0, 255); rlVertex3f(position.x + 1, position.y, position.z);
+
+ // ArrowX
+ rlColor4ub(200, 0, 0, 255); rlVertex3f(position.x + 1.1, position.y, position.z);
+ rlColor4ub(200, 0, 0, 255); rlVertex3f(position.x + .9, position.y, position.z + .1);
+
+ rlColor4ub(200, 0, 0, 255); rlVertex3f(position.x + 1.1, position.y, position.z);
+ rlColor4ub(200, 0, 0, 255); rlVertex3f(position.x + .9, position.y, position.z - .1);
+
+ // Y Axis
+ rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x, position.y, position.z);
+ rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x, position.y + 1, position.z);
+
+ // ArrowY
+ rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x, position.y + 1.1, position.z);
+ rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x + .1, position.y + .9, position.z);
+
+ rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x, position.y + 1.1, position.z);
+ rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x - .1, position.y + .9, position.z);
+
+ // Z Axis
+ rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x, position.y, position.z);
+ rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x, position.y, position.z - 1);
+
+ // ArrowZ
+ rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x, position.y, position.z - 1.1);
+ rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x + .1, position.y, position.z - .9);
+
+ rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x, position.y, position.z - 1.1);
+ rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x - .1, position.y, position.z - .9);
+
+ // Extra
+ if(orbits)
+ {
+ int n = 3;
+
+ // X Axis
+ for (int i=0; i < 360; i += 6)
+ {
+ rlColor4ub(200, 0, 0, 255); rlVertex3f(0, position.x + sin(DEG2RAD*i) * scale/n, position.y + cos(DEG2RAD*i) * scale/n);
+ rlColor4ub(200, 0, 0, 255); rlVertex3f(0, position.x + sin(DEG2RAD*(i+6)) * scale/n, position.y + cos(DEG2RAD*(i+6)) * scale/n);
+ }
+
+ // Y Axis
+ for (int i=0; i < 360; i += 6)
+ {
+ rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x + sin(DEG2RAD*i) * scale/n, 0, position.y + cos(DEG2RAD*i) * scale/n);
+ rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x + sin(DEG2RAD*(i+6)) * scale/n, 0, position.y + cos(DEG2RAD*(i+6)) * scale/n);
+ }
+
+ // Z Axis
+ for (int i=0; i < 360; i += 6)
+ {
+ rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x + sin(DEG2RAD*i) * scale/n, position.y + cos(DEG2RAD*i) * scale/n, 0);
+ rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x + sin(DEG2RAD*(i+6)) * scale/n, position.y + cos(DEG2RAD*(i+6)) * scale/n, 0);
+ }
+ }
+ rlEnd();
+ rlPopMatrix();
- //glDisable(GL_LINE_SMOOTH);
+ rotation += 0.1f;
}
// Load a 3d model (.OBJ)
// TODO: Add comments explaining this function process
Model LoadModel(const char *fileName)
{
- Model model;
+ VertexData vData;
char dataType;
char comments[200];
@@ -507,7 +690,6 @@ Model LoadModel(const char *fileName)
{
fscanf(objFile, "%i", &numTexCoords);
}
- else printf("Ouch! Something was wrong...");
fgets(comments, 200, objFile);
}
@@ -526,7 +708,6 @@ Model LoadModel(const char *fileName)
{
fscanf(objFile, "%i", &numNormals);
}
- else printf("Ouch! Something was wrong...");
fgets(comments, 200, objFile);
}
@@ -545,7 +726,6 @@ Model LoadModel(const char *fileName)
{
fscanf(objFile, "%i", &numVertex);
}
- else printf("Ouch! Something was wrong...");
fgets(comments, 200, objFile);
}
@@ -565,7 +745,6 @@ Model LoadModel(const char *fileName)
{
fscanf(objFile, "%i", &numTriangles);
}
- else printf("Ouch! Something was wrong...");
fgets(comments, 200, objFile);
@@ -578,17 +757,19 @@ Model LoadModel(const char *fileName)
Vector3 midNormals[numNormals];
Vector2 midTexCoords[numTexCoords];
- model.numVertices = numTriangles*3;
-
- model.vertices = (Vector3 *)malloc(model.numVertices * sizeof(Vector3));
- model.normals = (Vector3 *)malloc(model.numVertices * sizeof(Vector3));
- model.texcoords = (Vector2 *)malloc(model.numVertices * sizeof(Vector2));
+ vData.numVertices = numTriangles*3;
+
+ vData.vertices = (float *)malloc(vData.numVertices * 3 * sizeof(float));
+ vData.texcoords = (float *)malloc(vData.numVertices * 2 * sizeof(float));
+ vData.normals = (float *)malloc(vData.numVertices * 3 * sizeof(float));
int countVertex = 0;
int countNormals = 0;
int countTexCoords = 0;
- int countMaxVertex = 0;
+ int vCounter = 0; // Used to count vertices float by float
+ int tcCounter = 0; // Used to count texcoords float by float
+ int nCounter = 0; // Used to count normals float by float
rewind(objFile);
@@ -632,31 +813,58 @@ Model LoadModel(const char *fileName)
} break;
case 'f':
{
+ // At this point all vertex data (v, vt, vn) have been gathered on midVertices, midTexCoords, midNormals
+ // Now we can organize that data into our VertexData struct
+
int vNum, vtNum, vnNum;
fscanf(objFile, "%c", &dataType);
fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
- model.vertices[countMaxVertex] = midVertices[vNum-1];
- model.normals[countMaxVertex] = midNormals[vnNum-1];
- model.texcoords[countMaxVertex].x = midTexCoords[vtNum-1].x;
- model.texcoords[countMaxVertex].y = -midTexCoords[vtNum-1].y;
- countMaxVertex++;
-
+ vData.vertices[vCounter] = midVertices[vNum-1].x;
+ vData.vertices[vCounter + 1] = midVertices[vNum-1].y;
+ vData.vertices[vCounter + 2] = midVertices[vNum-1].z;
+ vCounter += 3;
+
+ vData.normals[nCounter] = midNormals[vnNum-1].x;
+ vData.normals[nCounter + 1] = midNormals[vnNum-1].y;
+ vData.normals[nCounter + 2] = midNormals[vnNum-1].z;
+ nCounter += 3;
+
+ vData.texcoords[tcCounter] = midTexCoords[vtNum-1].x;
+ vData.texcoords[tcCounter + 1] = -midTexCoords[vtNum-1].y;
+ tcCounter += 2;
+
fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
- model.vertices[countMaxVertex] = midVertices[vNum-1];
- model.normals[countMaxVertex] = midNormals[vnNum-1];
- model.texcoords[countMaxVertex].x = midTexCoords[vtNum-1].x;
- model.texcoords[countMaxVertex].y = -midTexCoords[vtNum-1].y;
- countMaxVertex++;
+ vData.vertices[vCounter] = midVertices[vNum-1].x;
+ vData.vertices[vCounter + 1] = midVertices[vNum-1].y;
+ vData.vertices[vCounter + 2] = midVertices[vNum-1].z;
+ vCounter += 3;
+
+ vData.normals[nCounter] = midNormals[vnNum-1].x;
+ vData.normals[nCounter + 1] = midNormals[vnNum-1].y;
+ vData.normals[nCounter + 2] = midNormals[vnNum-1].z;
+ nCounter += 3;
+
+ vData.texcoords[tcCounter] = midTexCoords[vtNum-1].x;
+ vData.texcoords[tcCounter + 1] = -midTexCoords[vtNum-1].y;
+ tcCounter += 2;
fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
- model.vertices[countMaxVertex] = midVertices[vNum-1];
- model.normals[countMaxVertex] = midNormals[vnNum-1];
- model.texcoords[countMaxVertex].x = midTexCoords[vtNum-1].x;
- model.texcoords[countMaxVertex].y = -midTexCoords[vtNum-1].y;
- countMaxVertex++;
+ vData.vertices[vCounter] = midVertices[vNum-1].x;
+ vData.vertices[vCounter + 1] = midVertices[vNum-1].y;
+ vData.vertices[vCounter + 2] = midVertices[vNum-1].z;
+ vCounter += 3;
+
+ vData.normals[nCounter] = midNormals[vnNum-1].x;
+ vData.normals[nCounter + 1] = midNormals[vnNum-1].y;
+ vData.normals[nCounter + 2] = midNormals[vnNum-1].z;
+ nCounter += 3;
+
+ vData.texcoords[tcCounter] = midTexCoords[vtNum-1].x;
+ vData.texcoords[tcCounter + 1] = -midTexCoords[vtNum-1].y;
+ tcCounter += 2;
} break;
default: break;
}
@@ -664,14 +872,29 @@ Model LoadModel(const char *fileName)
fclose(objFile);
+ // NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct
+
+ Model model;
+
+#ifdef USE_OPENGL_11
+ model.data = vData; // model data is vertex data
+#else
+ model.vaoId = rlglLoadModel(vData); // Use loaded data to generate VAO
+
+ // Now that vertex data is uploaded to GPU, we can free arrays
+ free(vData.vertices);
+ free(vData.texcoords);
+ free(vData.normals);
+#endif
+
return model;
}
// Load a heightmap image as a 3d model
Model LoadHeightmap(Image heightmap, float maxHeight)
{
- Model model;
-
+ VertexData vData;
+
int mapX = heightmap.width;
int mapZ = heightmap.height;
@@ -679,13 +902,16 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
// TODO: Consider resolution when generating model data?
int numTriangles = (mapX-1)*(mapZ-1)*2; // One quad every four pixels
- model.numVertices = numTriangles*3;
+ vData.numVertices = numTriangles*3;
- model.vertices = (Vector3 *)malloc(model.numVertices * sizeof(Vector3));
- model.normals = (Vector3 *)malloc(model.numVertices * sizeof(Vector3));
- model.texcoords = (Vector2 *)malloc(model.numVertices * sizeof(Vector2));
+ vData.vertices = (float *)malloc(vData.numVertices * 3 * sizeof(float));
+ vData.normals = (float *)malloc(vData.numVertices * 3 * sizeof(float));
+ vData.texcoords = (float *)malloc(vData.numVertices * 2 * sizeof(float));
+
+ int vCounter = 0; // Used to count vertices float by float
+ int tcCounter = 0; // Used to count texcoords float by float
+ int nCounter = 0; // Used to count normals float by float
- int vCounter = 0;
int trisCounter = 0;
float scaleFactor = maxHeight/255; // TODO: Review scaleFactor calculation
@@ -698,57 +924,83 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
//----------------------------------------------------------
// one triangle - 3 vertex
- model.vertices[vCounter].x = x;
- model.vertices[vCounter].y = GetHeightValue(heightmap.pixels[x + z*mapX])*scaleFactor;
- model.vertices[vCounter].z = z;
+ vData.vertices[vCounter] = x;
+ vData.vertices[vCounter + 1] = GetHeightValue(heightmap.pixels[x + z*mapX])*scaleFactor;
+ vData.vertices[vCounter + 2] = z;
- model.vertices[vCounter+1].x = x;
- model.vertices[vCounter+1].y = GetHeightValue(heightmap.pixels[x + (z+1)*mapX])*scaleFactor;
- model.vertices[vCounter+1].z = z+1;
+ vData.vertices[vCounter + 3] = x;
+ vData.vertices[vCounter + 4] = GetHeightValue(heightmap.pixels[x + (z+1)*mapX])*scaleFactor;
+ vData.vertices[vCounter + 5] = z+1;
- model.vertices[vCounter+2].x = x+1;
- model.vertices[vCounter+2].y = GetHeightValue(heightmap.pixels[(x+1) + z*mapX])*scaleFactor;
- model.vertices[vCounter+2].z = z;
+ vData.vertices[vCounter + 6] = x+1;
+ vData.vertices[vCounter + 7] = GetHeightValue(heightmap.pixels[(x+1) + z*mapX])*scaleFactor;
+ vData.vertices[vCounter + 8] = z;
// another triangle - 3 vertex
- model.vertices[vCounter+3] = model.vertices[vCounter+2];
- model.vertices[vCounter+4] = model.vertices[vCounter+1];
+ vData.vertices[vCounter + 9] = vData.vertices[vCounter + 6];
+ vData.vertices[vCounter + 10] = vData.vertices[vCounter + 7];
+ vData.vertices[vCounter + 11] = vData.vertices[vCounter + 8];
- model.vertices[vCounter+5].x = x+1;
- model.vertices[vCounter+5].y = GetHeightValue(heightmap.pixels[(x+1) + (z+1)*mapX])*scaleFactor;
- model.vertices[vCounter+5].z = z+1;
+ vData.vertices[vCounter + 12] = vData.vertices[vCounter + 3];
+ vData.vertices[vCounter + 13] = vData.vertices[vCounter + 4];
+ vData.vertices[vCounter + 14] = vData.vertices[vCounter + 5];
+
+ vData.vertices[vCounter + 15] = x+1;
+ vData.vertices[vCounter + 16] = GetHeightValue(heightmap.pixels[(x+1) + (z+1)*mapX])*scaleFactor;
+ vData.vertices[vCounter + 17] = z+1;
+ vCounter += 18; // 6 vertex, 18 floats
// Fill texcoords array with data
//--------------------------------------------------------------
- model.texcoords[vCounter].x = (float)x / (mapX-1);
- model.texcoords[vCounter].y = (float)z / (mapZ-1);
+ vData.texcoords[tcCounter] = (float)x / (mapX-1);
+ vData.texcoords[tcCounter + 1] = (float)z / (mapZ-1);
+
+ vData.texcoords[tcCounter + 2] = (float)x / (mapX-1);
+ vData.texcoords[tcCounter + 3] = (float)(z+1) / (mapZ-1);
- model.texcoords[vCounter+1].x = (float)x / (mapX-1);
- model.texcoords[vCounter+1].y = (float)(z+1) / (mapZ-1);
+ vData.texcoords[tcCounter + 4] = (float)(x+1) / (mapX-1);
+ vData.texcoords[tcCounter + 5] = (float)z / (mapZ-1);
- model.texcoords[vCounter+2].x = (float)(x+1) / (mapX-1);
- model.texcoords[vCounter+2].y = (float)z / (mapZ-1);
+ vData.texcoords[tcCounter + 6] = vData.texcoords[tcCounter + 4];
+ vData.texcoords[tcCounter + 7] = vData.texcoords[tcCounter + 5];
- model.texcoords[vCounter+3] = model.texcoords[vCounter+2];
- model.texcoords[vCounter+4] = model.texcoords[vCounter+1];
+ vData.texcoords[tcCounter + 8] = vData.texcoords[tcCounter + 2];
+ vData.texcoords[tcCounter + 9] = vData.texcoords[tcCounter + 1];
- model.texcoords[vCounter+5].x = (float)(x+1) / (mapX-1);
- model.texcoords[vCounter+5].y = (float)(z+1) / (mapZ-1);
+ vData.texcoords[tcCounter + 10] = (float)(x+1) / (mapX-1);
+ vData.texcoords[tcCounter + 11] = (float)(z+1) / (mapZ-1);
+ tcCounter += 12; // 6 texcoords, 12 floats
// Fill normals array with data
//--------------------------------------------------------------
// TODO: Review normals calculation
- model.normals[vCounter] = (Vector3){ 0.0f, 1.0f, 0.0f };
- model.normals[vCounter+1] = (Vector3){ 0.0f, 1.0f, 0.0f };
- model.normals[vCounter+2] = (Vector3){ 0.0f, 1.0f, 0.0f };
- model.normals[vCounter+3] = (Vector3){ 0.0f, 1.0f, 0.0f };
- model.normals[vCounter+4] = (Vector3){ 0.0f, 1.0f, 0.0f };
- model.normals[vCounter+5] = (Vector3){ 0.0f, 1.0f, 0.0f };
-
- vCounter += 6;
+ for (int i = 0; i < 18; i += 3)
+ {
+ vData.normals[nCounter + i] = 0.0f;
+ vData.normals[nCounter + i + 1] = 1.0f;
+ vData.normals[nCounter + i + 2] = 0.0f;
+ }
+
+ nCounter += 18; // 6 vertex, 18 floats
+
trisCounter += 2;
}
}
+
+ // NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct
+
+ Model model;
+
+#ifdef USE_OPENGL_11
+ model.data = vData; // model data is vertex data
+#else
+ model.vaoId = rlglLoadModel(vData); // Use loaded data to generate VAO
+
+ // Now that vertex data is uploaded to GPU, we can free arrays
+ free(vData.vertices);
+ free(vData.texcoords);
+ free(vData.normals);
+#endif
return model;
}
@@ -756,61 +1008,37 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
// Unload 3d model from memory
void UnloadModel(Model model)
{
- free(model.vertices);
- free(model.texcoords);
- free(model.normals);
+#ifdef USE_OPENGL_11
+ free(model.data.vertices);
+ free(model.data.texcoords);
+ free(model.data.normals);
+#endif
+
+#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+ rlDeleteVertexArrays(model.vaoId);
+#endif
}
// Draw a model
void DrawModel(Model model, Vector3 position, float scale, Color color)
{
- // NOTE: For models we use Vertex Arrays (OpenGL 1.1)
- //static int rotation = 0;
-
- glEnableClientState(GL_VERTEX_ARRAY); // Enable vertex array
- glEnableClientState(GL_TEXTURE_COORD_ARRAY); // Enable texture coords array
- glEnableClientState(GL_NORMAL_ARRAY); // Enable normals array
-
- glVertexPointer(3, GL_FLOAT, 0, model.vertices); // Pointer to vertex coords array
- glTexCoordPointer(2, GL_FLOAT, 0, model.texcoords); // Pointer to texture coords array
- glNormalPointer(GL_FLOAT, 0, model.normals); // Pointer to normals array
- //glColorPointer(4, GL_UNSIGNED_BYTE, 0, model.colors); // Pointer to colors array (NOT USED)
-
- glPushMatrix();
- glTranslatef(position.x, position.y, position.z);
- //glRotatef(rotation * GetFrameTime(), 0, 1, 0);
- glScalef(scale, scale, scale);
-
- glColor4ub(color.r, color.g, color.b, color.a);
-
- glDrawArrays(GL_TRIANGLES, 0, model.numVertices);
- glPopMatrix();
-
- glDisableClientState(GL_VERTEX_ARRAY); // Disable vertex array
- glDisableClientState(GL_TEXTURE_COORD_ARRAY); // Disable texture coords array
- glDisableClientState(GL_NORMAL_ARRAY); // Disable normals array
-
- //rotation += 10;
+ rlglDrawModel(model, position, scale, false);
}
// Draw a textured model
void DrawModelEx(Model model, Texture2D texture, Vector3 position, float scale, Color tint)
{
- glEnable(GL_TEXTURE_2D);
-
- glBindTexture(GL_TEXTURE_2D, texture.glId);
+ rlEnableTexture(texture.glId);
DrawModel(model, position, scale, tint);
- glDisable(GL_TEXTURE_2D);
+ rlDisableTexture();
}
// Draw a model wires
void DrawModelWires(Model model, Vector3 position, float scale, Color color)
{
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- DrawModel(model, position, scale, color);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ rlglDrawModel(model, position, scale, true);
}
// Draw a billboard
@@ -842,20 +1070,18 @@ void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size,
Vector3 c = VectorAdd(center, p2);
Vector3 d = VectorSubtract(center, p1);
- glEnable(GL_TEXTURE_2D);
-
- glBindTexture(GL_TEXTURE_2D, texture.glId);
+ rlEnableTexture(texture.glId);
- glBegin(GL_QUADS);
- glColor4ub(tint.r, tint.g, tint.b, tint.a);
- glNormal3f(0.0f, 1.0f, 0.0f);
- glTexCoord2f(0.0f, 0.0f); glVertex3f(a.x, a.y, a.z);
- glTexCoord2f(1.0f, 0.0f); glVertex3f(b.x, b.y, b.z);
- glTexCoord2f(1.0f, 1.0f); glVertex3f(c.x, c.y, c.z);
- glTexCoord2f(0.0f, 1.0f); glVertex3f(d.x, d.y, d.z);
- glEnd();
-
- glDisable(GL_TEXTURE_2D);
+ rlBegin(RL_QUADS);
+ rlColor4ub(tint.r, tint.g, tint.b, tint.a);
+ rlNormal3f(0.0f, 1.0f, 0.0f);
+ rlTexCoord2f(0.0f, 0.0f); rlVertex3f(a.x, a.y, a.z);
+ rlTexCoord2f(1.0f, 0.0f); rlVertex3f(b.x, b.y, b.z);
+ rlTexCoord2f(1.0f, 1.0f); rlVertex3f(c.x, c.y, c.z);
+ rlTexCoord2f(0.0f, 1.0f); rlVertex3f(d.x, d.y, d.z);
+ rlEnd();
+
+ rlDisableTexture();
}
// Draw a billboard (part of a texture defined by a rectangle)
@@ -887,92 +1113,33 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vec
Vector3 c = VectorAdd(center, p2);
Vector3 d = VectorSubtract(center, p1);
- glEnable(GL_TEXTURE_2D); // Enable textures usage
-
- glBindTexture(GL_TEXTURE_2D, texture.glId);
+ rlEnableTexture(texture.glId);
- glBegin(GL_QUADS);
- glColor4ub(tint.r, tint.g, tint.b, tint.a);
+ rlBegin(RL_QUADS);
+ rlColor4ub(tint.r, tint.g, tint.b, tint.a);
// Bottom-left corner for texture and quad
- glTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height);
- glVertex3f(a.x, a.y, a.z);
+ rlTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height);
+ rlVertex3f(a.x, a.y, a.z);
// Bottom-right corner for texture and quad
- glTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height);
- glVertex3f(b.x, b.y, b.z);
+ rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height);
+ rlVertex3f(b.x, b.y, b.z);
// Top-right corner for texture and quad
- glTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
- glVertex3f(c.x, c.y, c.z);
+ rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
+ rlVertex3f(c.x, c.y, c.z);
// Top-left corner for texture and quad
- glTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
- glVertex3f(d.x, d.y, d.z);
- glEnd();
+ rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
+ rlVertex3f(d.x, d.y, d.z);
+ rlEnd();
- glDisable(GL_TEXTURE_2D); // Disable textures usage
+ rlDisableTexture();
}
// Get current vertex y altitude (proportional to pixel colors in grayscale)
static float GetHeightValue(Color pixel)
{
return (((float)pixel.r + (float)pixel.g + (float)pixel.b)/3);
-}
-
-// Returns camera look-at matrix (view matrix)
-static Matrix MatrixLookAt(Vector3 eye, Vector3 target, Vector3 up)
-{
- Matrix result;
-
- Vector3 z = VectorSubtract(eye, target);
- VectorNormalize(&z);
- Vector3 x = VectorCrossProduct(up, z);
- VectorNormalize(&x);
- Vector3 y = VectorCrossProduct(z, x);
- VectorNormalize(&y);
-
- result.m0 = x.x;
- result.m1 = x.y;
- result.m2 = x.z;
- result.m3 = -((x.x * eye.x) + (x.y * eye.y) + (x.z * eye.z));
- result.m4 = y.x;
- result.m5 = y.y;
- result.m6 = y.z;
- result.m7 = -((y.x * eye.x) + (y.y * eye.y) + (y.z * eye.z));
- result.m8 = z.x;
- result.m9 = z.y;
- result.m10 = z.z;
- result.m11 = -((z.x * eye.x) + (z.y * eye.y) + (z.z * eye.z));
- result.m12 = 0;
- result.m13 = 0;
- result.m14 = 0;
- result.m15 = 1;
-
- return result;
-}
-
-// Transposes provided matrix
-static 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;
-
- *mat = temp;
} \ No newline at end of file
diff --git a/src/raylib.h b/src/raylib.h
index fd66819c..237f635d 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -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,50 +200,49 @@ typedef struct Texture2D {
int height;
} Texture2D;
-// SpriteFont one Character (Glyph) data, defined in text module
+// Camera type, defines a camera position/orientation in 3d space
+typedef struct Camera {
+ Vector3 position;
+ Vector3 target;
+ Vector3 up;
+} Camera;
+
typedef struct Character Character;
-// SpriteFont type, includes texture and charSet array data
+// SpriteFont type
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;
- Vector3 target;
- Vector3 up;
-} Camera;
+// 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
-// Basic 3d Model type
-typedef struct Model {
- int numVertices;
- Vector3 *vertices;
- Vector2 *texcoords;
- Vector3 *normals;
-} Model;
-
-// Basic Sound source and buffer
+// 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
}
diff --git a/src/raymath.c b/src/raymath.c
index 3546113c..fa4bac90 100644
--- a/src/raymath.c
+++ b/src/raymath.c
@@ -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;
-
- 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;
+ 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;
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;
-
- // 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 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;
+
+ // 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;
+ 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;
+ result.m13 = mat.m13;
+ result.m14 = mat.m14;
+ result.m15 = mat.m15;
- return result;
+ 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);
-
- 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;
+ 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;
- 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 x2 = x + x;
- float y2 = y + y;
- float z2 = z + z;
-
- 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 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;
+ 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 xx = x*x2;
+ float xy = x*y2;
+ float xz = x*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;
+
+ 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
diff --git a/src/raymath.h b/src/raymath.h
index 49cceafb..69a6a582 100644
--- a/src/raymath.h
+++ b/src/raymath.h
@@ -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
diff --git a/src/rlgl.c b/src/rlgl.c
new file mode 100644
index 00000000..8a758a22
--- /dev/null
+++ b/src/rlgl.c
@@ -0,0 +1,1572 @@
+/*********************************************************************************************
+*
+* 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+
+*
+* 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.
+*
+**********************************************************************************************/
+
+#include "rlgl.h"
+
+#include <stdio.h> // Standard input / output lib
+#include <stdlib.h> // Declares malloc() and free() for memory management, rand()
+
+// TODO: Security check in case multiple USE_OPENGL_* defined
+
+#ifdef USE_OPENGL_11
+ #include <GL/gl.h> // Extensions loading lib
+#endif
+
+#ifdef USE_OPENGL_33
+ #define GLEW_STATIC
+ #include <GL/glew.h> // Extensions loading lib
+#endif
+
+//#include "glad.h" // Extensions loading lib? --> REVIEW
+
+#define USE_VBO_DOUBLE_BUFFERS // Enable VBO double buffers usage --> REVIEW!
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+#define MATRIX_STACK_SIZE 16 // Matrix stack max size
+#define MAX_DRAWS_BY_TEXTURE 256 // Draws are organized by texture changes
+#define TEMP_VERTEX_BUFFER_SIZE 4096 // Temporal Vertex Buffer (required for vertex-transformations)
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef struct {
+ int numQuads;
+ int texId;
+} QuadsByTexture;
+
+typedef struct {
+ int vCounter;
+ int cCounter;
+ float *vertices; // 3 components per vertex
+ float *colors; // 4 components per vertex
+} VertexPositionColorBuffer;
+/*
+typedef struct {
+ int vCounter;
+ int tcCounter;
+ int cCounter;
+ float *vertices; // 3 components per vertex
+ float *texcoords; // 2 components per vertex
+ float *colors; // 4 components per vertex
+} VertexPositionColorTextureBuffer;
+*/
+/*
+typedef struct {
+ int vCounter;
+ int tcCounter;
+ int nCounter;
+ float *vertices; // 3 components per vertex
+ float *texcoords; // 2 components per vertex
+ float *normals; // 3 components per vertex
+} VertexPositionTextureNormalBuffer;
+*/
+typedef struct {
+ int vCounter;
+ int tcCounter;
+ int cCounter;
+ float *vertices; // 3 components per vertex
+ float *texcoords; // 2 components per vertex
+ float *colors; // 4 components per vertex
+ unsigned int *indices; // 6 indices per quad
+} VertexPositionColorTextureIndexBuffer;
+
+typedef struct {
+ GLuint texId;
+ int firstVertex; // Actually, when using glDrawElements, this parameter is useless..
+ int vCount;
+} DrawCall;
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+static Matrix stack[MATRIX_STACK_SIZE];
+static int stackCounter = 0;
+
+static Matrix modelview;
+static Matrix projection;
+static Matrix *currentMatrix;
+static int currentMatrixMode;
+
+static DrawMode currentDrawMode;
+
+// Vertex arrays for lines, triangles and quads
+static VertexPositionColorBuffer lines; // No texture support
+static VertexPositionColorBuffer triangles; // No texture support
+static VertexPositionColorTextureIndexBuffer quads;
+
+// Vetex-Fragment Shader Program ID
+static GLuint shaderProgram;
+
+// Shader program attibutes binding locations
+static GLuint vertexLoc, texcoordLoc, colorLoc;
+static GLuint projectionMatrixLoc, modelviewMatrixLoc;
+static GLuint textureLoc;
+
+// Vertex Array Objects (VAO)
+static GLuint vaoLines, vaoTriangles, vaoQuads;
+
+// Vertex Buffer Objects (VBO)
+static GLuint linesBuffer[2];
+static GLuint trianglesBuffer[2];
+static GLuint quadsBuffer[4];
+
+#ifdef USE_VBO_DOUBLE_BUFFERS
+// Double buffering
+// TODO: REVIEW -> Not getting any performance improvement... why?
+static GLuint vaoQuadsB;
+static GLuint quadsBufferB[4];
+static bool useBufferB = false;
+#endif
+
+static DrawCall *draws;
+static int drawsCounter;
+
+// Temp vertex buffer to be used with rlTranslate, rlRotate, rlScale
+static Vector3 *tempBuffer;
+static int tempBufferCount = 0;
+static bool useTempBuffer = false;
+
+// White texture useful for plain color polys (required by shader)
+static GLuint whiteTexture;
+#endif
+
+//----------------------------------------------------------------------------------
+// Module specific Functions Declaration
+//----------------------------------------------------------------------------------
+#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+static GLuint LoadDefaultShaders();
+static void InitializeBuffers();
+static void InitializeVAOs();
+static void UpdateBuffers();
+
+// Shader files loading (external) - Not used but useful...
+static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName);
+static char *TextFileRead(char *fn);
+#endif
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition - Matrix operations
+//----------------------------------------------------------------------------------
+
+#ifdef USE_OPENGL_11
+
+// Fallback to OpenGL 1.1 function calls
+//---------------------------------------
+void rlMatrixMode(int mode)
+{
+ switch (mode)
+ {
+ case RL_PROJECTION: glMatrixMode(GL_PROJECTION); break;
+ case RL_MODELVIEW: glMatrixMode(GL_MODELVIEW); break;
+ case RL_TEXTURE: glMatrixMode(GL_TEXTURE); break;
+ default: break;
+ }
+}
+
+void rlFrustum(double left, double right, double bottom, double top, double near, double far)
+{
+ glFrustum(left, right, bottom, top, near, far);
+}
+
+void rlOrtho(double left, double right, double bottom, double top, double near, double far)
+{
+ glOrtho(left, right, bottom, top, near, far);
+}
+
+void rlPushMatrix() { glPushMatrix(); }
+void rlPopMatrix() { glPopMatrix(); }
+void rlLoadIdentity() { glLoadIdentity(); }
+void rlTranslatef(float x, float y, float z) { glTranslatef(x, y, z); }
+void rlRotatef(float angleDeg, float x, float y, float z) { glRotatef(angleDeg, x, y, z); }
+void rlScalef(float x, float y, float z) { glScalef(x, y, z); }
+void rlMultMatrixf(float *mat) { glMultMatrixf(mat); }
+
+#else
+
+// Choose the current matrix to be transformed
+void rlMatrixMode(int mode)
+{
+ if (mode == RL_PROJECTION) currentMatrix = &projection;
+ else if (mode == RL_MODELVIEW) currentMatrix = &modelview;
+ //else if (mode == GL_TEXTURE) TODO: NEVER USED!
+
+ currentMatrixMode = mode;
+}
+
+// Push the current matrix to stack
+void rlPushMatrix()
+{
+ if (stackCounter == MATRIX_STACK_SIZE - 1)
+ {
+ TraceLog(ERROR, "Stack Buffer Overflow (MAX %i Matrix)", MATRIX_STACK_SIZE);
+ }
+
+ stack[stackCounter] = *currentMatrix;
+ rlLoadIdentity();
+ stackCounter++;
+
+ if (currentMatrixMode == RL_MODELVIEW) useTempBuffer = true;
+}
+
+// Pop lattest inserted matrix from stack
+void rlPopMatrix()
+{
+ if (stackCounter > 0)
+ {
+ Matrix mat = stack[stackCounter - 1];
+ *currentMatrix = mat;
+ stackCounter--;
+ }
+}
+
+// Reset current matrix to identity matrix
+void rlLoadIdentity()
+{
+ *currentMatrix = MatrixIdentity();
+}
+
+// Multiply the current matrix by a translation matrix
+void rlTranslatef(float x, float y, float z)
+{
+ Matrix mat = MatrixTranslate(x, y, z);
+
+ *currentMatrix = MatrixMultiply(*currentMatrix, mat);
+}
+
+// Multiply the current matrix by a rotation matrix
+void rlRotatef(float angleDeg, float x, float y, float z)
+{
+ // TODO: Rotation matrix --> REVIEW!
+ Matrix rot = MatrixIdentity();
+
+ if (x == 1) rot = MatrixRotateX(angleDeg*DEG2RAD);
+ else if (y == 1) rot = MatrixRotateY(angleDeg*DEG2RAD);
+ else if (z == 1) rot = MatrixRotateZ(angleDeg*DEG2RAD);
+
+ *currentMatrix = MatrixMultiply(*currentMatrix, rot);
+}
+
+// Multiply the current matrix by a scaling matrix
+void rlScalef(float x, float y, float z)
+{
+ Matrix mat = MatrixScale(x, y, z);
+
+ *currentMatrix = MatrixMultiply(*currentMatrix, mat);
+}
+
+// Multiply the current matrix by another matrix
+void rlMultMatrixf(float *m)
+{
+ // TODO: review Matrix creation from array
+ Matrix mat = { m[0], m[1], m[2], m[3],
+ m[4], m[5], m[6], m[7],
+ m[8], m[9], m[10], m[11],
+ m[12], m[13], m[14], m[15] };
+
+ *currentMatrix = MatrixMultiply(*currentMatrix, mat);
+}
+
+// Multiply the current matrix by a perspective matrix generated by parameters
+void rlFrustum(double left, double right, double bottom, double top, double near, double far)
+{
+ Matrix matPerps = MatrixFrustum(left, right, bottom, top, near, far);
+ MatrixTranspose(&matPerps);
+
+ *currentMatrix = MatrixMultiply(*currentMatrix, matPerps);
+}
+
+// Multiply the current matrix by an orthographic matrix generated by parameters
+void rlOrtho(double left, double right, double bottom, double top, double near, double far)
+{
+ Matrix matOrtho = MatrixOrtho(left, right, bottom, top, near, far);
+ MatrixTranspose(&matOrtho);
+
+ *currentMatrix = MatrixMultiply(*currentMatrix, matOrtho);
+}
+
+#endif
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition - Vertex level operations
+//----------------------------------------------------------------------------------
+#ifdef USE_OPENGL_11
+
+// Fallback to OpenGL 1.1 function calls
+//---------------------------------------
+void rlBegin(int mode)
+{
+ switch (mode)
+ {
+ case RL_LINES: glBegin(GL_LINES); break;
+ case RL_TRIANGLES: glBegin(GL_TRIANGLES); break;
+ case RL_QUADS: glBegin(GL_QUADS); break;
+ default: break;
+ }
+}
+
+void rlEnd() { glEnd(); }
+void rlVertex2i(int x, int y) { glVertex2i(x, y); }
+void rlVertex2f(float x, float y) { glVertex2f(x, y); }
+void rlVertex3f(float x, float y, float z) { glVertex3f(x, y, z); }
+void rlTexCoord2f(float x, float y) { glTexCoord2f(x, y); }
+void rlNormal3f(float x, float y, float z) { glNormal3f(x, y, z); }
+void rlColor4ub(byte r, byte g, byte b, byte a) { glColor4ub(r, g, b, a); }
+void rlColor3f(float x, float y, float z) { glColor3f(x, y, z); }
+void rlColor4f(float x, float y, float z, float w) { glColor4f(x, y, z, w); }
+
+#else
+
+// Initialize drawing mode (how to organize vertex)
+void rlBegin(int mode)
+{
+ // Draw mode can only be RL_LINES, RL_TRIANGLES and RL_QUADS
+ currentDrawMode = mode;
+}
+
+// Finish vertex providing
+void rlEnd()
+{
+ if (useTempBuffer)
+ {
+ // IT WORKS!!! --> Refactor...
+ Matrix mat = *currentMatrix;
+ MatrixTranspose(&mat);
+
+ // Apply transformation matrix to all temp vertices
+ for (int i = 0; i < tempBufferCount; i++) VectorTransform(&tempBuffer[i], mat);
+
+ // Deactivate tempBuffer usage to allow rlVertex3f do its job
+ useTempBuffer = false;
+
+ // Copy all transformed vertices to right VAO
+ for (int i = 0; i < tempBufferCount; i++) rlVertex3f(tempBuffer[i].x, tempBuffer[i].y, tempBuffer[i].z);
+
+ // Reset temp buffer
+ tempBufferCount = 0;
+ }
+
+ // Make sure vertexCounter is the same for vertices-texcoords-normals-colors
+ // NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls.
+ switch (currentDrawMode)
+ {
+ case RL_LINES:
+ {
+ if (lines.vCounter != lines.cCounter)
+ {
+ int addColors = lines.vCounter - lines.cCounter;
+
+ for (int i = 0; i < addColors; i++)
+ {
+ lines.colors[4*lines.cCounter] = lines.colors[4*lines.cCounter - 4];
+ lines.colors[4*lines.cCounter + 1] = lines.colors[4*lines.cCounter - 3];
+ lines.colors[4*lines.cCounter + 2] = lines.colors[4*lines.cCounter - 2];
+ lines.colors[4*lines.cCounter + 3] = lines.colors[4*lines.cCounter - 1];
+
+ lines.cCounter++;
+ }
+ }
+ } break;
+ case RL_TRIANGLES:
+ {
+ if (triangles.vCounter != triangles.cCounter)
+ {
+ int addColors = triangles.vCounter - triangles.cCounter;
+
+ for (int i = 0; i < addColors; i++)
+ {
+ triangles.colors[4*triangles.cCounter] = triangles.colors[4*triangles.cCounter - 4];
+ triangles.colors[4*triangles.cCounter + 1] = triangles.colors[4*triangles.cCounter - 3];
+ triangles.colors[4*triangles.cCounter + 2] = triangles.colors[4*triangles.cCounter - 2];
+ triangles.colors[4*triangles.cCounter + 3] = triangles.colors[4*triangles.cCounter - 1];
+
+ triangles.cCounter++;
+ }
+ }
+ } break;
+ case RL_QUADS:
+ {
+ // Make sure colors count match vertex count
+ if (quads.vCounter != quads.cCounter)
+ {
+ int addColors = quads.vCounter - quads.cCounter;
+
+ for (int i = 0; i < addColors; i++)
+ {
+ quads.colors[4*quads.cCounter] = quads.colors[4*quads.cCounter - 4];
+ quads.colors[4*quads.cCounter + 1] = quads.colors[4*quads.cCounter - 3];
+ quads.colors[4*quads.cCounter + 2] = quads.colors[4*quads.cCounter - 2];
+ quads.colors[4*quads.cCounter + 3] = quads.colors[4*quads.cCounter - 1];
+
+ quads.cCounter++;
+ }
+ }
+
+ // Make sure texcoords count match vertex count
+ if (quads.vCounter != quads.tcCounter)
+ {
+ int addTexCoords = quads.vCounter - quads.tcCounter;
+
+ for (int i = 0; i < addTexCoords; i++)
+ {
+ quads.texcoords[2*quads.tcCounter] = 0.0f;
+ quads.texcoords[2*quads.tcCounter + 1] = 0.0f;
+
+ quads.tcCounter++;
+ }
+ }
+
+ // TODO: Make sure normals count match vertex count
+
+ } break;
+ default: break;
+ }
+}
+
+// Define one vertex (position)
+void rlVertex3f(float x, float y, float z)
+{
+ if (useTempBuffer)
+ {
+ tempBuffer[tempBufferCount].x = x;
+ tempBuffer[tempBufferCount].y = y;
+ tempBuffer[tempBufferCount].z = z;
+ tempBufferCount++;
+ }
+ else
+ {
+ switch (currentDrawMode)
+ {
+ case RL_LINES:
+ {
+ lines.vertices[3*lines.vCounter] = x;
+ lines.vertices[3*lines.vCounter + 1] = y;
+ lines.vertices[3*lines.vCounter + 2] = z;
+
+ lines.vCounter++;
+
+ } break;
+ case RL_TRIANGLES:
+ {
+ triangles.vertices[3*triangles.vCounter] = x;
+ triangles.vertices[3*triangles.vCounter + 1] = y;
+ triangles.vertices[3*triangles.vCounter + 2] = z;
+
+ triangles.vCounter++;
+
+ } break;
+ case RL_QUADS:
+ {
+ quads.vertices[3*quads.vCounter] = x;
+ quads.vertices[3*quads.vCounter + 1] = y;
+ quads.vertices[3*quads.vCounter + 2] = z;
+
+ quads.vCounter++;
+
+ draws[drawsCounter - 1].vCount++;
+
+ } break;
+ default: break;
+ }
+ }
+}
+
+// Define one vertex (position)
+void rlVertex2f(float x, float y)
+{
+ rlVertex3f(x, y, 0.0);
+}
+
+// Define one vertex (position)
+void rlVertex2i(int x, int y)
+{
+ rlVertex3f((float)x, (float)y, 0.0);
+}
+
+// Define one vertex (texture coordinate)
+// NOTE: Texture coordinates are limited to TRIANGLES only
+void rlTexCoord2f(float x, float y)
+{
+ if (currentDrawMode == RL_QUADS)
+ {
+ quads.texcoords[2*quads.tcCounter] = x;
+ quads.texcoords[2*quads.tcCounter + 1] = y;
+
+ quads.tcCounter++;
+ }
+}
+
+// Define one vertex (normal)
+// NOTE: Normals limited to TRIANGLES only ?
+void rlNormal3f(float x, float y, float z)
+{
+ // TODO: Normals usage...
+}
+
+// Define one vertex (color)
+void rlColor4f(float x, float y, float z, float w)
+{
+ switch (currentDrawMode)
+ {
+ case RL_LINES:
+ {
+ lines.colors[4*lines.cCounter] = x;
+ lines.colors[4*lines.cCounter + 1] = y;
+ lines.colors[4*lines.cCounter + 2] = z;
+ lines.colors[4*lines.cCounter + 3] = w;
+
+ lines.cCounter++;
+
+ } break;
+ case RL_TRIANGLES:
+ {
+ triangles.colors[4*triangles.cCounter] = x;
+ triangles.colors[4*triangles.cCounter + 1] = y;
+ triangles.colors[4*triangles.cCounter + 2] = z;
+ triangles.colors[4*triangles.cCounter + 3] = w;
+
+ triangles.cCounter++;
+
+ } break;
+ case RL_QUADS:
+ {
+ quads.colors[4*quads.cCounter] = x;
+ quads.colors[4*quads.cCounter + 1] = y;
+ quads.colors[4*quads.cCounter + 2] = z;
+ quads.colors[4*quads.cCounter + 3] = w;
+
+ quads.cCounter++;
+
+ } break;
+ default: break;
+ }
+}
+
+// Define one vertex (color)
+void rlColor4ub(byte r, byte g, byte b, byte a)
+{
+ rlColor4f((float)r/255, (float)g/255, (float)b/255, (float)a/255);
+}
+
+// Define one vertex (color)
+void rlColor3f(float x, float y, float z)
+{
+ rlColor4f(x, y, z, 1.0);
+}
+
+#endif
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition - OpenGL equivalent functions (common to 1.1, 3.3+, ES2)
+//----------------------------------------------------------------------------------
+
+// Enable texture usage
+void rlEnableTexture(unsigned int id)
+{
+#ifdef USE_OPENGL_11
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, id);
+#endif
+
+#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+ if (draws[drawsCounter - 1].texId != id)
+ {
+ if (draws[drawsCounter - 1].vCount > 0) drawsCounter++;
+
+ draws[drawsCounter - 1].texId = id;
+ draws[drawsCounter - 1].firstVertex = draws[drawsCounter - 2].vCount;
+ draws[drawsCounter - 1].vCount = 0;
+ }
+#endif
+}
+
+// Disable texture usage
+void rlDisableTexture()
+{
+#ifdef USE_OPENGL_11
+ glDisable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, 0);
+#endif
+}
+
+// Unload texture from GPU memory
+void rlDeleteTextures(unsigned int id)
+{
+ glDeleteTextures(1, &id);
+}
+
+// Unload vertex data from GPU memory
+void rlDeleteVertexArrays(unsigned int id)
+{
+#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+ glDeleteVertexArrays(1, &id);
+#endif
+}
+
+// Clear color buffer with color
+void rlClearColor(byte r, byte g, byte b, byte a)
+{
+ // Color values clamp to 0.0f(0) and 1.0f(255)
+ float cr = (float)r / 255;
+ float cg = (float)g / 255;
+ float cb = (float)b / 255;
+ float ca = (float)a / 255;
+
+ glClearColor(cr, cg, cb, ca);
+}
+
+// Clear used screen buffers (color and depth)
+void rlClearScreenBuffers()
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear used buffers: Color and Depth (Depth is used for 3D)
+ //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // Stencil buffer not used...
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition - rlgl Functions
+//----------------------------------------------------------------------------------
+
+#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+
+// Init OpenGL 3.3+ required data
+void rlglInit()
+{
+ // Initialize GLEW
+ glewExperimental = 1; // Needed for core profile
+
+ GLenum error = glewInit();
+
+ if (error != GLEW_OK)
+ {
+ TraceLog(ERROR, "Failed to initialize GLEW - Error Code: %s\n", glewGetErrorString(error));
+ }
+
+ if (glewIsSupported("GL_VERSION_3_3")) TraceLog(INFO, "OpenGL 3.3 initialized\n");
+
+ // Print OpenGL and GLSL version
+ TraceLog(INFO, "Vendor: %s", glGetString(GL_VENDOR));
+ TraceLog(INFO, "Renderer: %s", glGetString(GL_RENDERER));
+ TraceLog(INFO, "Version: %s", glGetString(GL_VERSION));
+ TraceLog(INFO, "GLSL: %s\n", glGetString(0x8B8C)); //GL_SHADING_LANGUAGE_VERSION
+
+/*
+ // TODO: GLEW is a big library that loads ALL extensions, maybe using glad we can only load required ones...
+ if (!gladLoadGL())
+ {
+ TraceLog("ERROR: Failed to initialize glad\n");
+ }
+*/
+ // Set default draw mode
+ currentDrawMode = RL_TRIANGLES;
+
+ // Reset projection and modelview matrices
+ projection = MatrixIdentity();
+ modelview = MatrixIdentity();
+ currentMatrix = &modelview;
+
+ // Initialize matrix stack
+ for (int i = 0; i < MATRIX_STACK_SIZE; i++) stack[i] = MatrixIdentity();
+
+ // Init default Shader (GLSL 110) -> Common for GL 3.3+ and ES2
+ shaderProgram = LoadDefaultShaders();
+ //shaderProgram = LoadShaders("simple150.vert", "simple150.frag");
+
+ // Get handles to GLSL input vars locations
+ vertexLoc = glGetAttribLocation(shaderProgram, "vertexPosition");
+ texcoordLoc = glGetAttribLocation(shaderProgram, "vertexTexCoord");
+ colorLoc = glGetAttribLocation(shaderProgram, "vertexColor");
+
+ // Get handles to GLSL uniform vars locations (vertex-shader)
+ modelviewMatrixLoc = glGetUniformLocation(shaderProgram, "modelviewMatrix");
+ projectionMatrixLoc = glGetUniformLocation(shaderProgram, "projectionMatrix");
+
+ // Get handles to GLSL uniform vars locations (fragment-shader)
+ textureLoc = glGetUniformLocation(shaderProgram, "texture0");
+
+ TraceLog(INFO, "Default shader loaded");
+
+ InitializeBuffers(); // Init vertex arrays
+ InitializeVAOs(); // Init VBO and VAO
+
+ // Init temp vertex buffer, used when transformation required (translate, rotate, scale)
+ tempBuffer = (Vector3 *)malloc(sizeof(Vector3)*TEMP_VERTEX_BUFFER_SIZE);
+
+ for (int i = 0; i < TEMP_VERTEX_BUFFER_SIZE; i++) tempBuffer[i] = VectorZero();
+
+ // Create default white texture for plain colors (required by shader)
+ unsigned char pixels[4] = { 255, 255, 255, 255 }; // 1 pixel RGBA (4 bytes)
+
+ whiteTexture = rlglLoadTexture(1, 1, pixels);
+
+ if (whiteTexture != 0) TraceLog(INFO, "Base white texture successfully created, id: %i", whiteTexture);
+ else TraceLog(WARNING, "Base white texture could not be created");
+
+ // Init draw calls tracking system
+ draws = (DrawCall *)malloc(sizeof(DrawCall)*MAX_DRAWS_BY_TEXTURE);
+
+ for (int i = 0; i < MAX_DRAWS_BY_TEXTURE; i++)
+ {
+ draws[i].texId = 0;
+ draws[i].firstVertex = 0;
+ draws[i].vCount = 0;
+ }
+
+ drawsCounter = 1;
+ draws[drawsCounter - 1].texId = whiteTexture;
+}
+
+// Vertex Buffer Object deinitialization (memory free)
+void rlglClose()
+{
+ // Unbind everything
+ glBindVertexArray(0);
+ glDisableVertexAttribArray(0);
+ glDisableVertexAttribArray(1);
+ glDisableVertexAttribArray(2);
+ glDisableVertexAttribArray(3);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ glUseProgram(0);
+
+ // Delete VAOs and VBOs
+ glDeleteBuffers(1, &linesBuffer[0]);
+ glDeleteBuffers(1, &linesBuffer[1]);
+ glDeleteBuffers(1, &trianglesBuffer[0]);
+ glDeleteBuffers(1, &trianglesBuffer[1]);
+ glDeleteBuffers(1, &quadsBuffer[0]);
+ glDeleteBuffers(1, &quadsBuffer[1]);
+ glDeleteBuffers(1, &quadsBuffer[2]);
+ glDeleteBuffers(1, &quadsBuffer[3]);
+
+ glDeleteVertexArrays(1, &vaoLines);
+ glDeleteVertexArrays(1, &vaoTriangles);
+ glDeleteVertexArrays(1, &vaoQuads);
+
+ //glDetachShader(shaderProgram, v);
+ //glDetachShader(shaderProgram, f);
+ //glDeleteShader(v);
+ //glDeleteShader(f);
+ glDeleteProgram(shaderProgram);
+
+ // Free vertex arrays memory
+ free(lines.vertices);
+ free(lines.colors);
+
+ free(triangles.vertices);
+ free(triangles.colors);
+
+ free(quads.vertices);
+ free(quads.texcoords);
+ free(quads.colors);
+
+ // Free GPU texture
+ glDeleteTextures(1, &whiteTexture);
+}
+
+void rlglDraw()
+{
+ glUseProgram(shaderProgram); // Use our shader
+
+ glUniformMatrix4fv(projectionMatrixLoc, 1, false, GetMatrixVector(projection));
+ glUniformMatrix4fv(modelviewMatrixLoc, 1, false, GetMatrixVector(modelview));
+ glUniform1i(textureLoc, 0);
+
+ UpdateBuffers();
+
+ if (lines.vCounter > 0)
+ {
+ glBindTexture(GL_TEXTURE_2D, whiteTexture);
+
+ glBindVertexArray(vaoLines);
+ glDrawArrays(GL_LINES, 0, lines.vCounter);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ if (triangles.vCounter > 0)
+ {
+ glBindTexture(GL_TEXTURE_2D, whiteTexture);
+
+ glBindVertexArray(vaoTriangles);
+ glDrawArrays(GL_TRIANGLES, 0, triangles.vCounter);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ if (quads.vCounter > 0)
+ {
+ int numQuads = 0;
+ int numIndicesToProcess = 0;
+ int indicesOffset = 0;
+
+#ifdef USE_VBO_DOUBLE_BUFFERS
+ // Depending on useBufferB, use Buffer A or Buffer B
+ if (useBufferB) glBindVertexArray(vaoQuadsB);
+ else
+#endif
+ {
+ glBindVertexArray(vaoQuads);
+ }
+
+ //TraceLog(INFO, "Draws required per frame: %i", drawsCounter);
+
+ for (int i = 0; i < drawsCounter; i++)
+ {
+ numQuads = draws[i].vCount/4;
+ numIndicesToProcess = numQuads*6; // Get number of Quads * 6 index by Quad
+
+ //TraceLog(INFO, "Quads to render: %i - Vertex Count: %i", numQuads, draws[i].vCount);
+
+ glBindTexture(GL_TEXTURE_2D, draws[i].texId);
+
+ // NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process
+ glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid*) (sizeof(GLuint) * indicesOffset));
+
+ indicesOffset += draws[i].vCount/4*6;
+ }
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures
+ glBindVertexArray(0); // Unbind VAO
+
+ // Reset draws counter
+ drawsCounter = 1;
+ draws[0].texId = whiteTexture;
+ draws[0].firstVertex = 0;
+ draws[0].vCount = 0;
+
+ // Reset vertex counters for next frame
+ lines.vCounter = 0;
+ lines.cCounter = 0;
+
+ triangles.vCounter = 0;
+ triangles.cCounter = 0;
+
+ quads.vCounter = 0;
+ quads.tcCounter = 0;
+ quads.cCounter = 0;
+
+ // TODO: Review double buffer performance -> no improvement! (?)
+#ifdef USE_VBO_DOUBLE_BUFFERS
+ useBufferB = !useBufferB; // Change buffers usage!
+#endif
+}
+
+#endif // End for OpenGL 3.3+ and ES2 only functions
+
+// Draw a 3d model
+void rlglDrawModel(Model model, Vector3 position, float scale, bool wires)
+{
+ if (wires) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+#ifdef USE_OPENGL_11
+ // NOTE: For models we use Vertex Arrays (OpenGL 1.1)
+ glEnableClientState(GL_VERTEX_ARRAY); // Enable vertex array
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY); // Enable texture coords array
+ glEnableClientState(GL_NORMAL_ARRAY); // Enable normals array
+
+ glVertexPointer(3, GL_FLOAT, 0, model.data.vertices); // Pointer to vertex coords array
+ glTexCoordPointer(2, GL_FLOAT, 0, model.data.texcoords); // Pointer to texture coords array
+ glNormalPointer(GL_FLOAT, 0, model.data.normals); // Pointer to normals array
+ //glColorPointer(4, GL_UNSIGNED_BYTE, 0, model.colors); // Pointer to colors array (NOT USED)
+
+ rlPushMatrix();
+ rlTranslatef(position.x, position.y, position.z);
+ //rlRotatef(rotation * GetFrameTime(), 0, 1, 0);
+ rlScalef(scale, scale, scale);
+
+ rlColor4ub(1.0f, 1.0f, 1.0f, 1.0f);
+
+ glDrawArrays(GL_TRIANGLES, 0, model.data.numVertices);
+ rlPopMatrix();
+
+ glDisableClientState(GL_VERTEX_ARRAY); // Disable vertex array
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY); // Disable texture coords array
+ glDisableClientState(GL_NORMAL_ARRAY); // Disable normals array
+#endif
+
+#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+ glUseProgram(shaderProgram); // Use our shader
+
+ Matrix modelview2 = MatrixMultiply(model.transform, modelview);
+
+ // NOTE: Drawing in OpenGL 3.3+, transform is passed to shader
+ glUniformMatrix4fv(projectionMatrixLoc, 1, false, GetMatrixVector(projection));
+ glUniformMatrix4fv(modelviewMatrixLoc, 1, false, GetMatrixVector(modelview2));
+ glUniform1i(textureLoc, 0);
+
+ glBindVertexArray(model.vaoId);
+ //glBindTexture(GL_TEXTURE_2D, model.textureId);
+
+ glDrawArrays(GL_TRIANGLES, 0, model.numVertices);
+
+ //glBindTexture(GL_TEXTURE_2D, 0); // Unbind textures
+ glBindVertexArray(0); // Unbind VAO
+#endif
+
+ if (wires) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
+
+// Initialize Graphics Device (OpenGL stuff)
+void rlglInitGraphicsDevice(int fbWidth, int fbHeight)
+{
+ //glViewport(0, 0, fbWidth, fbHeight); // Set viewport width and height
+ // NOTE: Not required, viewport will be full window space
+
+ // NOTE: Don't confuse glViewport with the transformation matrix
+ // NOTE: glViewport just defines the area of the context that you will actually draw to.
+
+ 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, 1.0f); // Set background color (black)
+ //glClearDepth(1.0f); // Clear depth buffer (default)
+
+ 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)
+
+#ifdef USE_OPENGL_11
+ 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)
+#endif
+
+ rlMatrixMode(RL_PROJECTION); // Switch to PROJECTION matrix
+ rlLoadIdentity(); // Reset current matrix (PROJECTION)
+
+ rlOrtho(0, fbWidth, fbHeight, 0, 0, 1); // Config orthographic mode: top-left corner --> (0,0)
+
+ rlMatrixMode(RL_MODELVIEW); // Switch back to MODELVIEW matrix
+ rlLoadIdentity(); // Reset current matrix (MODELVIEW)
+
+ // NOTE: All shapes/models triangles are drawn CCW
+
+ 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)
+
+#ifdef USE_OPENGL_11
+ glShadeModel(GL_SMOOTH); // Smooth shading between vertex (vertex colors interpolation) (Deprecated on OpenGL 3.3+)
+ // Possible options: GL_SMOOTH (Color interpolation) or GL_FLAT (no interpolation)
+#endif
+
+ TraceLog(INFO, "OpenGL graphics device initialized");
+}
+
+// Convert image data to OpenGL texture (returns OpenGL valid Id)
+// NOTE: Image is not unloaded, it should be done manually...
+unsigned int rlglLoadTexture(int width, int height, unsigned char *data)
+{
+ glBindTexture(GL_TEXTURE_2D,0); // Free any old binding
+
+ GLuint id;
+ glGenTextures(1, &id); // Generate Pointer to the texture
+
+ //glActiveTexture(GL_TEXTURE0);
+ 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
+
+#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+ // 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!
+#endif
+
+ // NOTE: Not using mipmappings (texture for 2D drawing)
+ // At this point we have the image converted to texture and uploaded to GPU
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+
+ // At this point we have the image converted to texture and uploaded to GPU
+
+ // Unbind current texture
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ TraceLog(INFO, "New texture created, id: %i (%i x %i)", id, width, height);
+
+ return id;
+}
+
+
+#ifdef USE_OPENGL_33
+
+#define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII
+#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII
+#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII
+
+// Convert image data to OpenGL texture (returns OpenGL valid Id)
+// NOTE: Expected compressed data from DDS file
+unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int format)
+{
+ // Create one OpenGL texture
+ GLuint id;
+ int compFormat = 0;
+
+ TraceLog(DEBUG, "Compressed texture width: %i", width);
+ TraceLog(DEBUG, "Compressed texture height: %i", height);
+ TraceLog(DEBUG, "Compressed texture mipmap levels: %i", mipmapCount);
+ TraceLog(DEBUG, "Compressed texture format: 0x%x", format);
+
+ switch(format)
+ {
+ case FOURCC_DXT1: compFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
+ case FOURCC_DXT3: compFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;
+ case FOURCC_DXT5: compFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
+ default: compFormat = -1; break;
+ }
+
+ if (compFormat == -1)
+ {
+ TraceLog(WARNING, "Texture compressed format not recognized");
+ id = 0;
+ }
+ else
+ {
+ glGenTextures(1, &id);
+
+ // Bind the texture
+ glBindTexture(GL_TEXTURE_2D, id);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ unsigned int blockSize = (compFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;
+ unsigned int offset = 0;
+
+ // Load the mipmaps
+ for (int level = 0; level < mipmapCount && (width || height); level++)
+ {
+ unsigned int size = ((width+3)/4)*((height+3)/4)*blockSize;
+
+ glCompressedTexImage2D(GL_TEXTURE_2D, level, compFormat, width, height, 0, size, data + offset);
+
+ offset += size;
+ width /= 2;
+ height /= 2;
+
+ // Security check for NPOT textures
+ if (width < 1) width = 1;
+ if (height < 1) height = 1;
+ }
+ }
+
+ return id;
+}
+
+// Load vertex data into a VAO
+unsigned int rlglLoadModel(VertexData mesh)
+{
+ GLuint vaoModel; // Vertex Array Objects (VAO)
+ GLuint vertexBuffer[3]; // Vertex Buffer Objects (VBO)
+
+ // Initialize Quads VAO (Buffer A)
+ glGenVertexArrays(1, &vaoModel);
+ glBindVertexArray(vaoModel);
+
+ // Create buffers for our vertex data (positions, texcoords, normals)
+ glGenBuffers(3, vertexBuffer);
+
+ // Enable vertex attributes
+ glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.numVertices, mesh.vertices, GL_STATIC_DRAW);
+ glEnableVertexAttribArray(vertexLoc);
+ glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh.numVertices, mesh.texcoords, GL_STATIC_DRAW);
+ glEnableVertexAttribArray(texcoordLoc);
+ glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.numVertices, mesh.normals, GL_STATIC_DRAW);
+ //glEnableVertexAttribArray(normalLoc);
+ //glVertexAttribPointer(normalLoc, 3, GL_FLOAT, 0, 0, 0);
+
+ return vaoModel;
+}
+#endif
+
+// Read screen pixel data (color buffer)
+unsigned char *rlglReadScreenPixels(int width, int height)
+{
+ unsigned char *screenData = (unsigned char *)malloc(width * height * sizeof(unsigned char) * 4);
+
+ // NOTE: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer
+ glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, screenData);
+
+ // Flip image vertically!
+ unsigned char *imgData = (unsigned char *)malloc(width * height * sizeof(unsigned char) * 4);
+
+ for (int y = height-1; y >= 0; y--)
+ {
+ for (int x = 0; x < (width*4); x++)
+ {
+ imgData[x + (height - y - 1)*width*4] = screenData[x + (y*width*4)];
+ }
+ }
+
+ free(screenData);
+
+ return imgData; // NOTE: image data should be freed
+}
+
+#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+
+void PrintProjectionMatrix()
+{
+ PrintMatrix(projection);
+}
+
+void PrintModelviewMatrix()
+{
+ PrintMatrix(modelview);
+}
+
+#endif
+
+//----------------------------------------------------------------------------------
+// Module specific Functions Definition
+//----------------------------------------------------------------------------------
+
+#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+
+// Load Shaders (Vertex and Fragment)
+static GLuint LoadDefaultShaders()
+{
+ // NOTE: Shaders are written using GLSL 110 (desktop), that is equivalent to GLSL 100 on ES2
+
+ // Vertex shader directly defined, no external file required
+ char vShaderStr[] = " #version 110 \n" // Equivalent to version 100 on ES2
+ "uniform mat4 projectionMatrix; \n"
+ "uniform mat4 modelviewMatrix; \n"
+ "attribute vec3 vertexPosition; \n"
+ "attribute vec2 vertexTexCoord; \n"
+ "attribute vec4 vertexColor; \n"
+ "varying vec2 fragTexCoord; \n"
+ "varying vec4 fragColor; \n"
+ "void main() \n"
+ "{ \n"
+ " fragTexCoord = vertexTexCoord; \n"
+ " fragColor = vertexColor; \n"
+ " gl_Position = projectionMatrix * modelviewMatrix * vec4(vertexPosition, 1.0); \n"
+ "} \n";
+
+ // Fragment shader directly defined, no external file required
+ char fShaderStr[] = " #version 110 \n" // Equivalent to version 100 on ES2
+ "uniform sampler2D texture0; \n"
+ "varying vec2 fragTexCoord; \n"
+ "varying vec4 fragColor; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_FragColor = texture2D(texture0, fragTexCoord) * fragColor; \n"
+ "} \n";
+
+ GLuint program;
+ GLuint vertexShader;
+ GLuint fragmentShader;
+
+ vertexShader = glCreateShader(GL_VERTEX_SHADER);
+ fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
+
+ const char *pvs = vShaderStr;
+ const char *pfs = fShaderStr;
+
+ glShaderSource(vertexShader, 1, &pvs, NULL);
+ glShaderSource(fragmentShader, 1, &pfs, NULL);
+
+ glCompileShader(vertexShader);
+ glCompileShader(fragmentShader);
+
+ program = glCreateProgram();
+
+ glAttachShader(program, vertexShader);
+ glAttachShader(program, fragmentShader);
+
+ glLinkProgram(program);
+
+ glDeleteShader(vertexShader);
+ glDeleteShader(fragmentShader);
+
+ return program;
+}
+
+
+// Load Shaders
+static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName)
+{
+ // Shaders loading from external text file
+ char *vShaderStr = TextFileRead(vertexFileName);
+ char *fShaderStr = TextFileRead(fragmentFileName);
+
+ GLuint program;
+ GLuint vertexShader;
+ GLuint fragmentShader;
+
+ vertexShader = glCreateShader(GL_VERTEX_SHADER);
+ fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
+
+ const char *pvs = vShaderStr;
+ const char *pfs = fShaderStr;
+
+ glShaderSource(vertexShader, 1, &pvs, NULL);
+ glShaderSource(fragmentShader, 1, &pfs, NULL);
+
+ glCompileShader(vertexShader);
+ glCompileShader(fragmentShader);
+
+ program = glCreateProgram();
+
+ glAttachShader(program, vertexShader);
+ glAttachShader(program, fragmentShader);
+
+ glLinkProgram(program);
+
+ glDeleteShader(vertexShader);
+ glDeleteShader(fragmentShader);
+
+ return program;
+}
+
+// Read shader text file
+static char *TextFileRead(char *fn)
+{
+ FILE *fp;
+ char *text = NULL;
+
+ int count=0;
+
+ if (fn != NULL)
+ {
+ fp = fopen(fn,"rt");
+
+ if (fp != NULL)
+ {
+ fseek(fp, 0, SEEK_END);
+ count = ftell(fp);
+ rewind(fp);
+
+ if (count > 0)
+ {
+ text = (char *)malloc(sizeof(char) * (count+1));
+ count = fread(text, sizeof(char), count, fp);
+ text[count] = '\0';
+ }
+
+ fclose(fp);
+ }
+ }
+ return text;
+}
+
+// Allocate and initialize float array buffers to store vertex data (lines, triangles, quads)
+static void InitializeBuffers()
+{
+ // Initialize lines arrays (vertex position and color data)
+ lines.vertices = (float *)malloc(sizeof(float)*3*2*MAX_LINES_BATCH); // 3 float by vertex, 2 vertex by line
+ lines.colors = (float *)malloc(sizeof(float)*4*2*MAX_LINES_BATCH); // 4 float by color, 2 colors by line
+
+ for (int i = 0; i < (3*2*MAX_LINES_BATCH); i++) lines.vertices[i] = 0.0;
+ for (int i = 0; i < (4*2*MAX_LINES_BATCH); i++) lines.colors[i] = 0.0;
+
+ lines.vCounter = 0;
+ lines.cCounter = 0;
+
+ // Initialize triangles arrays (vertex position and color data)
+ triangles.vertices = (float *)malloc(sizeof(float)*3*3*MAX_TRIANGLES_BATCH); // 3 float by vertex, 3 vertex by triangle
+ triangles.colors = (float *)malloc(sizeof(float)*4*3*MAX_TRIANGLES_BATCH); // 4 float by color, 3 colors by triangle
+
+ for (int i = 0; i < (3*3*MAX_TRIANGLES_BATCH); i++) triangles.vertices[i] = 0.0;
+ for (int i = 0; i < (4*3*MAX_TRIANGLES_BATCH); i++) triangles.colors[i] = 0.0;
+
+ triangles.vCounter = 0;
+ triangles.cCounter = 0;
+
+ // Initialize quads arrays (vertex position, texcoord and color data... and indexes)
+ quads.vertices = (float *)malloc(sizeof(float)*3*4*MAX_QUADS_BATCH); // 3 float by vertex, 4 vertex by quad
+ quads.texcoords = (float *)malloc(sizeof(float)*2*4*MAX_QUADS_BATCH); // 2 float by texcoord, 4 texcoord by quad
+ quads.colors = (float *)malloc(sizeof(float)*4*4*MAX_QUADS_BATCH); // 4 float by color, 4 colors by quad
+ quads.indices = (unsigned int *)malloc(sizeof(int)*6*MAX_QUADS_BATCH); // 6 int by quad (indices)
+
+ for (int i = 0; i < (3*4*MAX_QUADS_BATCH); i++) quads.vertices[i] = 0.0;
+ for (int i = 0; i < (2*4*MAX_QUADS_BATCH); i++) quads.texcoords[i] = 0.0;
+ for (int i = 0; i < (4*4*MAX_QUADS_BATCH); i++) quads.colors[i] = 0.0;
+
+ int k = 0;
+
+ // Indices can be initialized right now
+ for (int i = 0; i < (6*MAX_QUADS_BATCH); i+=6)
+ {
+ quads.indices[i] = 4*k;
+ quads.indices[i+1] = 4*k+1;
+ quads.indices[i+2] = 4*k+2;
+ quads.indices[i+3] = 4*k;
+ quads.indices[i+4] = 4*k+2;
+ quads.indices[i+5] = 4*k+3;
+
+ k++;
+ }
+
+ quads.vCounter = 0;
+ quads.tcCounter = 0;
+ quads.cCounter = 0;
+}
+
+// Initialize Vertex Array Objects (Contain VBO)
+static void InitializeVAOs()
+{
+ // Initialize Lines VAO
+ glGenVertexArrays(1, &vaoLines);
+ glBindVertexArray(vaoLines);
+
+ // Create buffers for our vertex data
+ glGenBuffers(2, linesBuffer);
+
+ // Lines - Vertex positions buffer binding and attributes enable
+ glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*2*MAX_LINES_BATCH, lines.vertices, GL_DYNAMIC_DRAW);
+ glEnableVertexAttribArray(vertexLoc);
+ glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
+
+ // Lines - colors buffer
+ glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW);
+ glEnableVertexAttribArray(colorLoc);
+ glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
+
+ //--------------------------------------------------------------
+
+ // Initialize Triangles VAO
+ glGenVertexArrays(1, &vaoTriangles);
+ glBindVertexArray(vaoTriangles);
+
+ // Create buffers for our vertex data
+ glGenBuffers(2, trianglesBuffer);
+
+ // Enable vertex attributes
+ glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*3*MAX_TRIANGLES_BATCH, triangles.vertices, GL_DYNAMIC_DRAW);
+ glEnableVertexAttribArray(vertexLoc);
+ glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW);
+ glEnableVertexAttribArray(colorLoc);
+ glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
+
+ //--------------------------------------------------------------
+
+ // Initialize Quads VAO (Buffer A)
+ glGenVertexArrays(1, &vaoQuads);
+ glBindVertexArray(vaoQuads);
+
+ // Create buffers for our vertex data
+ glGenBuffers(4, quadsBuffer);
+
+ // Enable vertex attributes
+ glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW);
+ glEnableVertexAttribArray(vertexLoc);
+ glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW);
+ glEnableVertexAttribArray(texcoordLoc);
+ glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW);
+ glEnableVertexAttribArray(colorLoc);
+ glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
+
+ // Fill index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW);
+
+#ifdef USE_VBO_DOUBLE_BUFFERS
+ // Initialize Quads VAO (Buffer B)
+ glGenVertexArrays(1, &vaoQuadsB);
+ glBindVertexArray(vaoQuadsB);
+
+ // Create buffers for our vertex data
+ glGenBuffers(4, quadsBufferB);
+
+ // Enable vertex attributes
+ glBindBuffer(GL_ARRAY_BUFFER, quadsBufferB[0]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW);
+ glEnableVertexAttribArray(vertexLoc);
+ glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, quadsBufferB[1]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW);
+ glEnableVertexAttribArray(texcoordLoc);
+ glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
+
+ glBindBuffer(GL_ARRAY_BUFFER, quadsBufferB[2]);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW);
+ glEnableVertexAttribArray(colorLoc);
+ glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
+
+ // Fill index buffer
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBufferB[3]);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW);
+
+ TraceLog(INFO, "Using VBO double buffering");
+#endif
+
+ TraceLog(INFO, "Vertex buffers successfully initialized (lines, triangles, quads)\n");
+
+ // Unbind the current VAO
+ glBindVertexArray(0);
+}
+
+// Update VBOs with vertex array data
+static void UpdateBuffers()
+{
+ // Activate Lines VAO
+ glBindVertexArray(vaoLines);
+
+ // Lines - vertex positions buffer
+ glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[0]);
+ //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*2*MAX_LINES_BATCH, lines.vertices, GL_DYNAMIC_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*lines.vCounter, lines.vertices); // target - offset (in bytes) - size (in bytes) - data pointer
+
+ // Lines - colors buffer
+ glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]);
+ //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*4*lines.vCounter, lines.colors);
+
+ //--------------------------------------------------------------
+
+ // Activate Triangles VAO
+ glBindVertexArray(vaoTriangles);
+
+ // Triangles - vertex positions buffer
+ glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[0]);
+ //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*3*MAX_TRIANGLES_BATCH, triangles.vertices, GL_DYNAMIC_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*triangles.vCounter, triangles.vertices);
+
+ // Triangles - colors buffer
+ glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]);
+ //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*4*triangles.cCounter, triangles.colors);
+
+ //--------------------------------------------------------------
+
+ // Depending on useBufferB, update Buffer A or Buffer B
+#ifdef USE_VBO_DOUBLE_BUFFERS
+ if (useBufferB)
+ {
+ // Activate Quads VAO (Buffer B)
+ glBindVertexArray(vaoQuadsB);
+
+ // Quads - vertex positions buffer
+ glBindBuffer(GL_ARRAY_BUFFER, quadsBufferB[0]);
+ //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*quads.vCounter, quads.vertices);
+
+ // Quads - texture coordinates buffer
+ glBindBuffer(GL_ARRAY_BUFFER, quadsBufferB[1]);
+ //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*quads.vCounter, quads.texcoords);
+
+ // Quads - colors buffer
+ glBindBuffer(GL_ARRAY_BUFFER, quadsBufferB[2]);
+ //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*4*quads.vCounter, quads.colors);
+ }
+ else
+#endif
+ {
+ // Activate Quads VAO (Buffer A)
+ glBindVertexArray(vaoQuads);
+
+ // Quads - vertex positions buffer
+ glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]);
+ //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*quads.vCounter, quads.vertices);
+
+ // Quads - texture coordinates buffer
+ glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]);
+ //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*quads.vCounter, quads.texcoords);
+
+ // Quads - colors buffer
+ glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]);
+ //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*4*quads.vCounter, quads.colors);
+ }
+
+
+ // Another option would be using buffer mapping...
+ //triangles.vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
+ // Now we can modify vertices
+ //glUnmapBuffer(GL_ARRAY_BUFFER);
+
+ //--------------------------------------------------------------
+
+ // Unbind the current VAO
+ glBindVertexArray(0);
+}
+
+#endif
+
+#ifdef RLGL_STANDALONE
+
+typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
+
+// Output a trace log message
+// NOTE: Expected msgType: (0)Info, (1)Error, (2)Warning
+void TraceLog(int msgType, const char *text, ...)
+{
+ va_list args;
+ va_start(args, text);
+
+ switch(msgType)
+ {
+ case 0: fprintf(stdout, "INFO: "); break;
+ case 1: fprintf(stdout, "ERROR: "); break;
+ case 2: fprintf(stdout, "WARNING: "); break;
+ case 3: fprintf(logstream, "DEBUG: "); break;
+ default: break;
+ }
+
+ vfprintf(stdout, text, args);
+ fprintf(stdout, "\n");
+
+ va_end(args);
+
+ if (msgType == 1) exit(1);
+}
+#endif \ No newline at end of file
diff --git a/src/rlgl.h b/src/rlgl.h
new file mode 100644
index 00000000..0cd53661
--- /dev/null
+++ b/src/rlgl.h
@@ -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 \ No newline at end of file
diff --git a/src/shapes.c b/src/shapes.c
index 07a73cad..42496351 100644
--- a/src/shapes.c
+++ b/src/shapes.c
@@ -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)
{
diff --git a/src/simple150.frag b/src/simple150.frag
index 61b337ed..74a727dd 100644
--- a/src/simple150.frag
+++ b/src/simple150.frag
@@ -11,5 +11,4 @@ void main()
{
// Output pixel color
pixelColor = texture(texture0, fragTexCoord) * fragColor;
- //pixelColor = fragColor;
} \ No newline at end of file
diff --git a/src/stb_vorbis.c b/src/stb_vorbis.c
index cf7ad1d4..a88b2a77 100644
--- a/src/stb_vorbis.c
+++ b/src/stb_vorbis.c
@@ -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),
diff --git a/src/stb_vorbis.h b/src/stb_vorbis.h
index 98c1209a..2d7b61e5 100644
--- a/src/stb_vorbis.h
+++ b/src/stb_vorbis.h
@@ -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 \ No newline at end of file
diff --git a/src/text.c b/src/text.c
index 492329c5..4cc36baf 100644
--- a/src/text.c
+++ b/src/text.c
@@ -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
@@ -64,6 +74,11 @@ 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
//----------------------------------------------------------------------------------
static bool PixelIsMagenta(Color p); // Check if a pixel is magenta
@@ -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);
-
- glBindTexture(GL_TEXTURE_2D, spriteFont.texture.glId);
+ rlEnableTexture(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, '.');
diff --git a/src/textures.c b/src/textures.c
index ca0492c4..7d4a0fb4 100644
--- a/src/textures.c
+++ b/src/textures.c
@@ -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'))
- {
- 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++)
+ if (!rresFile) TraceLog(WARNING, "[%s] Could not open raylib resource file", rresName);
+ else
{
- 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;
+ TraceLog(WARNING, "[%s] This is not a valid raylib resource file", rresName);
+ }
+ else
+ {
+ // Read number of resources embedded
+ fread(&numRes, sizeof(short), 1, rresFile);
- // Check data is of valid IMAGE type
- if (infoHeader.type == 0) // IMAGE data type
+ for (int i = 0; i < numRes; i++)
{
- // TODO: Check data compression type
+ fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile);
- // 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;
+ 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)
- unsigned char *data = malloc(infoHeader.size);
+ 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)
+ 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
{
- 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++;
+ // 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);
}
-
- free(imgData);
-
- free(data);
- }
- else
- {
- printf("Required resource do not seem to be a valid IMAGE resource\n");
- exit(2);
}
}
- 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
-
- glBindTexture(GL_TEXTURE_2D, texture.glId);
-
- 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();
+ rlEnableTexture(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);
+
+ 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
-
- glBindTexture(GL_TEXTURE_2D, texture.glId);
+ rlEnableTexture(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
+
+ // 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);
- glBegin(GL_QUADS);
- glColor4ub(tint.r, tint.g, tint.b, tint.a);
- glNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer
+ // 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();
+
+ 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)
+{
+ rlEnableTexture(texture.glId);
+
+ // 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(sourceRec.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(sourceRec.width, sourceRec.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, sourceRec.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();
}
-// 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)
+Texture2D CreateTexture(Image image)
{
- glEnable(GL_TEXTURE_2D); // Enable textures usage
+ 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);
- glBindTexture(GL_TEXTURE_2D, texture.glId);
+ 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");
- glPushMatrix();
- glTranslatef(-origin.x, -origin.y, 0);
- glRotatef(rotation, 0, 0, 1);
- glTranslatef(destRec.x + origin.x, destRec.y + origin.y, 0);
+ 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);
- glBegin(GL_QUADS);
- glColor4ub(tint.r, tint.g, tint.b, tint.a);
- glNormal3f(0.0f, 0.0f, 1.0f); // Normal vector pointing towards viewer
+ 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;
- // Bottom-left corner for texture and quad
- glTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height);
- glVertex2f(0.0f, 0.0f);
+ TraceLog(DEBUG, "[%s] DDS file header size: %i", fileName, sizeof(ddsHeader));
- // 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);
+ 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);
- // 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);
+ int bufsize;
- // 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();
+ // 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;
+ }
+ }
- glDisable(GL_TEXTURE_2D); // Disable textures usage
+ return image;
} \ No newline at end of file
diff --git a/src/utils.c b/src/utils.c
index 8c5d7240..6d2a4f30 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -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!!!
-} \ No newline at end of file
+}
+
+// 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);
+}
+
diff --git a/src/utils.h b/src/utils.h
index 53241aff..a887beef 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -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
diff --git a/src/vector3.c b/src/vector3.c
deleted file mode 100644
index 6b0e1573..00000000
--- a/src/vector3.c
+++ /dev/null
@@ -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;
-}
diff --git a/src/vector3.h b/src/vector3.h
deleted file mode 100644
index 6c0ead6d..00000000
--- a/src/vector3.h
+++ /dev/null
@@ -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 \ No newline at end of file