From 6db44500b75097a581587cba15ce703963d2ced8 Mon Sep 17 00:00:00 2001
From: Joshua Reisenauer <kd7tck@msn.com>
Date: Wed, 11 May 2016 00:37:10 -0700
Subject: [PATCH 01/33] adding multiple music streams

---
 src/audio.c  | 181 +++++++++++++++++++++++----------------------------
 src/audio.h  |   9 +--
 src/raylib.h |   9 +--
 3 files changed, 91 insertions(+), 108 deletions(-)

diff --git a/src/audio.c b/src/audio.c
index fbf53df66..39be4eebd 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -61,6 +61,7 @@
 //----------------------------------------------------------------------------------
 #define MAX_STREAM_BUFFERS          2
 #define MAX_AUDIO_CONTEXTS          4             // Number of open AL sources
+#define MAX_MUSIC_STREAMS           2
 
 #if defined(PLATFORM_RPI) || defined(PLATFORM_ANDROID)
     // NOTE: On RPI and Android should be lower to avoid frame-stalls
@@ -81,13 +82,8 @@
 typedef struct Music {
     stb_vorbis *stream;
     jar_xm_context_t *chipctx; // Stores jar_xm context
-
-    ALuint buffers[MAX_STREAM_BUFFERS];
-    ALuint source;
-    ALenum format;
-
-    int channels;
-    int sampleRate;
+    AudioContext_t *ctx; // audio context
+    
     int totalSamplesLeft;
     float totalLengthSeconds;
     bool loop;
@@ -117,8 +113,8 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
 //----------------------------------------------------------------------------------
 static AudioContext_t* mixChannelsActive_g[MAX_AUDIO_CONTEXTS];      // What mix channels are currently active
 static bool musicEnabled = false;
-static Music currentMusic;          // Current music loaded
-                                    // NOTE: Only one music file playing at a time
+static Music currentMusic[2];                                        // Current music loaded, up to two can play at the same time
+
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
 //----------------------------------------------------------------------------------
@@ -769,151 +765,129 @@ void SetSoundPitch(Sound sound, float pitch)
 // Start music playing (open stream)
 void PlayMusicStream(char *fileName)
 {
+    int musicIndex;
+    int mixIndex;
+    for(musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++) // find empty music slot
+    {
+        if(currentMusic[musicIndex].stream == NULL && !currentMusic[musicIndex].chipTune) break;
+        else if(musicIndex = MAX_MUSIC_STREAMS - 1) return;
+    }
+    for(mixIndex = 0; mixIndex < MAX_AUDIO_CONTEXTS; mixIndex++) // find empty mix channel slot
+    {
+        if(mixChannelsActive_g[mixIndex] == NULL) break;
+        else if(musicIndex = MAX_AUDIO_CONTEXTS - 1) return;
+    }
+    
+    
     if (strcmp(GetExtension(fileName),"ogg") == 0)
     {
-        // Stop current music, clean buffers, unload current stream
-        StopMusicStream();
-
         // Open audio stream
-        currentMusic.stream = stb_vorbis_open_filename(fileName, NULL, NULL);
+        currentMusic[musicIndex].stream = stb_vorbis_open_filename(fileName, NULL, NULL);
 
-        if (currentMusic.stream == NULL)
+        if (currentMusic[musicIndex].stream == NULL)
         {
             TraceLog(WARNING, "[%s] OGG audio file could not be opened", fileName);
         }
         else
         {
             // Get file info
-            stb_vorbis_info info = stb_vorbis_get_info(currentMusic.stream);
-
-            currentMusic.channels = info.channels;
-            currentMusic.sampleRate = info.sample_rate;
+            stb_vorbis_info info = stb_vorbis_get_info(currentMusic[musicIndex].stream);
 
             TraceLog(INFO, "[%s] Ogg sample rate: %i", fileName, info.sample_rate);
             TraceLog(INFO, "[%s] Ogg channels: %i", fileName, info.channels);
             TraceLog(DEBUG, "[%s] Temp memory required: %i", fileName, info.temp_memory_required);
 
-            if (info.channels == 2) currentMusic.format = AL_FORMAT_STEREO16;
-            else currentMusic.format = AL_FORMAT_MONO16;
+            if (info.channels == 2){
+                currentMusic[musicIndex].ctx = InitAudioContext(info.sample_rate, mixIndex, 2, false);
+            }
+            else{
+                currentMusic[musicIndex].ctx = InitAudioContext(info.sample_rate, mixIndex, 1, false);
+            }
 
-            currentMusic.loop = true;                  // We loop by default
+            currentMusic[musicIndex].loop = true;                  // We loop by default
             musicEnabled = true;
 
-            // Create an audio source
-            alGenSources(1, &currentMusic.source);     // Generate pointer to audio source
-
-            alSourcef(currentMusic.source, AL_PITCH, 1);
-            alSourcef(currentMusic.source, AL_GAIN, 1);
-            alSource3f(currentMusic.source, AL_POSITION, 0, 0, 0);
-            alSource3f(currentMusic.source, AL_VELOCITY, 0, 0, 0);
-            //alSourcei(currentMusic.source, AL_LOOPING, AL_TRUE);     // ERROR: Buffers do not queue!
-
-            // Generate two OpenAL buffers
-            alGenBuffers(2, currentMusic.buffers);
-
-            // Fill buffers with music...
-            BufferMusicStream(currentMusic.buffers[0]);
-            BufferMusicStream(currentMusic.buffers[1]);
-
-            // Queue buffers and start playing
-            alSourceQueueBuffers(currentMusic.source, 2, currentMusic.buffers);
-            alSourcePlay(currentMusic.source);
-
-            // NOTE: Regularly, we must check if a buffer has been processed and refill it: UpdateMusicStream()
-
-            currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels;
-            currentMusic.totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic.stream);
+            currentMusic[musicIndex].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[musicIndex].stream) * currentMusic[musicIndex].channels;
+            currentMusic[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[musicIndex].stream);
         }
     }
     else if (strcmp(GetExtension(fileName),"xm") == 0)
     {
-        // Stop current music, clean buffers, unload current stream
-        StopMusicStream();
-        
-        // new song settings for xm chiptune
-        currentMusic.chipTune = true;
-        currentMusic.channels = 2;
-        currentMusic.sampleRate = 48000;
-        currentMusic.loop = true;
-        
         // only stereo is supported for xm
-        if(!jar_xm_create_context_from_file(&currentMusic.chipctx, currentMusic.sampleRate, fileName))
+        if(!jar_xm_create_context_from_file(&currentMusic[musicIndex].chipctx, 48000, fileName))
         {
-            currentMusic.format = AL_FORMAT_STEREO16;
-            jar_xm_set_max_loop_count(currentMusic.chipctx, 0); // infinite number of loops
-            currentMusic.totalSamplesLeft =  jar_xm_get_remaining_samples(currentMusic.chipctx);
-            currentMusic.totalLengthSeconds = ((float)currentMusic.totalSamplesLeft) / ((float)currentMusic.sampleRate);
+            currentMusic[musicIndex].chipTune = true;
+            currentMusic[musicIndex].loop = true;
+            jar_xm_set_max_loop_count(currentMusic[musicIndex].chipctx, 0); // infinite number of loops
+            currentMusic[musicIndex].totalSamplesLeft =  jar_xm_get_remaining_samples(currentMusic[musicIndex].chipctx);
+            currentMusic[musicIndex].totalLengthSeconds = ((float)currentMusic[musicIndex].totalSamplesLeft) / ((float)currentMusic[musicIndex].sampleRate);
             musicEnabled = true;
             
-            TraceLog(INFO, "[%s] XM number of samples: %i", fileName, currentMusic.totalSamplesLeft);
-            TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, currentMusic.totalLengthSeconds);
-            
-            // Set up OpenAL
-            alGenSources(1, &currentMusic.source);
-            alSourcef(currentMusic.source, AL_PITCH, 1);
-            alSourcef(currentMusic.source, AL_GAIN, 1);
-            alSource3f(currentMusic.source, AL_POSITION, 0, 0, 0);
-            alSource3f(currentMusic.source, AL_VELOCITY, 0, 0, 0);
-            alGenBuffers(2, currentMusic.buffers);
-            BufferMusicStream(currentMusic.buffers[0]);
-            BufferMusicStream(currentMusic.buffers[1]);
-            alSourceQueueBuffers(currentMusic.source, 2, currentMusic.buffers);
-            alSourcePlay(currentMusic.source);
+            TraceLog(INFO, "[%s] XM number of samples: %i", fileName, currentMusic[musicIndex].totalSamplesLeft);
+            TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, currentMusic[musicIndex].totalLengthSeconds);
             
-            // NOTE: Regularly, we must check if a buffer has been processed and refill it: UpdateMusicStream()
+            currentMusic[musicIndex].ctx = InitAudioContext(48000, mixIndex, 2, true);
         }
         else TraceLog(WARNING, "[%s] XM file could not be opened", fileName);
     }
     else TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName);
 }
 
-// Stop music playing (close stream)
-void StopMusicStream(void)
+// Stop music playing for individual music index of currentMusic array (close stream)
+void StopMusicStream(int index)
 {
-    if (musicEnabled)
+    if (index < MAX_MUSIC_STREAMS && currentMusic[index].ctx)
     {
-        alSourceStop(currentMusic.source);
-        EmptyMusicStream(); // Empty music buffers
-        alDeleteSources(1, &currentMusic.source);
-        alDeleteBuffers(2, currentMusic.buffers);
+        CloseAudioContext(currentMusic[index].ctx);
         
-        if (currentMusic.chipTune)
+        if (currentMusic[index].chipTune)
         {
-            jar_xm_free_context(currentMusic.chipctx);
+            jar_xm_free_context(currentMusic[index].chipctx);
         }
         else
         {
-            stb_vorbis_close(currentMusic.stream);
+            stb_vorbis_close(currentMusic[index].stream);
         }
+        
+        if(!getMusicStreamCount()) musicEnabled = false;
     }
+}
 
-    musicEnabled = false;
+//get number of music channels active at this time, this does not mean they are playing
+int getMusicStreamCount(void)
+{
+    int musicCount;
+    for(int musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++) // find empty music slot
+        if(currentMusic[musicIndex].stream != NULL || currentMusic[musicIndex].chipTune) musicCount++;
+        
+    return musicCount;
 }
 
 // Pause music playing
-void PauseMusicStream(void)
+void PauseMusicStream(int index)
 {
     // Pause music stream if music available!
     if (musicEnabled)
     {
         TraceLog(INFO, "Pausing music stream");
-        alSourcePause(currentMusic.source);
+        UpdateAudioContext(currentMusic[index].ctx, NULL, 0); // pushing null data auto pauses stream
         musicEnabled = false;
     }
 }
 
 // Resume music playing
-void ResumeMusicStream(void)
+void ResumeMusicStream(int index)
 {
     // Resume music playing... if music available!
     ALenum state;
-    alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
-
-    if (state == AL_PAUSED)
-    {
-        TraceLog(INFO, "Resuming music stream");
-        alSourcePlay(currentMusic.source);
-        musicEnabled = true;
+    if(currentMusic[musicIndex].ctx){
+        alGetSourcei(currentMusic[musicIndex].ctx->alSource, AL_SOURCE_STATE, &state);
+        if (state == AL_PAUSED)
+        {
+            TraceLog(INFO, "Resuming music stream");
+            alSourcePlay(currentMusic[musicIndex].ctx->alSource);
+            musicEnabled = true;
+        }
     }
 }
 
@@ -922,17 +896,24 @@ bool IsMusicPlaying(void)
 {
     bool playing = false;
     ALint state;
-
-    alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
-    if (state == AL_PLAYING) playing = true;
+    
+    for(int musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++)
+    {
+        if(currentMusic[musicIndex].ctx){
+            alGetSourcei(currentMusic[musicIndex].ctx->alSource, AL_SOURCE_STATE, &state);
+            if (state == AL_PLAYING) playing = true;
+        }
+    }
 
     return playing;
 }
 
 // Set volume for music
-void SetMusicVolume(float volume)
+void SetMusicVolume(int index, float volume)
 {
-    alSourcef(currentMusic.source, AL_GAIN, volume);
+    if(currentMusic[musicIndex].ctx){
+        alSourcef(currentMusic[musicIndex].ctx->alSource, AL_GAIN, volume);
+    }
 }
 
 // Get current music time length (in seconds)
diff --git a/src/audio.h b/src/audio.h
index afd881b71..a1602bd97 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -102,13 +102,14 @@ void SetSoundPitch(Sound sound, float pitch);                   // Set pitch for
 
 void PlayMusicStream(char *fileName);                           // Start music playing (open stream)
 void UpdateMusicStream(void);                                   // Updates buffers for music streaming
-void StopMusicStream(void);                                     // Stop music playing (close stream)
-void PauseMusicStream(void);                                    // Pause music playing
-void ResumeMusicStream(void);                                   // Resume playing paused music
+void StopMusicStream(int index);                                // Stop music playing (close stream)
+void PauseMusicStream(int index);                               // Pause music playing
+void ResumeMusicStream(int index);                              // Resume playing paused music
 bool IsMusicPlaying(void);                                      // Check if music is playing
-void SetMusicVolume(float volume);                              // Set volume for music (1.0 is max level)
+void SetMusicVolume(int index, float volume);                   // Set volume for music (1.0 is max level)
 float GetMusicTimeLength(void);                                 // Get music time length (in seconds)
 float GetMusicTimePlayed(void);                                 // Get current music time played (in seconds)
+int getMusicStreamCount(void);
 
 #ifdef __cplusplus
 }
diff --git a/src/raylib.h b/src/raylib.h
index d464c8e98..0c49a0852 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -893,13 +893,14 @@ void SetSoundPitch(Sound sound, float pitch);                   // Set pitch for
 
 void PlayMusicStream(char *fileName);                           // Start music playing (open stream)
 void UpdateMusicStream(void);                                   // Updates buffers for music streaming
-void StopMusicStream(void);                                     // Stop music playing (close stream)
-void PauseMusicStream(void);                                    // Pause music playing
-void ResumeMusicStream(void);                                   // Resume playing paused music
+void StopMusicStream(int index);                                // Stop music playing (close stream)
+void PauseMusicStream(int index);                               // Pause music playing
+void ResumeMusicStream(int index);                              // Resume playing paused music
 bool IsMusicPlaying(void);                                      // Check if music is playing
-void SetMusicVolume(float volume);                              // Set volume for music (1.0 is max level)
+void SetMusicVolume(int index, float volume);                   // Set volume for music (1.0 is max level)
 float GetMusicTimeLength(void);                                 // Get current music time length (in seconds)
 float GetMusicTimePlayed(void);                                 // Get current music time played (in seconds)
+int getMusicStreamCount(void);
 
 #ifdef __cplusplus
 }

From ad3d270c429844462f3fd62fa12257760fac24b5 Mon Sep 17 00:00:00 2001
From: Joshua Reisenauer <kd7tck@msn.com>
Date: Wed, 11 May 2016 18:14:59 -0700
Subject: [PATCH 02/33] added set pitch for music streams

---
 src/audio.c  | 40 ++++++++++++++++++++++------------------
 src/audio.h  |  3 ++-
 src/raylib.h |  3 ++-
 3 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/src/audio.c b/src/audio.c
index 39be4eebd..f89be8bf6 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -113,7 +113,7 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
 //----------------------------------------------------------------------------------
 static AudioContext_t* mixChannelsActive_g[MAX_AUDIO_CONTEXTS];      // What mix channels are currently active
 static bool musicEnabled = false;
-static Music currentMusic[2];                                        // Current music loaded, up to two can play at the same time
+static Music currentMusic[MAX_MUSIC_STREAMS];                        // Current music loaded, up to two can play at the same time
 
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
@@ -797,18 +797,18 @@ void PlayMusicStream(char *fileName)
             TraceLog(INFO, "[%s] Ogg channels: %i", fileName, info.channels);
             TraceLog(DEBUG, "[%s] Temp memory required: %i", fileName, info.temp_memory_required);
 
+            currentMusic[musicIndex].loop = true;                  // We loop by default
+            musicEnabled = true;
+
+            currentMusic[musicIndex].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[musicIndex].stream) * info.channels;
+            currentMusic[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[musicIndex].stream);
+            
             if (info.channels == 2){
                 currentMusic[musicIndex].ctx = InitAudioContext(info.sample_rate, mixIndex, 2, false);
             }
             else{
                 currentMusic[musicIndex].ctx = InitAudioContext(info.sample_rate, mixIndex, 1, false);
             }
-
-            currentMusic[musicIndex].loop = true;                  // We loop by default
-            musicEnabled = true;
-
-            currentMusic[musicIndex].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[musicIndex].stream) * currentMusic[musicIndex].channels;
-            currentMusic[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[musicIndex].stream);
         }
     }
     else if (strcmp(GetExtension(fileName),"xm") == 0)
@@ -820,7 +820,7 @@ void PlayMusicStream(char *fileName)
             currentMusic[musicIndex].loop = true;
             jar_xm_set_max_loop_count(currentMusic[musicIndex].chipctx, 0); // infinite number of loops
             currentMusic[musicIndex].totalSamplesLeft =  jar_xm_get_remaining_samples(currentMusic[musicIndex].chipctx);
-            currentMusic[musicIndex].totalLengthSeconds = ((float)currentMusic[musicIndex].totalSamplesLeft) / ((float)currentMusic[musicIndex].sampleRate);
+            currentMusic[musicIndex].totalLengthSeconds = ((float)currentMusic[musicIndex].totalSamplesLeft) / 48000.f;
             musicEnabled = true;
             
             TraceLog(INFO, "[%s] XM number of samples: %i", fileName, currentMusic[musicIndex].totalSamplesLeft);
@@ -891,18 +891,15 @@ void ResumeMusicStream(int index)
     }
 }
 
-// Check if music is playing
-bool IsMusicPlaying(void)
+// Check if any music is playing
+bool IsMusicPlaying(int index)
 {
     bool playing = false;
     ALint state;
     
-    for(int musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++)
-    {
-        if(currentMusic[musicIndex].ctx){
-            alGetSourcei(currentMusic[musicIndex].ctx->alSource, AL_SOURCE_STATE, &state);
-            if (state == AL_PLAYING) playing = true;
-        }
+    if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx){
+        alGetSourcei(currentMusic[index].ctx->alSource, AL_SOURCE_STATE, &state);
+        if (state == AL_PLAYING) playing = true;
     }
 
     return playing;
@@ -911,8 +908,15 @@ bool IsMusicPlaying(void)
 // Set volume for music
 void SetMusicVolume(int index, float volume)
 {
-    if(currentMusic[musicIndex].ctx){
-        alSourcef(currentMusic[musicIndex].ctx->alSource, AL_GAIN, volume);
+    if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx){
+        alSourcef(currentMusic[index].ctx->alSource, AL_GAIN, volume);
+    }
+}
+
+void SetMusicPitch(int index, float pitch)
+{
+    if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx){
+        alSourcef(currentMusic[index].ctx->alSource, AL_PITCH, pitch);
     }
 }
 
diff --git a/src/audio.h b/src/audio.h
index a1602bd97..fef85b4f6 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -105,11 +105,12 @@ void UpdateMusicStream(void);                                   // Updates buffe
 void StopMusicStream(int index);                                // Stop music playing (close stream)
 void PauseMusicStream(int index);                               // Pause music playing
 void ResumeMusicStream(int index);                              // Resume playing paused music
-bool IsMusicPlaying(void);                                      // Check if music is playing
+bool IsMusicPlaying(int index);                                 // Check if music is playing
 void SetMusicVolume(int index, float volume);                   // Set volume for music (1.0 is max level)
 float GetMusicTimeLength(void);                                 // Get music time length (in seconds)
 float GetMusicTimePlayed(void);                                 // Get current music time played (in seconds)
 int getMusicStreamCount(void);
+void SetMusicPitch(int index, float pitch);
 
 #ifdef __cplusplus
 }
diff --git a/src/raylib.h b/src/raylib.h
index 0c49a0852..b9390d31a 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -896,11 +896,12 @@ void UpdateMusicStream(void);                                   // Updates buffe
 void StopMusicStream(int index);                                // Stop music playing (close stream)
 void PauseMusicStream(int index);                               // Pause music playing
 void ResumeMusicStream(int index);                              // Resume playing paused music
-bool IsMusicPlaying(void);                                      // Check if music is playing
+bool IsMusicPlaying(int index);                                 // Check if music is playing
 void SetMusicVolume(int index, float volume);                   // Set volume for music (1.0 is max level)
 float GetMusicTimeLength(void);                                 // Get current music time length (in seconds)
 float GetMusicTimePlayed(void);                                 // Get current music time played (in seconds)
 int getMusicStreamCount(void);
+void SetMusicPitch(int index, float pitch);
 
 #ifdef __cplusplus
 }

From 9737c58054d5d0cc636fca0c998b31a69d501970 Mon Sep 17 00:00:00 2001
From: Joshua Reisenauer <kd7tck@msn.com>
Date: Wed, 11 May 2016 20:15:37 -0700
Subject: [PATCH 03/33] PlayMusicStream now uses index

---
 src/audio.c  | 29 +++++++++++++++++++----------
 src/audio.h  |  2 +-
 src/raylib.h |  2 +-
 3 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/src/audio.c b/src/audio.c
index f89be8bf6..6a8d251ef 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -763,19 +763,18 @@ void SetSoundPitch(Sound sound, float pitch)
 //----------------------------------------------------------------------------------
 
 // Start music playing (open stream)
-void PlayMusicStream(char *fileName)
+// returns 0 on success
+int PlayMusicStream(int musicIndex, char *fileName)
 {
-    int musicIndex;
+    int musicIndex = index;
     int mixIndex;
-    for(musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++) // find empty music slot
-    {
-        if(currentMusic[musicIndex].stream == NULL && !currentMusic[musicIndex].chipTune) break;
-        else if(musicIndex = MAX_MUSIC_STREAMS - 1) return;
-    }
+    
+    if(currentMusic[musicIndex].stream != NULL || currentMusic[musicIndex].chipTune) return 1; // error
+    
     for(mixIndex = 0; mixIndex < MAX_AUDIO_CONTEXTS; mixIndex++) // find empty mix channel slot
     {
         if(mixChannelsActive_g[mixIndex] == NULL) break;
-        else if(musicIndex = MAX_AUDIO_CONTEXTS - 1) return;
+        else if(musicIndex = MAX_AUDIO_CONTEXTS - 1) return 2; // error
     }
     
     
@@ -787,6 +786,7 @@ void PlayMusicStream(char *fileName)
         if (currentMusic[musicIndex].stream == NULL)
         {
             TraceLog(WARNING, "[%s] OGG audio file could not be opened", fileName);
+            return 3; // error
         }
         else
         {
@@ -828,9 +828,18 @@ void PlayMusicStream(char *fileName)
             
             currentMusic[musicIndex].ctx = InitAudioContext(48000, mixIndex, 2, true);
         }
-        else TraceLog(WARNING, "[%s] XM file could not be opened", fileName);
+        else
+        {
+            TraceLog(WARNING, "[%s] XM file could not be opened", fileName);
+            return 4; // error
+        }
+    }
+    else
+    {
+        TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName);
+        return 5; // error
     }
-    else TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName);
+    return 0; // normal return
 }
 
 // Stop music playing for individual music index of currentMusic array (close stream)
diff --git a/src/audio.h b/src/audio.h
index fef85b4f6..d09c4accf 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -100,7 +100,7 @@ bool IsSoundPlaying(Sound sound);                               // Check if a so
 void SetSoundVolume(Sound sound, float volume);                 // Set volume for a sound (1.0 is max level)
 void SetSoundPitch(Sound sound, float pitch);                   // Set pitch for a sound (1.0 is base level)
 
-void PlayMusicStream(char *fileName);                           // Start music playing (open stream)
+int PlayMusicStream(int musicIndex, char *fileName);            // Start music playing (open stream)
 void UpdateMusicStream(void);                                   // Updates buffers for music streaming
 void StopMusicStream(int index);                                // Stop music playing (close stream)
 void PauseMusicStream(int index);                               // Pause music playing
diff --git a/src/raylib.h b/src/raylib.h
index a65079064..cb17aa78a 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -894,7 +894,7 @@ bool IsSoundPlaying(Sound sound);                               // Check if a so
 void SetSoundVolume(Sound sound, float volume);                 // Set volume for a sound (1.0 is max level)
 void SetSoundPitch(Sound sound, float pitch);                   // Set pitch for a sound (1.0 is base level)
 
-void PlayMusicStream(char *fileName);                           // Start music playing (open stream)
+int PlayMusicStream(int musicIndex, char *fileName);            // Start music playing (open stream)
 void UpdateMusicStream(void);                                   // Updates buffers for music streaming
 void StopMusicStream(int index);                                // Stop music playing (close stream)
 void PauseMusicStream(int index);                               // Pause music playing

From f0ada8c40d7887654d05c62f980a0a5473c1d8a7 Mon Sep 17 00:00:00 2001
From: Joshua Reisenauer <kd7tck@msn.com>
Date: Wed, 11 May 2016 22:37:53 -0700
Subject: [PATCH 04/33] apply index to remaining functions

---
 src/audio.c  | 108 ++++++++++++++++++++++++++-------------------------
 src/audio.h  |   6 +--
 src/raylib.h |   6 +--
 3 files changed, 62 insertions(+), 58 deletions(-)

diff --git a/src/audio.c b/src/audio.c
index 6a8d251ef..947295669 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -118,12 +118,12 @@ static Music currentMusic[MAX_MUSIC_STREAMS];                        // Current
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
 //----------------------------------------------------------------------------------
-static Wave LoadWAV(const char *fileName);          // Load WAV file
-static Wave LoadOGG(char *fileName);                // Load OGG file
-static void UnloadWave(Wave wave);                  // Unload wave data
+static Wave LoadWAV(const char *fileName);                // Load WAV file
+static Wave LoadOGG(char *fileName);                      // Load OGG file
+static void UnloadWave(Wave wave);                        // Unload wave data
 
-static bool BufferMusicStream(ALuint buffer);       // Fill music buffers with data
-static void EmptyMusicStream(void);                 // Empty music buffers
+static bool BufferMusicStream(int index, ALuint buffer);  // Fill music buffers with data
+static void EmptyMusicStream(int index);                  // Empty music buffers
 
 static unsigned short FillAlBufferWithSilence(AudioContext_t *context, ALuint buffer);// fill buffer with zeros, returns number processed
 static void ResampleShortToFloat(short *shorts, float *floats, unsigned short len); // pass two arrays of the same legnth in
@@ -766,7 +766,6 @@ void SetSoundPitch(Sound sound, float pitch)
 // returns 0 on success
 int PlayMusicStream(int musicIndex, char *fileName)
 {
-    int musicIndex = index;
     int mixIndex;
     
     if(currentMusic[musicIndex].stream != NULL || currentMusic[musicIndex].chipTune) return 1; // error
@@ -930,36 +929,36 @@ void SetMusicPitch(int index, float pitch)
 }
 
 // Get current music time length (in seconds)
-float GetMusicTimeLength(void)
+float GetMusicTimeLength(int index)
 {
     float totalSeconds;
-    if (currentMusic.chipTune)
+    if (currentMusic[index].chipTune)
     {
-        totalSeconds = currentMusic.totalLengthSeconds;
+        totalSeconds = currentMusic[index].totalLengthSeconds;
     }
     else
     {
-        totalSeconds = stb_vorbis_stream_length_in_seconds(currentMusic.stream);
+        totalSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[index].stream);
     }
 
     return totalSeconds;
 }
 
 // Get current music time played (in seconds)
-float GetMusicTimePlayed(void)
+float GetMusicTimePlayed(int index)
 {
     float secondsPlayed;
-    if (currentMusic.chipTune)
+    if (currentMusic[index].chipTune)
     {
         uint64_t samples;
-        jar_xm_get_position(currentMusic.chipctx, NULL, NULL, NULL, &samples);
-        secondsPlayed = (float)samples / (currentMusic.sampleRate * currentMusic.channels); // Not sure if this is the correct value
+        jar_xm_get_position(currentMusic[index].chipctx, NULL, NULL, NULL, &samples);
+        secondsPlayed = (float)samples / (48000 * currentMusic[index].ctx->channels); // Not sure if this is the correct value
     }
     else
     {
-        int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels;
-        int samplesPlayed = totalSamples - currentMusic.totalSamplesLeft;
-        secondsPlayed = (float)samplesPlayed / (currentMusic.sampleRate * currentMusic.channels);
+        int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].ctx->channels;
+        int samplesPlayed = totalSamples - currentMusic[index].totalSamplesLeft;
+        secondsPlayed = (float)samplesPlayed / (currentMusic[index].ctx->sampleRate * currentMusic[index].ctx->channels);
     }
     
 
@@ -971,9 +970,10 @@ float GetMusicTimePlayed(void)
 //----------------------------------------------------------------------------------
 
 // Fill music buffers with new data from music stream
-static bool BufferMusicStream(ALuint buffer)
+static bool BufferMusicStream(int index, ALuint buffer)
 {
     short pcm[MUSIC_BUFFER_SIZE_SHORT];
+    float pcmf[MUSIC_BUFFER_SIZE_FLOAT];
     
     int  size = 0;              // Total size of data steamed (in bytes)
     int  streamedBytes = 0;     // samples of data obtained, channels are not included in calculation
@@ -981,93 +981,97 @@ static bool BufferMusicStream(ALuint buffer)
 
     if (musicEnabled)
     {
-        if (currentMusic.chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes.
+        if (currentMusic[index].chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes.
         {
-            int readlen = MUSIC_BUFFER_SIZE_SHORT / 2;
-            jar_xm_generate_samples_16bit(currentMusic.chipctx, pcm, readlen); // reads 2*readlen shorts and moves them to buffer+size memory location
-            size += readlen * currentMusic.channels; // Not sure if this is what it needs
+            int readlen = MUSIC_BUFFER_SIZE_FLOAT / 2;
+            jar_xm_generate_samples(currentMusic[index].chipctx, pcmf, readlen); // reads 2*readlen shorts and moves them to buffer+size memory location
+            size += readlen * currentMusic[index].ctx->channels; // Not sure if this is what it needs
+            
+            alBufferData(buffer, currentMusic[index].ctx->alFormat, pcmf, size*sizeof(float), 48000);
+            currentMusic[index].totalSamplesLeft -= size;
+            if(currentMusic[index].totalSamplesLeft <= 0) active = false;
         }
         else
         {
             while (size < MUSIC_BUFFER_SIZE_SHORT)
             {
-                streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic.stream, currentMusic.channels, pcm + size, MUSIC_BUFFER_SIZE_SHORT - size);
-                if (streamedBytes > 0) size += (streamedBytes*currentMusic.channels);
+                streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic[index].stream, currentMusic[index].ctx->channels, pcm + size, MUSIC_BUFFER_SIZE_SHORT - size);
+                if (streamedBytes > 0) size += (streamedBytes*currentMusic[index].ctx->channels);
                 else break;
             }
+            
+            if (size > 0)
+            {
+                alBufferData(buffer, currentMusic[index].ctx->alFormat, pcm, size*sizeof(short), currentMusic[index].ctx->sampleRate);
+                currentMusic[index].totalSamplesLeft -= size;
+                
+                if(currentMusic[index].totalSamplesLeft <= 0) active = false; // end if no more samples left
+            }
+            else
+            {
+                active = false;
+                TraceLog(WARNING, "No more data obtained from stream");
+            }
         }
         TraceLog(DEBUG, "Streaming music data to buffer. Bytes streamed: %i", size);
     }
 
-    if (size > 0)
-    {
-        alBufferData(buffer, currentMusic.format, pcm, size*sizeof(short), currentMusic.sampleRate);
-        currentMusic.totalSamplesLeft -= size;
-        
-        if(currentMusic.totalSamplesLeft <= 0) active = false; // end if no more samples left
-    }
-    else
-    {
-        active = false;
-        TraceLog(WARNING, "No more data obtained from stream");
-    }
-
     return active;
 }
 
 // Empty music buffers
-static void EmptyMusicStream(void)
+static void EmptyMusicStream(int index)
 {
     ALuint buffer = 0;
     int queued = 0;
 
-    alGetSourcei(currentMusic.source, AL_BUFFERS_QUEUED, &queued);
+    alGetSourcei(currentMusic[index].source, AL_BUFFERS_QUEUED, &queued);
 
     while (queued > 0)
     {
-        alSourceUnqueueBuffers(currentMusic.source, 1, &buffer);
+        alSourceUnqueueBuffers(currentMusic[index].source, 1, &buffer);
 
         queued--;
     }
 }
 
 // Update (re-fill) music buffers if data already processed
-void UpdateMusicStream(void)
+void UpdateMusicStream(int index)
 {
     ALuint buffer = 0;
     ALint processed = 0;
     bool active = true;
 
-    if (musicEnabled)
+    if (index < MAX_MUSIC_STREAMS && musicEnabled)
     {
         // Get the number of already processed buffers (if any)
-        alGetSourcei(currentMusic.source, AL_BUFFERS_PROCESSED, &processed);
+        alGetSourcei(currentMusic[index].source, AL_BUFFERS_PROCESSED, &processed);
 
         while (processed > 0)
         {
             // Recover processed buffer for refill
-            alSourceUnqueueBuffers(currentMusic.source, 1, &buffer);
+            alSourceUnqueueBuffers(currentMusic[index].source, 1, &buffer);
 
             // Refill buffer
             active = BufferMusicStream(buffer);
 
             // If no more data to stream, restart music (if loop)
-            if ((!active) && (currentMusic.loop))
+            if ((!active) && (currentMusic[index].loop))
             {
-                if(currentMusic.chipTune)
+                if(currentMusic[index].chipTune)
                 {
-                    currentMusic.totalSamplesLeft = currentMusic.totalLengthSeconds * currentMusic.sampleRate;
+                    currentMusic[index].totalSamplesLeft = currentMusic[index].totalLengthSeconds * currentMusic[index].ctx->sampleRate;
                 }
                 else
                 {
-                    stb_vorbis_seek_start(currentMusic.stream);
-                    currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream)*currentMusic.channels;
+                    stb_vorbis_seek_start(currentMusic[index].stream);
+                    currentMusic[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[index].stream)*currentMusic[index].ctx->channels;
                 }
                 active = BufferMusicStream(buffer);
             }
 
             // Add refilled buffer to queue again... don't let the music stop!
-            alSourceQueueBuffers(currentMusic.source, 1, &buffer);
+            alSourceQueueBuffers(currentMusic[index].source, 1, &buffer);
 
             if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data...");
 
@@ -1075,9 +1079,9 @@ void UpdateMusicStream(void)
         }
 
         ALenum state;
-        alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
+        alGetSourcei(currentMusic[index].source, AL_SOURCE_STATE, &state);
 
-        if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic.source);
+        if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic[index].source);
 
         if (!active) StopMusicStream();
     }
diff --git a/src/audio.h b/src/audio.h
index d09c4accf..63c1c1365 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -101,14 +101,14 @@ void SetSoundVolume(Sound sound, float volume);                 // Set volume fo
 void SetSoundPitch(Sound sound, float pitch);                   // Set pitch for a sound (1.0 is base level)
 
 int PlayMusicStream(int musicIndex, char *fileName);            // Start music playing (open stream)
-void UpdateMusicStream(void);                                   // Updates buffers for music streaming
+void UpdateMusicStream(int index);                              // Updates buffers for music streaming
 void StopMusicStream(int index);                                // Stop music playing (close stream)
 void PauseMusicStream(int index);                               // Pause music playing
 void ResumeMusicStream(int index);                              // Resume playing paused music
 bool IsMusicPlaying(int index);                                 // Check if music is playing
 void SetMusicVolume(int index, float volume);                   // Set volume for music (1.0 is max level)
-float GetMusicTimeLength(void);                                 // Get music time length (in seconds)
-float GetMusicTimePlayed(void);                                 // Get current music time played (in seconds)
+float GetMusicTimeLength(int index);                            // Get music time length (in seconds)
+float GetMusicTimePlayed(int index);                            // Get current music time played (in seconds)
 int getMusicStreamCount(void);
 void SetMusicPitch(int index, float pitch);
 
diff --git a/src/raylib.h b/src/raylib.h
index cb17aa78a..05c945f73 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -895,14 +895,14 @@ void SetSoundVolume(Sound sound, float volume);                 // Set volume fo
 void SetSoundPitch(Sound sound, float pitch);                   // Set pitch for a sound (1.0 is base level)
 
 int PlayMusicStream(int musicIndex, char *fileName);            // Start music playing (open stream)
-void UpdateMusicStream(void);                                   // Updates buffers for music streaming
+void UpdateMusicStream(int index);                              // Updates buffers for music streaming
 void StopMusicStream(int index);                                // Stop music playing (close stream)
 void PauseMusicStream(int index);                               // Pause music playing
 void ResumeMusicStream(int index);                              // Resume playing paused music
 bool IsMusicPlaying(int index);                                 // Check if music is playing
 void SetMusicVolume(int index, float volume);                   // Set volume for music (1.0 is max level)
-float GetMusicTimeLength(void);                                 // Get current music time length (in seconds)
-float GetMusicTimePlayed(void);                                 // Get current music time played (in seconds)
+float GetMusicTimeLength(int index);                            // Get current music time length (in seconds)
+float GetMusicTimePlayed(int index);                            // Get current music time played (in seconds)
 int getMusicStreamCount(void);
 void SetMusicPitch(int index, float pitch);
 

From 83dbc076507b7025aa0a1315e409ff46f75c1e0b Mon Sep 17 00:00:00 2001
From: Joshua Reisenauer <kd7tck@msn.com>
Date: Thu, 12 May 2016 16:02:23 -0700
Subject: [PATCH 05/33] buffering of music now uses update audio context

---
 src/audio.c   | 94 ++++++++++++++++++---------------------------------
 src/easings.h | 10 +++---
 2 files changed, 37 insertions(+), 67 deletions(-)

diff --git a/src/audio.c b/src/audio.c
index 947295669..cc964cd18 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -118,12 +118,12 @@ static Music currentMusic[MAX_MUSIC_STREAMS];                        // Current
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
 //----------------------------------------------------------------------------------
-static Wave LoadWAV(const char *fileName);                // Load WAV file
-static Wave LoadOGG(char *fileName);                      // Load OGG file
-static void UnloadWave(Wave wave);                        // Unload wave data
+static Wave LoadWAV(const char *fileName);         // Load WAV file
+static Wave LoadOGG(char *fileName);               // Load OGG file
+static void UnloadWave(Wave wave);                 // Unload wave data
 
-static bool BufferMusicStream(int index, ALuint buffer);  // Fill music buffers with data
-static void EmptyMusicStream(int index);                  // Empty music buffers
+static bool BufferMusicStream(int index);          // Fill music buffers with data
+static void EmptyMusicStream(int index);           // Empty music buffers
 
 static unsigned short FillAlBufferWithSilence(AudioContext_t *context, ALuint buffer);// fill buffer with zeros, returns number processed
 static void ResampleShortToFloat(short *shorts, float *floats, unsigned short len); // pass two arrays of the same legnth in
@@ -970,7 +970,7 @@ float GetMusicTimePlayed(int index)
 //----------------------------------------------------------------------------------
 
 // Fill music buffers with new data from music stream
-static bool BufferMusicStream(int index, ALuint buffer)
+static bool BufferMusicStream(int index)
 {
     short pcm[MUSIC_BUFFER_SIZE_SHORT];
     float pcmf[MUSIC_BUFFER_SIZE_FLOAT];
@@ -985,33 +985,17 @@ static bool BufferMusicStream(int index, ALuint buffer)
         {
             int readlen = MUSIC_BUFFER_SIZE_FLOAT / 2;
             jar_xm_generate_samples(currentMusic[index].chipctx, pcmf, readlen); // reads 2*readlen shorts and moves them to buffer+size memory location
+            UpdateAudioContext(currentMusic[index].ctx, pcmf, MUSIC_BUFFER_SIZE_FLOAT);
             size += readlen * currentMusic[index].ctx->channels; // Not sure if this is what it needs
-            
-            alBufferData(buffer, currentMusic[index].ctx->alFormat, pcmf, size*sizeof(float), 48000);
             currentMusic[index].totalSamplesLeft -= size;
             if(currentMusic[index].totalSamplesLeft <= 0) active = false;
         }
         else
         {
-            while (size < MUSIC_BUFFER_SIZE_SHORT)
-            {
-                streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic[index].stream, currentMusic[index].ctx->channels, pcm + size, MUSIC_BUFFER_SIZE_SHORT - size);
-                if (streamedBytes > 0) size += (streamedBytes*currentMusic[index].ctx->channels);
-                else break;
-            }
-            
-            if (size > 0)
-            {
-                alBufferData(buffer, currentMusic[index].ctx->alFormat, pcm, size*sizeof(short), currentMusic[index].ctx->sampleRate);
-                currentMusic[index].totalSamplesLeft -= size;
-                
-                if(currentMusic[index].totalSamplesLeft <= 0) active = false; // end if no more samples left
-            }
-            else
-            {
-                active = false;
-                TraceLog(WARNING, "No more data obtained from stream");
-            }
+            streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic[index].stream, currentMusic[index].ctx->channels, pcm, MUSIC_BUFFER_SIZE_SHORT);
+            UpdateAudioContext(currentMusic[index].ctx, pcm, MUSIC_BUFFER_SIZE_SHORT);
+            currentMusic[index].totalSamplesLeft -= MUSIC_BUFFER_SIZE_SHORT;
+            if(currentMusic[index].totalSamplesLeft <= 0) active = false;
         }
         TraceLog(DEBUG, "Streaming music data to buffer. Bytes streamed: %i", size);
     }
@@ -1038,53 +1022,39 @@ static void EmptyMusicStream(int index)
 // Update (re-fill) music buffers if data already processed
 void UpdateMusicStream(int index)
 {
-    ALuint buffer = 0;
-    ALint processed = 0;
+    ALenum state;
     bool active = true;
 
     if (index < MAX_MUSIC_STREAMS && musicEnabled)
     {
-        // Get the number of already processed buffers (if any)
-        alGetSourcei(currentMusic[index].source, AL_BUFFERS_PROCESSED, &processed);
-
-        while (processed > 0)
+        active = BufferMusicStream(index);
+        
+        if ((!active) && (currentMusic[index].loop))
         {
-            // Recover processed buffer for refill
-            alSourceUnqueueBuffers(currentMusic[index].source, 1, &buffer);
-
-            // Refill buffer
-            active = BufferMusicStream(buffer);
-
-            // If no more data to stream, restart music (if loop)
-            if ((!active) && (currentMusic[index].loop))
+            if(currentMusic[index].chipTune)
             {
-                if(currentMusic[index].chipTune)
-                {
-                    currentMusic[index].totalSamplesLeft = currentMusic[index].totalLengthSeconds * currentMusic[index].ctx->sampleRate;
-                }
-                else
-                {
-                    stb_vorbis_seek_start(currentMusic[index].stream);
-                    currentMusic[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[index].stream)*currentMusic[index].ctx->channels;
-                }
-                active = BufferMusicStream(buffer);
+                currentMusic[index].totalSamplesLeft = currentMusic[index].totalLengthSeconds * currentMusic[index].ctx->sampleRate;
             }
+            else
+            {
+                stb_vorbis_seek_start(currentMusic[index].stream);
+                currentMusic[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[index].stream)*currentMusic[index].ctx->channels;
+            }
+            active = BufferMusicStream(index);
+        }
+        
 
-            // Add refilled buffer to queue again... don't let the music stop!
-            alSourceQueueBuffers(currentMusic[index].source, 1, &buffer);
-
-            if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data...");
+        if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data...");
 
-            processed--;
-        }
+        processed--;
+    }
 
-        ALenum state;
-        alGetSourcei(currentMusic[index].source, AL_SOURCE_STATE, &state);
+    
+    alGetSourcei(currentMusic[index].source, AL_SOURCE_STATE, &state);
 
-        if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic[index].source);
+    if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic[index].source);
 
-        if (!active) StopMusicStream();
-    }
+    if (!active) StopMusicStream();
 }
 
 // Load WAV file into Wave structure
diff --git a/src/easings.h b/src/easings.h
index e1e5465a6..a8178f4a3 100644
--- a/src/easings.h
+++ b/src/easings.h
@@ -18,11 +18,11 @@
 *   float speed = 1.f;
 *   float currentTime = 0.f;
 *   float currentPos[2] = {0,0};
-*   float newPos[2] = {1,1};
-*   float tempPosition[2] = currentPos;//x,y positions
-*   while(currentPos[0] < newPos[0])
-*       currentPos[0] = EaseSineIn(currentTime, tempPosition[0], tempPosition[0]-newPos[0], speed);
-*       currentPos[1] = EaseSineIn(currentTime, tempPosition[1], tempPosition[1]-newPos[0], speed);
+*   float finalPos[2] = {1,1};
+*   float startPosition[2] = currentPos;//x,y positions
+*   while(currentPos[0] < finalPos[0])
+*       currentPos[0] = EaseSineIn(currentTime, startPosition[0], startPosition[0]-finalPos[0], speed);
+*       currentPos[1] = EaseSineIn(currentTime, startPosition[1], startPosition[1]-finalPos[0], speed);
 *       currentTime += diffTime();
 *
 *   A port of Robert Penner's easing equations to C (http://robertpenner.com/easing/)

From 5107a2dc40330623f61205ee70f067d24afb0af8 Mon Sep 17 00:00:00 2001
From: Joshua Reisenauer <kd7tck@msn.com>
Date: Thu, 12 May 2016 21:14:02 -0700
Subject: [PATCH 06/33] bug fixes

---
 src/audio.c | 69 +++++++++++++++++++++++++++--------------------------
 1 file changed, 35 insertions(+), 34 deletions(-)

diff --git a/src/audio.c b/src/audio.c
index cc964cd18..d19d33068 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -77,19 +77,6 @@
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
 
-// Music type (file streaming from memory)
-// NOTE: Anything longer than ~10 seconds should be streamed...
-typedef struct Music {
-    stb_vorbis *stream;
-    jar_xm_context_t *chipctx; // Stores jar_xm context
-    AudioContext_t *ctx; // audio context
-    
-    int totalSamplesLeft;
-    float totalLengthSeconds;
-    bool loop;
-    bool chipTune; // True if chiptune is loaded
-} Music;
-
 // Audio Context, used to create custom audio streams that are not bound to a sound file. There can be
 // no more than 4 concurrent audio contexts in use. This is due to each active context being tied to
 // a dedicated mix channel. All audio is 32bit floating point in stereo.
@@ -104,6 +91,19 @@ typedef struct AudioContext_t {
     ALuint alBuffer[MAX_STREAM_BUFFERS]; // openAL sample buffer
 } AudioContext_t;
 
+// Music type (file streaming from memory)
+// NOTE: Anything longer than ~10 seconds should be streamed...
+typedef struct Music {
+    stb_vorbis *stream;
+    jar_xm_context_t *chipctx; // Stores jar_xm context
+    AudioContext_t *ctx; // audio context
+    
+    int totalSamplesLeft;
+    float totalLengthSeconds;
+    bool loop;
+    bool chipTune; // True if chiptune is loaded
+} Music;
+
 #if defined(AUDIO_STANDALONE)
 typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
 #endif
@@ -168,7 +168,10 @@ void InitAudioDevice(void)
 // Close the audio device for the current context, and destroys the context
 void CloseAudioDevice(void)
 {
-    StopMusicStream();      // Stop music streaming and close current stream
+    for(int index=0; index<MAX_MUSIC_STREAMS; index++)
+    {
+        if(currentMusic[index].ctx) StopMusicStream(index);      // Stop music streaming and close current stream
+    }
 
     ALCdevice *device;
     ALCcontext *context = alcGetCurrentContext();
@@ -205,7 +208,6 @@ AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChanne
 {
     if(mixChannel >= MAX_AUDIO_CONTEXTS) return NULL;
     if(!IsAudioDeviceReady()) InitAudioDevice();
-    else StopMusicStream();
     
     if(!mixChannelsActive_g[mixChannel]){
         AudioContext_t *ac = (AudioContext_t*)malloc(sizeof(AudioContext_t));
@@ -776,7 +778,6 @@ int PlayMusicStream(int musicIndex, char *fileName)
         else if(musicIndex = MAX_AUDIO_CONTEXTS - 1) return 2; // error
     }
     
-    
     if (strcmp(GetExtension(fileName),"ogg") == 0)
     {
         // Open audio stream
@@ -888,12 +889,12 @@ void ResumeMusicStream(int index)
 {
     // Resume music playing... if music available!
     ALenum state;
-    if(currentMusic[musicIndex].ctx){
-        alGetSourcei(currentMusic[musicIndex].ctx->alSource, AL_SOURCE_STATE, &state);
+    if(currentMusic[index].ctx){
+        alGetSourcei(currentMusic[index].ctx->alSource, AL_SOURCE_STATE, &state);
         if (state == AL_PAUSED)
         {
             TraceLog(INFO, "Resuming music stream");
-            alSourcePlay(currentMusic[musicIndex].ctx->alSource);
+            alSourcePlay(currentMusic[index].ctx->alSource);
             musicEnabled = true;
         }
     }
@@ -976,9 +977,8 @@ static bool BufferMusicStream(int index)
     float pcmf[MUSIC_BUFFER_SIZE_FLOAT];
     
     int  size = 0;              // Total size of data steamed (in bytes)
-    int  streamedBytes = 0;     // samples of data obtained, channels are not included in calculation
     bool active = true;         // We can get more data from stream (not finished)
-
+        
     if (musicEnabled)
     {
         if (currentMusic[index].chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes.
@@ -992,12 +992,12 @@ static bool BufferMusicStream(int index)
         }
         else
         {
-            streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic[index].stream, currentMusic[index].ctx->channels, pcm, MUSIC_BUFFER_SIZE_SHORT);
-            UpdateAudioContext(currentMusic[index].ctx, pcm, MUSIC_BUFFER_SIZE_SHORT);
-            currentMusic[index].totalSamplesLeft -= MUSIC_BUFFER_SIZE_SHORT;
+            int streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic[index].stream, currentMusic[index].ctx->channels, pcm, MUSIC_BUFFER_SIZE_SHORT);
+            UpdateAudioContext(currentMusic[index].ctx, pcm, streamedBytes);
+            currentMusic[index].totalSamplesLeft -= streamedBytes*currentMusic[index].ctx->channels;
             if(currentMusic[index].totalSamplesLeft <= 0) active = false;
         }
-        TraceLog(DEBUG, "Streaming music data to buffer. Bytes streamed: %i", size);
+        // TraceLog(DEBUG, "Streaming music data to buffer. Bytes streamed: %i", size);
     }
 
     return active;
@@ -1009,11 +1009,11 @@ static void EmptyMusicStream(int index)
     ALuint buffer = 0;
     int queued = 0;
 
-    alGetSourcei(currentMusic[index].source, AL_BUFFERS_QUEUED, &queued);
+    alGetSourcei(currentMusic[index].ctx->alSource, AL_BUFFERS_QUEUED, &queued);
 
     while (queued > 0)
     {
-        alSourceUnqueueBuffers(currentMusic[index].source, 1, &buffer);
+        alSourceUnqueueBuffers(currentMusic[index].ctx->alSource, 1, &buffer);
 
         queued--;
     }
@@ -1045,16 +1045,17 @@ void UpdateMusicStream(int index)
         
 
         if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data...");
+        
+        alGetSourcei(currentMusic[index].ctx->alSource, AL_SOURCE_STATE, &state);
 
-        processed--;
-    }
-
-    
-    alGetSourcei(currentMusic[index].source, AL_SOURCE_STATE, &state);
+        if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic[index].ctx->alSource);
 
-    if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic[index].source);
+        if (!active) StopMusicStream(index);
+        
+    }
+    else
+        return;
 
-    if (!active) StopMusicStream();
 }
 
 // Load WAV file into Wave structure

From ea4b5552c2b4ff8a907dd1fefc084317187af168 Mon Sep 17 00:00:00 2001
From: Joshua Reisenauer <kd7tck@msn.com>
Date: Sat, 14 May 2016 00:25:40 -0700
Subject: [PATCH 07/33] corrected typos

---
 src/audio.c | 42 +++++++++++++++++++++++++++---------------
 1 file changed, 27 insertions(+), 15 deletions(-)

diff --git a/src/audio.c b/src/audio.c
index d19d33068..c53d63187 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -85,7 +85,7 @@ typedef struct AudioContext_t {
     unsigned char channels;              // 1=mono,2=stereo
     unsigned char mixChannel;            // 0-3 or mixA-mixD, each mix channel can receive up to one dedicated audio stream
     bool floatingPoint;                  // if false then the short datatype is used instead
-    bool playing;
+    bool playing;                        // false if paused
     ALenum alFormat;                     // openAL format specifier
     ALuint alSource;                     // openAL source
     ALuint alBuffer[MAX_STREAM_BUFFERS]; // openAL sample buffer
@@ -165,13 +165,14 @@ void InitAudioDevice(void)
     alListener3f(AL_ORIENTATION, 0, 0, -1);
 }
 
-// Close the audio device for the current context, and destroys the context
+// Close the audio device for all contexts
 void CloseAudioDevice(void)
 {
     for(int index=0; index<MAX_MUSIC_STREAMS; index++)
     {
         if(currentMusic[index].ctx) StopMusicStream(index);      // Stop music streaming and close current stream
     }
+    
 
     ALCdevice *device;
     ALCcontext *context = alcGetCurrentContext();
@@ -770,12 +771,12 @@ int PlayMusicStream(int musicIndex, char *fileName)
 {
     int mixIndex;
     
-    if(currentMusic[musicIndex].stream != NULL || currentMusic[musicIndex].chipTune) return 1; // error
+    if(currentMusic[musicIndex].stream || currentMusic[musicIndex].chipctx) return 1; // error
     
     for(mixIndex = 0; mixIndex < MAX_AUDIO_CONTEXTS; mixIndex++) // find empty mix channel slot
     {
         if(mixChannelsActive_g[mixIndex] == NULL) break;
-        else if(musicIndex = MAX_AUDIO_CONTEXTS - 1) return 2; // error
+        else if(mixIndex = MAX_AUDIO_CONTEXTS - 1) return 2; // error
     }
     
     if (strcmp(GetExtension(fileName),"ogg") == 0)
@@ -799,6 +800,7 @@ int PlayMusicStream(int musicIndex, char *fileName)
 
             currentMusic[musicIndex].loop = true;                  // We loop by default
             musicEnabled = true;
+            currentMusic[musicIndex].ctx->playing = true;
 
             currentMusic[musicIndex].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[musicIndex].stream) * info.channels;
             currentMusic[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[musicIndex].stream);
@@ -822,6 +824,7 @@ int PlayMusicStream(int musicIndex, char *fileName)
             currentMusic[musicIndex].totalSamplesLeft =  jar_xm_get_remaining_samples(currentMusic[musicIndex].chipctx);
             currentMusic[musicIndex].totalLengthSeconds = ((float)currentMusic[musicIndex].totalSamplesLeft) / 48000.f;
             musicEnabled = true;
+            currentMusic[musicIndex].ctx->playing = true;
             
             TraceLog(INFO, "[%s] XM number of samples: %i", fileName, currentMusic[musicIndex].totalSamplesLeft);
             TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, currentMusic[musicIndex].totalLengthSeconds);
@@ -859,16 +862,21 @@ void StopMusicStream(int index)
         }
         
         if(!getMusicStreamCount()) musicEnabled = false;
+        if(currentMusic[index].stream || currentMusic[index].chipctx)
+        {
+            currentMusic[index].stream = NULL;
+            currentMusic[index].chipctx = NULL;
+        }
     }
 }
 
 //get number of music channels active at this time, this does not mean they are playing
 int getMusicStreamCount(void)
 {
-    int musicCount;
+    int musicCount = 0;
     for(int musicIndex = 0; musicIndex < MAX_MUSIC_STREAMS; musicIndex++) // find empty music slot
         if(currentMusic[musicIndex].stream != NULL || currentMusic[musicIndex].chipTune) musicCount++;
-        
+    
     return musicCount;
 }
 
@@ -876,11 +884,11 @@ int getMusicStreamCount(void)
 void PauseMusicStream(int index)
 {
     // Pause music stream if music available!
-    if (musicEnabled)
+    if (currentMusic[index].ctx && musicEnabled)
     {
         TraceLog(INFO, "Pausing music stream");
-        UpdateAudioContext(currentMusic[index].ctx, NULL, 0); // pushing null data auto pauses stream
-        musicEnabled = false;
+        alSourcePause(currentMusic[index].ctx->alSource);
+        currentMusic[index].ctx->playing = false;
     }
 }
 
@@ -895,7 +903,7 @@ void ResumeMusicStream(int index)
         {
             TraceLog(INFO, "Resuming music stream");
             alSourcePlay(currentMusic[index].ctx->alSource);
-            musicEnabled = true;
+            currentMusic[index].ctx->playing = true;
         }
     }
 }
@@ -981,13 +989,17 @@ static bool BufferMusicStream(int index)
         
     if (musicEnabled)
     {
+        if(!currentMusic[index].ctx->playing)
+        {
+            UpdateAudioContext(currentMusic[index].ctx, NULL, 0);
+            return false;
+        }
+        
         if (currentMusic[index].chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes.
         {
-            int readlen = MUSIC_BUFFER_SIZE_FLOAT / 2;
-            jar_xm_generate_samples(currentMusic[index].chipctx, pcmf, readlen); // reads 2*readlen shorts and moves them to buffer+size memory location
+            jar_xm_generate_samples(currentMusic[index].chipctx, pcmf, MUSIC_BUFFER_SIZE_FLOAT / 2); // reads 2*readlen shorts and moves them to buffer+size memory location
             UpdateAudioContext(currentMusic[index].ctx, pcmf, MUSIC_BUFFER_SIZE_FLOAT);
-            size += readlen * currentMusic[index].ctx->channels; // Not sure if this is what it needs
-            currentMusic[index].totalSamplesLeft -= size;
+            currentMusic[index].totalSamplesLeft -= MUSIC_BUFFER_SIZE_FLOAT;
             if(currentMusic[index].totalSamplesLeft <= 0) active = false;
         }
         else
@@ -997,7 +1009,7 @@ static bool BufferMusicStream(int index)
             currentMusic[index].totalSamplesLeft -= streamedBytes*currentMusic[index].ctx->channels;
             if(currentMusic[index].totalSamplesLeft <= 0) active = false;
         }
-        // TraceLog(DEBUG, "Streaming music data to buffer. Bytes streamed: %i", size);
+        TraceLog(DEBUG, "Buffering index:%i, chiptune:%i", index, (int)currentMusic[index].chipTune);
     }
 
     return active;

From 8c5d403dda7a7070dc58204bb10539b3646f183b Mon Sep 17 00:00:00 2001
From: Joshua Reisenauer <kd7tck@msn.com>
Date: Sat, 14 May 2016 15:26:17 -0700
Subject: [PATCH 08/33] new function to check if music stream is ready

_g naming convention for globals, new error exit numbers.
---
 src/audio.c | 43 ++++++++++++++++++++++++++++++-------------
 1 file changed, 30 insertions(+), 13 deletions(-)

diff --git a/src/audio.c b/src/audio.c
index c53d63187..0fd1bb13a 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -112,7 +112,7 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
 // Global Variables Definition
 //----------------------------------------------------------------------------------
 static AudioContext_t* mixChannelsActive_g[MAX_AUDIO_CONTEXTS];      // What mix channels are currently active
-static bool musicEnabled = false;
+static bool musicEnabled_g = false;
 static Music currentMusic[MAX_MUSIC_STREAMS];                        // Current music loaded, up to two can play at the same time
 
 //----------------------------------------------------------------------------------
@@ -126,8 +126,9 @@ static bool BufferMusicStream(int index);          // Fill music buffers with da
 static void EmptyMusicStream(int index);           // Empty music buffers
 
 static unsigned short FillAlBufferWithSilence(AudioContext_t *context, ALuint buffer);// fill buffer with zeros, returns number processed
-static void ResampleShortToFloat(short *shorts, float *floats, unsigned short len); // pass two arrays of the same legnth in
-static void ResampleByteToFloat(char *chars, float *floats, unsigned short len); // pass two arrays of same length in
+static void ResampleShortToFloat(short *shorts, float *floats, unsigned short len);   // pass two arrays of the same legnth in
+static void ResampleByteToFloat(char *chars, float *floats, unsigned short len);      // pass two arrays of same length in
+static bool isMusicStreamReady(int index);                                            // Checks if music buffer is ready to be refilled
 
 #if defined(AUDIO_STANDALONE)
 const char *GetExtension(const char *fileName);     // Get the extension for a filename
@@ -799,18 +800,21 @@ int PlayMusicStream(int musicIndex, char *fileName)
             TraceLog(DEBUG, "[%s] Temp memory required: %i", fileName, info.temp_memory_required);
 
             currentMusic[musicIndex].loop = true;                  // We loop by default
-            musicEnabled = true;
-            currentMusic[musicIndex].ctx->playing = true;
+            musicEnabled_g = true;
+            
 
             currentMusic[musicIndex].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[musicIndex].stream) * info.channels;
             currentMusic[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[musicIndex].stream);
             
             if (info.channels == 2){
                 currentMusic[musicIndex].ctx = InitAudioContext(info.sample_rate, mixIndex, 2, false);
+                currentMusic[musicIndex].ctx->playing = true;
             }
             else{
                 currentMusic[musicIndex].ctx = InitAudioContext(info.sample_rate, mixIndex, 1, false);
+                currentMusic[musicIndex].ctx->playing = true;
             }
+            if(!currentMusic[musicIndex].ctx) return 4; // error
         }
     }
     else if (strcmp(GetExtension(fileName),"xm") == 0)
@@ -823,24 +827,25 @@ int PlayMusicStream(int musicIndex, char *fileName)
             jar_xm_set_max_loop_count(currentMusic[musicIndex].chipctx, 0); // infinite number of loops
             currentMusic[musicIndex].totalSamplesLeft =  jar_xm_get_remaining_samples(currentMusic[musicIndex].chipctx);
             currentMusic[musicIndex].totalLengthSeconds = ((float)currentMusic[musicIndex].totalSamplesLeft) / 48000.f;
-            musicEnabled = true;
-            currentMusic[musicIndex].ctx->playing = true;
+            musicEnabled_g = true;
             
             TraceLog(INFO, "[%s] XM number of samples: %i", fileName, currentMusic[musicIndex].totalSamplesLeft);
             TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, currentMusic[musicIndex].totalLengthSeconds);
             
             currentMusic[musicIndex].ctx = InitAudioContext(48000, mixIndex, 2, true);
+            if(!currentMusic[musicIndex].ctx) return 5; // error
+            currentMusic[musicIndex].ctx->playing = true;
         }
         else
         {
             TraceLog(WARNING, "[%s] XM file could not be opened", fileName);
-            return 4; // error
+            return 6; // error
         }
     }
     else
     {
         TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName);
-        return 5; // error
+        return 7; // error
     }
     return 0; // normal return
 }
@@ -861,7 +866,7 @@ void StopMusicStream(int index)
             stb_vorbis_close(currentMusic[index].stream);
         }
         
-        if(!getMusicStreamCount()) musicEnabled = false;
+        if(!getMusicStreamCount()) musicEnabled_g = false;
         if(currentMusic[index].stream || currentMusic[index].chipctx)
         {
             currentMusic[index].stream = NULL;
@@ -884,7 +889,7 @@ int getMusicStreamCount(void)
 void PauseMusicStream(int index)
 {
     // Pause music stream if music available!
-    if (currentMusic[index].ctx && musicEnabled)
+    if (currentMusic[index].ctx && musicEnabled_g)
     {
         TraceLog(INFO, "Pausing music stream");
         alSourcePause(currentMusic[index].ctx->alSource);
@@ -987,7 +992,7 @@ static bool BufferMusicStream(int index)
     int  size = 0;              // Total size of data steamed (in bytes)
     bool active = true;         // We can get more data from stream (not finished)
         
-    if (musicEnabled)
+    if (musicEnabled_g)
     {
         if(!currentMusic[index].ctx->playing)
         {
@@ -1031,13 +1036,25 @@ static void EmptyMusicStream(int index)
     }
 }
 
+//determine if a music stream is ready to be written to
+static bool isMusicStreamReady(int index)
+{
+    ALint processed = 0;
+    alGetSourcei(currentMusic[index].ctx->alSource, AL_BUFFERS_PROCESSED, &processed);
+    
+    if(processed)
+        return true;
+    
+    return false;
+}
+
 // Update (re-fill) music buffers if data already processed
 void UpdateMusicStream(int index)
 {
     ALenum state;
     bool active = true;
 
-    if (index < MAX_MUSIC_STREAMS && musicEnabled)
+    if (index < MAX_MUSIC_STREAMS && musicEnabled_g && isMusicStreamReady(index))
     {
         active = BufferMusicStream(index);
         

From d38d7a1bedadf7c4824c9bb1d4a9ecd3f0935b9c Mon Sep 17 00:00:00 2001
From: Joshua Reisenauer <kd7tck@msn.com>
Date: Sat, 14 May 2016 16:30:32 -0700
Subject: [PATCH 09/33] clean up on buffering and preconditions

---
 src/audio.c | 89 ++++++++++++++++++++++++++++++-----------------------
 1 file changed, 50 insertions(+), 39 deletions(-)

diff --git a/src/audio.c b/src/audio.c
index 0fd1bb13a..30e2343f1 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -889,7 +889,7 @@ int getMusicStreamCount(void)
 void PauseMusicStream(int index)
 {
     // Pause music stream if music available!
-    if (currentMusic[index].ctx && musicEnabled_g)
+    if (index < MAX_MUSIC_STREAMS && currentMusic[index].ctx && musicEnabled_g)
     {
         TraceLog(INFO, "Pausing music stream");
         alSourcePause(currentMusic[index].ctx->alSource);
@@ -902,7 +902,7 @@ void ResumeMusicStream(int index)
 {
     // Resume music playing... if music available!
     ALenum state;
-    if(currentMusic[index].ctx){
+    if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx){
         alGetSourcei(currentMusic[index].ctx->alSource, AL_SOURCE_STATE, &state);
         if (state == AL_PAUSED)
         {
@@ -962,17 +962,20 @@ float GetMusicTimeLength(int index)
 float GetMusicTimePlayed(int index)
 {
     float secondsPlayed;
-    if (currentMusic[index].chipTune)
-    {
-        uint64_t samples;
-        jar_xm_get_position(currentMusic[index].chipctx, NULL, NULL, NULL, &samples);
-        secondsPlayed = (float)samples / (48000 * currentMusic[index].ctx->channels); // Not sure if this is the correct value
-    }
-    else
+    if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx)
     {
-        int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].ctx->channels;
-        int samplesPlayed = totalSamples - currentMusic[index].totalSamplesLeft;
-        secondsPlayed = (float)samplesPlayed / (currentMusic[index].ctx->sampleRate * currentMusic[index].ctx->channels);
+        if (currentMusic[index].chipTune)
+        {
+            uint64_t samples;
+            jar_xm_get_position(currentMusic[index].chipctx, NULL, NULL, NULL, &samples);
+            secondsPlayed = (float)samples / (48000 * currentMusic[index].ctx->channels); // Not sure if this is the correct value
+        }
+        else
+        {
+            int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].ctx->channels;
+            int samplesPlayed = totalSamples - currentMusic[index].totalSamplesLeft;
+            secondsPlayed = (float)samplesPlayed / (currentMusic[index].ctx->sampleRate * currentMusic[index].ctx->channels);
+        }
     }
     
 
@@ -989,33 +992,42 @@ static bool BufferMusicStream(int index)
     short pcm[MUSIC_BUFFER_SIZE_SHORT];
     float pcmf[MUSIC_BUFFER_SIZE_FLOAT];
     
-    int  size = 0;              // Total size of data steamed (in bytes)
+    int  size = 0;              // Total size of data steamed in L+R samples
     bool active = true;         // We can get more data from stream (not finished)
         
-    if (musicEnabled_g)
+    
+    if(!currentMusic[index].ctx->playing && currentMusic[index].totalSamplesLeft > 0)
     {
-        if(!currentMusic[index].ctx->playing)
-        {
-            UpdateAudioContext(currentMusic[index].ctx, NULL, 0);
-            return false;
-        }
-        
-        if (currentMusic[index].chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes.
-        {
-            jar_xm_generate_samples(currentMusic[index].chipctx, pcmf, MUSIC_BUFFER_SIZE_FLOAT / 2); // reads 2*readlen shorts and moves them to buffer+size memory location
-            UpdateAudioContext(currentMusic[index].ctx, pcmf, MUSIC_BUFFER_SIZE_FLOAT);
-            currentMusic[index].totalSamplesLeft -= MUSIC_BUFFER_SIZE_FLOAT;
-            if(currentMusic[index].totalSamplesLeft <= 0) active = false;
-        }
+        UpdateAudioContext(currentMusic[index].ctx, NULL, 0);
+        return true; // it is still active, only it is paused
+    }
+    
+    
+    if (currentMusic[index].chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes.
+    {
+        if(currentMusic[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_FLOAT / 2)
+            size = MUSIC_BUFFER_SIZE_FLOAT / 2;
         else
-        {
-            int streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic[index].stream, currentMusic[index].ctx->channels, pcm, MUSIC_BUFFER_SIZE_SHORT);
-            UpdateAudioContext(currentMusic[index].ctx, pcm, streamedBytes);
-            currentMusic[index].totalSamplesLeft -= streamedBytes*currentMusic[index].ctx->channels;
-            if(currentMusic[index].totalSamplesLeft <= 0) active = false;
-        }
-        TraceLog(DEBUG, "Buffering index:%i, chiptune:%i", index, (int)currentMusic[index].chipTune);
+            size = currentMusic[index].totalSamplesLeft / 2;
+    
+        jar_xm_generate_samples(currentMusic[index].chipctx, pcmf, size); // reads 2*readlen shorts and moves them to buffer+size memory location
+        UpdateAudioContext(currentMusic[index].ctx, pcmf, size * 2);
+        currentMusic[index].totalSamplesLeft -= size * 2;
     }
+    else
+    {
+        if(currentMusic[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT)
+            size = MUSIC_BUFFER_SIZE_SHORT;
+        else
+            size = currentMusic[index].totalSamplesLeft;
+        
+        int streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic[index].stream, currentMusic[index].ctx->channels, pcm, size);
+        UpdateAudioContext(currentMusic[index].ctx, pcm, streamedBytes * currentMusic[index].ctx->channels);
+        currentMusic[index].totalSamplesLeft -= streamedBytes * currentMusic[index].ctx->channels;
+    }
+    
+    TraceLog(DEBUG, "Buffering index:%i, chiptune:%i", index, (int)currentMusic[index].chipTune);
+    if(currentMusic[index].totalSamplesLeft <= 0) active = false;
 
     return active;
 }
@@ -1042,8 +1054,7 @@ static bool isMusicStreamReady(int index)
     ALint processed = 0;
     alGetSourcei(currentMusic[index].ctx->alSource, AL_BUFFERS_PROCESSED, &processed);
     
-    if(processed)
-        return true;
+    if(processed) return true;
     
     return false;
 }
@@ -1054,11 +1065,11 @@ void UpdateMusicStream(int index)
     ALenum state;
     bool active = true;
 
-    if (index < MAX_MUSIC_STREAMS && musicEnabled_g && isMusicStreamReady(index))
+    if (index < MAX_MUSIC_STREAMS && musicEnabled_g && currentMusic[index].ctx && isMusicStreamReady(index))
     {
         active = BufferMusicStream(index);
         
-        if ((!active) && (currentMusic[index].loop))
+        if (!active && currentMusic[index].loop && currentMusic[index].ctx->playing)
         {
             if(currentMusic[index].chipTune)
             {
@@ -1067,7 +1078,7 @@ void UpdateMusicStream(int index)
             else
             {
                 stb_vorbis_seek_start(currentMusic[index].stream);
-                currentMusic[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[index].stream)*currentMusic[index].ctx->channels;
+                currentMusic[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].ctx->channels;
             }
             active = BufferMusicStream(index);
         }

From 86fbf4fd8f0cd5301259b2115125c45c9872c02a Mon Sep 17 00:00:00 2001
From: Joshua Reisenauer <kd7tck@msn.com>
Date: Sun, 15 May 2016 02:09:57 -0700
Subject: [PATCH 10/33] logic bug fix

---
 src/audio.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/audio.c b/src/audio.c
index 30e2343f1..cc5ca1a27 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -996,10 +996,10 @@ static bool BufferMusicStream(int index)
     bool active = true;         // We can get more data from stream (not finished)
         
     
-    if(!currentMusic[index].ctx->playing && currentMusic[index].totalSamplesLeft > 0)
+    if (!currentMusic[index].ctx->playing && currentMusic[index].totalSamplesLeft > 0)
     {
         UpdateAudioContext(currentMusic[index].ctx, NULL, 0);
-        return true; // it is still active, only it is paused
+        return true; // it is still active but it is paused
     }
     
     
@@ -1071,7 +1071,7 @@ void UpdateMusicStream(int index)
         
         if (!active && currentMusic[index].loop && currentMusic[index].ctx->playing)
         {
-            if(currentMusic[index].chipTune)
+            if (currentMusic[index].chipTune)
             {
                 currentMusic[index].totalSamplesLeft = currentMusic[index].totalLengthSeconds * currentMusic[index].ctx->sampleRate;
             }
@@ -1080,7 +1080,7 @@ void UpdateMusicStream(int index)
                 stb_vorbis_seek_start(currentMusic[index].stream);
                 currentMusic[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].ctx->channels;
             }
-            active = BufferMusicStream(index);
+            active = true;
         }
         
 
@@ -1088,7 +1088,7 @@ void UpdateMusicStream(int index)
         
         alGetSourcei(currentMusic[index].ctx->alSource, AL_SOURCE_STATE, &state);
 
-        if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic[index].ctx->alSource);
+        if (state != AL_PLAYING && active && currentMusic[index].ctx->playing) alSourcePlay(currentMusic[index].ctx->alSource);
 
         if (!active) StopMusicStream(index);
         

From 76ff4d220ee735b8b86bd4dae776665cf68e4fb4 Mon Sep 17 00:00:00 2001
From: Joshua Reisenauer <kd7tck@msn.com>
Date: Sun, 15 May 2016 19:37:15 -0700
Subject: [PATCH 11/33] renamed everything so it is obvious what it does

---
 src/audio.c  | 380 ++++++++++++++++++++++++---------------------------
 src/audio.h  |  15 +-
 src/raylib.h |  15 +-
 3 files changed, 190 insertions(+), 220 deletions(-)

diff --git a/src/audio.c b/src/audio.c
index cc5ca1a27..584d3ad14 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -77,10 +77,10 @@
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
 
-// Audio Context, used to create custom audio streams that are not bound to a sound file. There can be
-// no more than 4 concurrent audio contexts in use. This is due to each active context being tied to
-// a dedicated mix channel. All audio is 32bit floating point in stereo.
-typedef struct AudioContext_t {
+// Used to create custom audio streams that are not bound to a specific file. There can be
+// no more than 4 concurrent mixchannels in use. This is due to each active mixc being tied to
+// a dedicated mix channel.
+typedef struct MixChannel_t {
     unsigned short sampleRate;           // default is 48000
     unsigned char channels;              // 1=mono,2=stereo
     unsigned char mixChannel;            // 0-3 or mixA-mixD, each mix channel can receive up to one dedicated audio stream
@@ -89,14 +89,14 @@ typedef struct AudioContext_t {
     ALenum alFormat;                     // openAL format specifier
     ALuint alSource;                     // openAL source
     ALuint alBuffer[MAX_STREAM_BUFFERS]; // openAL sample buffer
-} AudioContext_t;
+} MixChannel_t;
 
 // Music type (file streaming from memory)
-// NOTE: Anything longer than ~10 seconds should be streamed...
+// NOTE: Anything longer than ~10 seconds should be streamed into a mix channel...
 typedef struct Music {
     stb_vorbis *stream;
-    jar_xm_context_t *chipctx; // Stores jar_xm context
-    AudioContext_t *ctx; // audio context
+    jar_xm_context_t *chipctx; // Stores jar_xm mixc
+    MixChannel_t *mixc; // mix channel
     
     int totalSamplesLeft;
     float totalLengthSeconds;
@@ -111,9 +111,9 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 //----------------------------------------------------------------------------------
-static AudioContext_t* mixChannelsActive_g[MAX_AUDIO_CONTEXTS];      // What mix channels are currently active
+static MixChannel_t* mixChannelsActive_g[MAX_AUDIO_CONTEXTS];      // What mix channels are currently active
 static bool musicEnabled_g = false;
-static Music currentMusic[MAX_MUSIC_STREAMS];                        // Current music loaded, up to two can play at the same time
+static Music currentMusic[MAX_MUSIC_STREAMS];                      // Current music loaded, up to two can play at the same time
 
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
@@ -122,13 +122,17 @@ static Wave LoadWAV(const char *fileName);         // Load WAV file
 static Wave LoadOGG(char *fileName);               // Load OGG file
 static void UnloadWave(Wave wave);                 // Unload wave data
 
-static bool BufferMusicStream(int index);          // Fill music buffers with data
-static void EmptyMusicStream(int index);           // Empty music buffers
+static bool BufferMusicStream(int index, int numBuffers); // Fill music buffers with data
+static void EmptyMusicStream(int index); // Empty music buffers
 
-static unsigned short FillAlBufferWithSilence(AudioContext_t *context, ALuint buffer);// fill buffer with zeros, returns number processed
-static void ResampleShortToFloat(short *shorts, float *floats, unsigned short len);   // pass two arrays of the same legnth in
-static void ResampleByteToFloat(char *chars, float *floats, unsigned short len);      // pass two arrays of same length in
-static bool isMusicStreamReady(int index);                                            // Checks if music buffer is ready to be refilled
+
+static MixChannel_t* InitMixChannel(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint); // For streaming into mix channels.
+static void CloseMixChannel(MixChannel_t* mixc); // Frees mix channel
+static unsigned short BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements); // Pushes more audio data into mixc mix channel, if NULL is passed it pauses
+static unsigned short FillAlBufferWithSilence(MixChannel_t *mixc, ALuint buffer); // Fill buffer with zeros, returns number processed
+static void ResampleShortToFloat(short *shorts, float *floats, unsigned short len); // Pass two arrays of the same legnth in
+static void ResampleByteToFloat(char *chars, float *floats, unsigned short len); // Pass two arrays of same length in
+static int IsMusicStreamReadyForBuffering(int index); // Checks if music buffer is ready to be refilled
 
 #if defined(AUDIO_STANDALONE)
 const char *GetExtension(const char *fileName);     // Get the extension for a filename
@@ -139,7 +143,7 @@ void TraceLog(int msgType, const char *text, ...);  // Outputs a trace log messa
 // Module Functions Definition - Audio Device initialization and Closing
 //----------------------------------------------------------------------------------
 
-// Initialize audio device and context
+// Initialize audio device and mixc
 void InitAudioDevice(void)
 {
     // Open and initialize a device with default settings
@@ -155,7 +159,7 @@ void InitAudioDevice(void)
 
         alcCloseDevice(device);
 
-        TraceLog(ERROR, "Could not setup audio context");
+        TraceLog(ERROR, "Could not setup mix channel");
     }
 
     TraceLog(INFO, "Audio device and context initialized successfully: %s", alcGetString(device, ALC_DEVICE_SPECIFIER));
@@ -171,14 +175,14 @@ void CloseAudioDevice(void)
 {
     for(int index=0; index<MAX_MUSIC_STREAMS; index++)
     {
-        if(currentMusic[index].ctx) StopMusicStream(index);      // Stop music streaming and close current stream
+        if(currentMusic[index].mixc) StopMusicStream(index);      // Stop music streaming and close current stream
     }
     
 
     ALCdevice *device;
     ALCcontext *context = alcGetCurrentContext();
 
-    if (context == NULL) TraceLog(WARNING, "Could not get current audio context for closing");
+    if (context == NULL) TraceLog(WARNING, "Could not get current mix channel for closing");
 
     device = alcGetContextsDevice(context);
 
@@ -203,186 +207,141 @@ bool IsAudioDeviceReady(void)
 // Module Functions Definition - Custom audio output
 //----------------------------------------------------------------------------------
 
-// Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing
-// The mixChannel is what mix channel you want to operate on, 0-3 are the ones available. Each mix channel can only be used one at a time.
-// exmple usage is InitAudioContext(48000, 0, 2, true); // mixchannel 1, 48khz, stereo, floating point
-AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint)
+// For streaming into mix channels.
+// The mixChannel is what audio muxing channel you want to operate on, 0-3 are the ones available. Each mix channel can only be used one at a time.
+// exmple usage is InitMixChannel(48000, 0, 2, true); // mixchannel 1, 48khz, stereo, floating point
+static MixChannel_t* InitMixChannel(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint)
 {
     if(mixChannel >= MAX_AUDIO_CONTEXTS) return NULL;
     if(!IsAudioDeviceReady()) InitAudioDevice();
     
     if(!mixChannelsActive_g[mixChannel]){
-        AudioContext_t *ac = (AudioContext_t*)malloc(sizeof(AudioContext_t));
-        ac->sampleRate = sampleRate;
-        ac->channels = channels;
-        ac->mixChannel = mixChannel;
-        ac->floatingPoint = floatingPoint;
-        mixChannelsActive_g[mixChannel] = ac;
+        MixChannel_t *mixc = (MixChannel_t*)malloc(sizeof(MixChannel_t));
+        mixc->sampleRate = sampleRate;
+        mixc->channels = channels;
+        mixc->mixChannel = mixChannel;
+        mixc->floatingPoint = floatingPoint;
+        mixChannelsActive_g[mixChannel] = mixc;
         
         // setup openAL format
         if(channels == 1)
         {
             if(floatingPoint)
-                ac->alFormat = AL_FORMAT_MONO_FLOAT32;
+                mixc->alFormat = AL_FORMAT_MONO_FLOAT32;
             else
-                ac->alFormat = AL_FORMAT_MONO16;
+                mixc->alFormat = AL_FORMAT_MONO16;
         }
         else if(channels == 2)
         {
             if(floatingPoint)
-                ac->alFormat = AL_FORMAT_STEREO_FLOAT32;
+                mixc->alFormat = AL_FORMAT_STEREO_FLOAT32;
             else
-                ac->alFormat = AL_FORMAT_STEREO16;
+                mixc->alFormat = AL_FORMAT_STEREO16;
         }
         
         // Create an audio source
-        alGenSources(1, &ac->alSource);
-        alSourcef(ac->alSource, AL_PITCH, 1);
-        alSourcef(ac->alSource, AL_GAIN, 1);
-        alSource3f(ac->alSource, AL_POSITION, 0, 0, 0);
-        alSource3f(ac->alSource, AL_VELOCITY, 0, 0, 0);
+        alGenSources(1, &mixc->alSource);
+        alSourcef(mixc->alSource, AL_PITCH, 1);
+        alSourcef(mixc->alSource, AL_GAIN, 1);
+        alSource3f(mixc->alSource, AL_POSITION, 0, 0, 0);
+        alSource3f(mixc->alSource, AL_VELOCITY, 0, 0, 0);
         
         // Create Buffer
-        alGenBuffers(MAX_STREAM_BUFFERS, ac->alBuffer);
+        alGenBuffers(MAX_STREAM_BUFFERS, mixc->alBuffer);
         
         //fill buffers
         int x;
         for(x=0;x<MAX_STREAM_BUFFERS;x++)
-            FillAlBufferWithSilence(ac, ac->alBuffer[x]);
+            FillAlBufferWithSilence(mixc, mixc->alBuffer[x]);
         
-        alSourceQueueBuffers(ac->alSource, MAX_STREAM_BUFFERS, ac->alBuffer);
-        alSourcePlay(ac->alSource);
-        ac->playing = true;
+        alSourceQueueBuffers(mixc->alSource, MAX_STREAM_BUFFERS, mixc->alBuffer);
+        mixc->playing = true;
+        alSourcePlay(mixc->alSource);
         
-        return ac;
+        return mixc;
     }
     return NULL;
 }
 
-// Frees buffer in audio context
-void CloseAudioContext(AudioContext ctx)
+// Frees buffer in mix channel
+static void CloseMixChannel(MixChannel_t* mixc)
 {
-    AudioContext_t *context = (AudioContext_t*)ctx;
-    if(context){
-        alSourceStop(context->alSource);
-        context->playing = false;
+    if(mixc){
+        alSourceStop(mixc->alSource);
+        mixc->playing = false;
         
         //flush out all queued buffers
         ALuint buffer = 0;
         int queued = 0;
-        alGetSourcei(context->alSource, AL_BUFFERS_QUEUED, &queued);
+        alGetSourcei(mixc->alSource, AL_BUFFERS_QUEUED, &queued);
         while (queued > 0)
         {
-            alSourceUnqueueBuffers(context->alSource, 1, &buffer);
+            alSourceUnqueueBuffers(mixc->alSource, 1, &buffer);
             queued--;
         }
         
         //delete source and buffers
-        alDeleteSources(1, &context->alSource);
-        alDeleteBuffers(MAX_STREAM_BUFFERS, context->alBuffer);
-        mixChannelsActive_g[context->mixChannel] = NULL;
-        free(context);
-        ctx = NULL;
+        alDeleteSources(1, &mixc->alSource);
+        alDeleteBuffers(MAX_STREAM_BUFFERS, mixc->alBuffer);
+        mixChannelsActive_g[mixc->mixChannel] = NULL;
+        free(mixc);
+        mixc = NULL;
     }
 }
 
-// Pushes more audio data into context mix channel, if none are ever pushed then zeros are fed in.
-// Call "UpdateAudioContext(ctx, NULL, 0)" if you want to pause the audio.
+// Pushes more audio data into mixc mix channel, only one buffer per call
+// Call "BufferMixChannel(mixc, NULL, 0)" if you want to pause the audio.
 // @Returns number of samples that where processed.
-unsigned short UpdateAudioContext(AudioContext ctx, void *data, unsigned short numberElements)
+static unsigned short BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements)
 {
-    AudioContext_t *context = (AudioContext_t*)ctx;
-    
-    if(!context || (context->channels == 2 && numberElements % 2 != 0)) return 0; // when there is two channels there must be an even number of samples
+    if(!mixc || mixChannelsActive_g[mixc->mixChannel] != mixc) return 0; // when there is two channels there must be an even number of samples
     
     if (!data || !numberElements)
     { // pauses audio until data is given
-        alSourcePause(context->alSource);
-        context->playing = false;
+        if(mixc->playing){
+            alSourcePause(mixc->alSource);
+            mixc->playing = false;
+        }
         return 0;
     }
-    else
+    else if(!mixc->playing)
     { // restart audio otherwise
-        ALint state;
-        alGetSourcei(context->alSource, AL_SOURCE_STATE, &state);
-        if (state != AL_PLAYING){
-            alSourcePlay(context->alSource);
-            context->playing = true;
-        }
+        alSourcePlay(mixc->alSource);
+        mixc->playing = true;
     }
     
-    if (context && context->playing && mixChannelsActive_g[context->mixChannel] == context)
+   
+    ALuint buffer = 0;
+    
+    alSourceUnqueueBuffers(mixc->alSource, 1, &buffer);
+    if(!buffer) return 0;
+    if(mixc->floatingPoint) // process float buffers
     {
-        ALint processed = 0;
-        ALuint buffer = 0;
-        unsigned short numberProcessed = 0;
-        unsigned short numberRemaining = numberElements;
-        
-        
-        alGetSourcei(context->alSource, AL_BUFFERS_PROCESSED, &processed); // Get the number of already processed buffers (if any)
-        if(!processed) return 0; // nothing to process, queue is still full
-        
-        
-        while (processed > 0)
-        {
-            if(context->floatingPoint) // process float buffers
-            {
-                float *ptr = (float*)data;
-                alSourceUnqueueBuffers(context->alSource, 1, &buffer);
-                if(numberRemaining >= MUSIC_BUFFER_SIZE_FLOAT)
-                {
-                    alBufferData(buffer, context->alFormat, &ptr[numberProcessed], MUSIC_BUFFER_SIZE_FLOAT*sizeof(float), context->sampleRate);
-                    numberProcessed+=MUSIC_BUFFER_SIZE_FLOAT;
-                    numberRemaining-=MUSIC_BUFFER_SIZE_FLOAT;
-                }
-                else
-                {
-                    alBufferData(buffer, context->alFormat, &ptr[numberProcessed], numberRemaining*sizeof(float), context->sampleRate);
-                    numberProcessed+=numberRemaining;
-                    numberRemaining=0;
-                }
-                alSourceQueueBuffers(context->alSource, 1, &buffer);
-                processed--;
-            }
-            else if(!context->floatingPoint) // process short buffers
-            {
-                short *ptr = (short*)data;
-                alSourceUnqueueBuffers(context->alSource, 1, &buffer);
-                if(numberRemaining >= MUSIC_BUFFER_SIZE_SHORT)
-                {
-                    alBufferData(buffer, context->alFormat, &ptr[numberProcessed], MUSIC_BUFFER_SIZE_FLOAT*sizeof(short), context->sampleRate);
-                    numberProcessed+=MUSIC_BUFFER_SIZE_SHORT;
-                    numberRemaining-=MUSIC_BUFFER_SIZE_SHORT;
-                }
-                else
-                {
-                    alBufferData(buffer, context->alFormat, &ptr[numberProcessed], numberRemaining*sizeof(short), context->sampleRate);
-                    numberProcessed+=numberRemaining;
-                    numberRemaining=0;
-                }
-                alSourceQueueBuffers(context->alSource, 1, &buffer);
-                processed--;
-            }
-            else
-                break;
-        }
-        return numberProcessed;
+        float *ptr = (float*)data;
+        alBufferData(buffer, mixc->alFormat, ptr, numberElements*sizeof(float), mixc->sampleRate);
+    }
+    else // process short buffers
+    {
+        short *ptr = (short*)data;
+        alBufferData(buffer, mixc->alFormat, ptr, numberElements*sizeof(short), mixc->sampleRate);
     }
-    return 0;
+    alSourceQueueBuffers(mixc->alSource, 1, &buffer);
+    
+    return numberElements;
 }
 
 // fill buffer with zeros, returns number processed
-static unsigned short FillAlBufferWithSilence(AudioContext_t *context, ALuint buffer)
+static unsigned short FillAlBufferWithSilence(MixChannel_t *mixc, ALuint buffer)
 {
-    if(context->floatingPoint){
+    if(mixc->floatingPoint){
         float pcm[MUSIC_BUFFER_SIZE_FLOAT] = {0.f};
-        alBufferData(buffer, context->alFormat, pcm, MUSIC_BUFFER_SIZE_FLOAT*sizeof(float), context->sampleRate);
+        alBufferData(buffer, mixc->alFormat, pcm, MUSIC_BUFFER_SIZE_FLOAT*sizeof(float), mixc->sampleRate);
         return MUSIC_BUFFER_SIZE_FLOAT;
     }
     else
     {
         short pcm[MUSIC_BUFFER_SIZE_SHORT] = {0};
-        alBufferData(buffer, context->alFormat, pcm, MUSIC_BUFFER_SIZE_SHORT*sizeof(short), context->sampleRate);
+        alBufferData(buffer, mixc->alFormat, pcm, MUSIC_BUFFER_SIZE_SHORT*sizeof(short), mixc->sampleRate);
         return MUSIC_BUFFER_SIZE_SHORT;
     }
 }
@@ -417,6 +376,28 @@ static void ResampleByteToFloat(char *chars, float *floats, unsigned short len)
     }
 }
 
+// used to output raw audio streams, returns negative numbers on error
+RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint)
+{
+    int mixIndex;
+    for(mixIndex = 0; mixIndex < MAX_AUDIO_CONTEXTS; mixIndex++) // find empty mix channel slot
+    {
+        if(mixChannelsActive_g[mixIndex] == NULL) break;
+        else if(mixIndex = MAX_AUDIO_CONTEXTS - 1) return -1; // error
+    }
+    
+    if(InitMixChannel(sampleRate, mixIndex, channels, floatingPoint))
+        return mixIndex;
+    else
+        return -2; // error
+}
+
+void CloseRawAudioContext(RawAudioContext ctx)
+{
+    if(mixChannelsActive_g[ctx])
+        CloseMixChannel(mixChannelsActive_g[ctx]);
+}
+
 
 
 //----------------------------------------------------------------------------------
@@ -807,14 +788,14 @@ int PlayMusicStream(int musicIndex, char *fileName)
             currentMusic[musicIndex].totalLengthSeconds = stb_vorbis_stream_length_in_seconds(currentMusic[musicIndex].stream);
             
             if (info.channels == 2){
-                currentMusic[musicIndex].ctx = InitAudioContext(info.sample_rate, mixIndex, 2, false);
-                currentMusic[musicIndex].ctx->playing = true;
+                currentMusic[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 2, false);
+                currentMusic[musicIndex].mixc->playing = true;
             }
             else{
-                currentMusic[musicIndex].ctx = InitAudioContext(info.sample_rate, mixIndex, 1, false);
-                currentMusic[musicIndex].ctx->playing = true;
+                currentMusic[musicIndex].mixc = InitMixChannel(info.sample_rate, mixIndex, 1, false);
+                currentMusic[musicIndex].mixc->playing = true;
             }
-            if(!currentMusic[musicIndex].ctx) return 4; // error
+            if(!currentMusic[musicIndex].mixc) return 4; // error
         }
     }
     else if (strcmp(GetExtension(fileName),"xm") == 0)
@@ -832,9 +813,9 @@ int PlayMusicStream(int musicIndex, char *fileName)
             TraceLog(INFO, "[%s] XM number of samples: %i", fileName, currentMusic[musicIndex].totalSamplesLeft);
             TraceLog(INFO, "[%s] XM track length: %11.6f sec", fileName, currentMusic[musicIndex].totalLengthSeconds);
             
-            currentMusic[musicIndex].ctx = InitAudioContext(48000, mixIndex, 2, true);
-            if(!currentMusic[musicIndex].ctx) return 5; // error
-            currentMusic[musicIndex].ctx->playing = true;
+            currentMusic[musicIndex].mixc = InitMixChannel(48000, mixIndex, 2, false);
+            if(!currentMusic[musicIndex].mixc) return 5; // error
+            currentMusic[musicIndex].mixc->playing = true;
         }
         else
         {
@@ -853,9 +834,9 @@ int PlayMusicStream(int musicIndex, char *fileName)
 // Stop music playing for individual music index of currentMusic array (close stream)
 void StopMusicStream(int index)
 {
-    if (index < MAX_MUSIC_STREAMS && currentMusic[index].ctx)
+    if (index < MAX_MUSIC_STREAMS && currentMusic[index].mixc)
     {
-        CloseAudioContext(currentMusic[index].ctx);
+        CloseMixChannel(currentMusic[index].mixc);
         
         if (currentMusic[index].chipTune)
         {
@@ -889,11 +870,11 @@ int getMusicStreamCount(void)
 void PauseMusicStream(int index)
 {
     // Pause music stream if music available!
-    if (index < MAX_MUSIC_STREAMS && currentMusic[index].ctx && musicEnabled_g)
+    if (index < MAX_MUSIC_STREAMS && currentMusic[index].mixc && musicEnabled_g)
     {
         TraceLog(INFO, "Pausing music stream");
-        alSourcePause(currentMusic[index].ctx->alSource);
-        currentMusic[index].ctx->playing = false;
+        alSourcePause(currentMusic[index].mixc->alSource);
+        currentMusic[index].mixc->playing = false;
     }
 }
 
@@ -902,13 +883,13 @@ void ResumeMusicStream(int index)
 {
     // Resume music playing... if music available!
     ALenum state;
-    if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx){
-        alGetSourcei(currentMusic[index].ctx->alSource, AL_SOURCE_STATE, &state);
+    if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){
+        alGetSourcei(currentMusic[index].mixc->alSource, AL_SOURCE_STATE, &state);
         if (state == AL_PAUSED)
         {
             TraceLog(INFO, "Resuming music stream");
-            alSourcePlay(currentMusic[index].ctx->alSource);
-            currentMusic[index].ctx->playing = true;
+            alSourcePlay(currentMusic[index].mixc->alSource);
+            currentMusic[index].mixc->playing = true;
         }
     }
 }
@@ -919,8 +900,8 @@ bool IsMusicPlaying(int index)
     bool playing = false;
     ALint state;
     
-    if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx){
-        alGetSourcei(currentMusic[index].ctx->alSource, AL_SOURCE_STATE, &state);
+    if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){
+        alGetSourcei(currentMusic[index].mixc->alSource, AL_SOURCE_STATE, &state);
         if (state == AL_PLAYING) playing = true;
     }
 
@@ -930,15 +911,15 @@ bool IsMusicPlaying(int index)
 // Set volume for music
 void SetMusicVolume(int index, float volume)
 {
-    if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx){
-        alSourcef(currentMusic[index].ctx->alSource, AL_GAIN, volume);
+    if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){
+        alSourcef(currentMusic[index].mixc->alSource, AL_GAIN, volume);
     }
 }
 
 void SetMusicPitch(int index, float pitch)
 {
-    if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx){
-        alSourcef(currentMusic[index].ctx->alSource, AL_PITCH, pitch);
+    if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc){
+        alSourcef(currentMusic[index].mixc->alSource, AL_PITCH, pitch);
     }
 }
 
@@ -962,19 +943,19 @@ float GetMusicTimeLength(int index)
 float GetMusicTimePlayed(int index)
 {
     float secondsPlayed;
-    if(index < MAX_MUSIC_STREAMS && currentMusic[index].ctx)
+    if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc)
     {
         if (currentMusic[index].chipTune)
         {
             uint64_t samples;
             jar_xm_get_position(currentMusic[index].chipctx, NULL, NULL, NULL, &samples);
-            secondsPlayed = (float)samples / (48000 * currentMusic[index].ctx->channels); // Not sure if this is the correct value
+            secondsPlayed = (float)samples / (48000 * currentMusic[index].mixc->channels); // Not sure if this is the correct value
         }
         else
         {
-            int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].ctx->channels;
+            int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].mixc->channels;
             int samplesPlayed = totalSamples - currentMusic[index].totalSamplesLeft;
-            secondsPlayed = (float)samplesPlayed / (currentMusic[index].ctx->sampleRate * currentMusic[index].ctx->channels);
+            secondsPlayed = (float)samplesPlayed / (currentMusic[index].mixc->sampleRate * currentMusic[index].mixc->channels);
         }
     }
     
@@ -987,32 +968,32 @@ float GetMusicTimePlayed(int index)
 //----------------------------------------------------------------------------------
 
 // Fill music buffers with new data from music stream
-static bool BufferMusicStream(int index)
+static bool BufferMusicStream(int index, int numBuffers)
 {
     short pcm[MUSIC_BUFFER_SIZE_SHORT];
     float pcmf[MUSIC_BUFFER_SIZE_FLOAT];
     
-    int  size = 0;              // Total size of data steamed in L+R samples
+    int  size = 0;              // Total size of data steamed in L+R samples for xm floats, individual L or R for ogg shorts
     bool active = true;         // We can get more data from stream (not finished)
-        
-    
-    if (!currentMusic[index].ctx->playing && currentMusic[index].totalSamplesLeft > 0)
-    {
-        UpdateAudioContext(currentMusic[index].ctx, NULL, 0);
-        return true; // it is still active but it is paused
-    }
-    
     
     if (currentMusic[index].chipTune) // There is no end of stream for xmfiles, once the end is reached zeros are generated for non looped chiptunes.
     {
-        if(currentMusic[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_FLOAT / 2)
-            size = MUSIC_BUFFER_SIZE_FLOAT / 2;
+        if(currentMusic[index].totalSamplesLeft >= MUSIC_BUFFER_SIZE_SHORT)
+            size = MUSIC_BUFFER_SIZE_SHORT / 2;
         else
             size = currentMusic[index].totalSamplesLeft / 2;
-    
-        jar_xm_generate_samples(currentMusic[index].chipctx, pcmf, size); // reads 2*readlen shorts and moves them to buffer+size memory location
-        UpdateAudioContext(currentMusic[index].ctx, pcmf, size * 2);
-        currentMusic[index].totalSamplesLeft -= size * 2;
+        
+        for(int x=0; x<numBuffers; x++)
+        {
+            jar_xm_generate_samples_16bit(currentMusic[index].chipctx, pcm, size); // reads 2*readlen shorts and moves them to buffer+size memory location
+            BufferMixChannel(currentMusic[index].mixc, pcm, size * 2);
+            currentMusic[index].totalSamplesLeft -= size * 2;
+            if(currentMusic[index].totalSamplesLeft <= 0)
+            {
+                active = false;
+                break;
+            }
+        }
     }
     else
     {
@@ -1021,13 +1002,18 @@ static bool BufferMusicStream(int index)
         else
             size = currentMusic[index].totalSamplesLeft;
         
-        int streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic[index].stream, currentMusic[index].ctx->channels, pcm, size);
-        UpdateAudioContext(currentMusic[index].ctx, pcm, streamedBytes * currentMusic[index].ctx->channels);
-        currentMusic[index].totalSamplesLeft -= streamedBytes * currentMusic[index].ctx->channels;
+        for(int x=0; x<numBuffers; x++)
+        {
+            int streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic[index].stream, currentMusic[index].mixc->channels, pcm, size);
+            BufferMixChannel(currentMusic[index].mixc, pcm, streamedBytes * currentMusic[index].mixc->channels);
+            currentMusic[index].totalSamplesLeft -= streamedBytes * currentMusic[index].mixc->channels;
+            if(currentMusic[index].totalSamplesLeft <= 0)
+            {
+                active = false;
+                break;
+            }
+        }
     }
-    
-    TraceLog(DEBUG, "Buffering index:%i, chiptune:%i", index, (int)currentMusic[index].chipTune);
-    if(currentMusic[index].totalSamplesLeft <= 0) active = false;
 
     return active;
 }
@@ -1038,25 +1024,22 @@ static void EmptyMusicStream(int index)
     ALuint buffer = 0;
     int queued = 0;
 
-    alGetSourcei(currentMusic[index].ctx->alSource, AL_BUFFERS_QUEUED, &queued);
+    alGetSourcei(currentMusic[index].mixc->alSource, AL_BUFFERS_QUEUED, &queued);
 
     while (queued > 0)
     {
-        alSourceUnqueueBuffers(currentMusic[index].ctx->alSource, 1, &buffer);
+        alSourceUnqueueBuffers(currentMusic[index].mixc->alSource, 1, &buffer);
 
         queued--;
     }
 }
 
 //determine if a music stream is ready to be written to
-static bool isMusicStreamReady(int index)
+static int IsMusicStreamReadyForBuffering(int index)
 {
     ALint processed = 0;
-    alGetSourcei(currentMusic[index].ctx->alSource, AL_BUFFERS_PROCESSED, &processed);
-    
-    if(processed) return true;
-    
-    return false;
+    alGetSourcei(currentMusic[index].mixc->alSource, AL_BUFFERS_PROCESSED, &processed);
+    return processed;
 }
 
 // Update (re-fill) music buffers if data already processed
@@ -1064,21 +1047,22 @@ void UpdateMusicStream(int index)
 {
     ALenum state;
     bool active = true;
-
-    if (index < MAX_MUSIC_STREAMS && musicEnabled_g && currentMusic[index].ctx && isMusicStreamReady(index))
+    int numBuffers = IsMusicStreamReadyForBuffering(index);
+    
+    if (currentMusic[index].mixc->playing && index < MAX_MUSIC_STREAMS && musicEnabled_g && currentMusic[index].mixc && numBuffers)
     {
-        active = BufferMusicStream(index);
+        active = BufferMusicStream(index, numBuffers);
         
-        if (!active && currentMusic[index].loop && currentMusic[index].ctx->playing)
+        if (!active && currentMusic[index].loop)
         {
             if (currentMusic[index].chipTune)
             {
-                currentMusic[index].totalSamplesLeft = currentMusic[index].totalLengthSeconds * currentMusic[index].ctx->sampleRate;
+                currentMusic[index].totalSamplesLeft = currentMusic[index].totalLengthSeconds * 48000;
             }
             else
             {
                 stb_vorbis_seek_start(currentMusic[index].stream);
-                currentMusic[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].ctx->channels;
+                currentMusic[index].totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic[index].stream) * currentMusic[index].mixc->channels;
             }
             active = true;
         }
@@ -1086,9 +1070,9 @@ void UpdateMusicStream(int index)
 
         if (alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Error buffering data...");
         
-        alGetSourcei(currentMusic[index].ctx->alSource, AL_SOURCE_STATE, &state);
+        alGetSourcei(currentMusic[index].mixc->alSource, AL_SOURCE_STATE, &state);
 
-        if (state != AL_PLAYING && active && currentMusic[index].ctx->playing) alSourcePlay(currentMusic[index].ctx->alSource);
+        if (state != AL_PLAYING && active) alSourcePlay(currentMusic[index].mixc->alSource);
 
         if (!active) StopMusicStream(index);
         
diff --git a/src/audio.h b/src/audio.h
index 63c1c1365..d3276bf6e 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -61,10 +61,7 @@ typedef struct Wave {
     short channels;
 } Wave;
 
-// Audio Context, used to create custom audio streams that are not bound to a sound file. There can be
-// no more than 4 concurrent audio contexts in use. This is due to each active context being tied to
-// a dedicated mix channel.
-typedef void* AudioContext;
+typedef int RawAudioContext;
 
 #ifdef __cplusplus
 extern "C" {            // Prevents name mangling of functions
@@ -82,13 +79,6 @@ void InitAudioDevice(void);                                     // Initialize au
 void CloseAudioDevice(void);                                    // Close the audio device and context (and music stream)
 bool IsAudioDeviceReady(void);                                  // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet
 
-// Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing
-// The mixChannel is what mix channel you want to operate on, 0-3 are the ones available. Each mix channel can only be used one at a time.
-// exmple usage is InitAudioContext(48000, 0, 2, true); // mixchannel 1, 48khz, stereo, floating point
-AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint);
-void CloseAudioContext(AudioContext ctx);                       // Frees audio context
-unsigned short UpdateAudioContext(AudioContext ctx, void *data, unsigned short numberElements); // Pushes more audio data into context mix channel, if NULL is passed to data then zeros are played
-
 Sound LoadSound(char *fileName);                                // Load sound to memory
 Sound LoadSoundFromWave(Wave wave);                             // Load sound to memory from wave data
 Sound LoadSoundFromRES(const char *rresName, int resId);        // Load sound to memory from rRES file (raylib Resource)
@@ -112,6 +102,9 @@ float GetMusicTimePlayed(int index);                            // Get current m
 int getMusicStreamCount(void);
 void SetMusicPitch(int index, float pitch);
 
+RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint);
+void CloseRawAudioContext(RawAudioContext ctx);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/raylib.h b/src/raylib.h
index ea9fbfcb6..6efde7102 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -451,10 +451,7 @@ typedef struct Wave {
     short channels;
 } Wave;
 
-// Audio Context, used to create custom audio streams that are not bound to a sound file. There can be
-// no more than 4 concurrent audio contexts in use. This is due to each active context being tied to
-// a dedicated mix channel.
-typedef void* AudioContext;
+typedef int RawAudioContext;
 
 // Texture formats
 // NOTE: Support depends on OpenGL version and platform
@@ -876,13 +873,6 @@ void InitAudioDevice(void);                                     // Initialize au
 void CloseAudioDevice(void);                                    // Close the audio device and context (and music stream)
 bool IsAudioDeviceReady(void);                                  // True if call to InitAudioDevice() was successful and CloseAudioDevice() has not been called yet
 
-// Audio contexts are for outputing custom audio waveforms, This will shut down any other sound sources currently playing
-// The mixChannel is what mix channel you want to operate on, 0-3 are the ones available. Each mix channel can only be used one at a time.
-// exmple usage is InitAudioContext(48000, 0, 2, true); // mixchannel 1, 48khz, stereo, floating point
-AudioContext InitAudioContext(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint);
-void CloseAudioContext(AudioContext ctx);                       // Frees audio context
-unsigned short UpdateAudioContext(AudioContext ctx, void *data, unsigned short numberElements); // Pushes more audio data into context mix channel, if NULL is passed to data then zeros are played
-
 Sound LoadSound(char *fileName);                                // Load sound to memory
 Sound LoadSoundFromWave(Wave wave);                             // Load sound to memory from wave data
 Sound LoadSoundFromRES(const char *rresName, int resId);        // Load sound to memory from rRES file (raylib Resource)
@@ -906,6 +896,9 @@ float GetMusicTimePlayed(int index);                            // Get current m
 int getMusicStreamCount(void);
 void SetMusicPitch(int index, float pitch);
 
+RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint); // used to output raw audio streams, returns negative numbers on error
+void CloseRawAudioContext(RawAudioContext ctx);
+
 #ifdef __cplusplus
 }
 #endif

From bc08271da3e68d2880f4ef712c13e88b99f1021d Mon Sep 17 00:00:00 2001
From: raysan5 <raysan5@gmail.com>
Date: Wed, 18 May 2016 12:04:27 +0200
Subject: [PATCH 12/33] Updated shaders with comments

---
 examples/resources/shaders/glsl100/bloom.fs |  2 +-
 examples/resources/shaders/glsl100/swirl.fs |  2 +-
 examples/resources/shaders/glsl330/bloom.fs |  2 +-
 examples/resources/shaders/glsl330/phong.fs |  3 +
 examples/resources/shaders/glsl330/swirl.fs |  2 +-
 shaders/glsl100/base.vs                     | 14 +++-
 shaders/glsl100/bloom.fs                    | 25 +++---
 shaders/glsl100/blur.fs                     |  5 ++
 shaders/glsl100/cross_hatching.fs           |  5 +-
 shaders/glsl100/cross_stitching.fs          |  5 +-
 shaders/glsl100/dream_vision.fs             |  3 +
 shaders/glsl100/fisheye.fs                  |  5 +-
 shaders/glsl100/grayscale.fs                | 13 ++-
 shaders/glsl100/pixel.fs                    |  3 +
 shaders/glsl100/posterization.fs            |  3 +
 shaders/glsl100/predator.fs                 |  3 +
 shaders/glsl100/scanlines.fs                |  5 +-
 shaders/glsl100/swirl.fs                    | 16 ++--
 shaders/glsl100/template.fs                 |  4 +
 shaders/glsl330/base.vs                     | 12 ++-
 shaders/glsl330/bloom.fs                    | 34 ++++----
 shaders/glsl330/blur.fs                     | 19 +++--
 shaders/glsl330/cross_hatching.fs           | 18 +++--
 shaders/glsl330/cross_stitching.fs          | 12 ++-
 shaders/glsl330/depth.fs                    | 27 +++++++
 shaders/glsl330/grayscale.fs                | 18 +++--
 shaders/glsl330/phong.fs                    | 87 ++++++++++++---------
 shaders/glsl330/phong.vs                    | 14 ++--
 shaders/glsl330/pixel.fs                    | 12 ++-
 shaders/glsl330/posterization.fs            | 23 +++---
 shaders/glsl330/predator.fs                 | 15 ++--
 shaders/glsl330/scanlines.fs                | 15 ++--
 shaders/glsl330/swirl.fs                    | 17 ++--
 shaders/glsl330/template.fs                 | 11 ++-
 34 files changed, 295 insertions(+), 159 deletions(-)
 create mode 100644 shaders/glsl330/depth.fs

diff --git a/examples/resources/shaders/glsl100/bloom.fs b/examples/resources/shaders/glsl100/bloom.fs
index 5a08843d7..280d2fb66 100644
--- a/examples/resources/shaders/glsl100/bloom.fs
+++ b/examples/resources/shaders/glsl100/bloom.fs
@@ -33,5 +33,5 @@ void main()
     else if (texelColor.r < 0.5) tc = sum*sum*0.009 + texelColor;
     else tc = sum*sum*0.0075 + texelColor;
     
-    finalColor = tc;
+    gl_FragColor = tc;
 }
\ No newline at end of file
diff --git a/examples/resources/shaders/glsl100/swirl.fs b/examples/resources/shaders/glsl100/swirl.fs
index e77d4f872..0d6d24f26 100644
--- a/examples/resources/shaders/glsl100/swirl.fs
+++ b/examples/resources/shaders/glsl100/swirl.fs
@@ -20,7 +20,7 @@ float angle = 0.8;
 
 uniform vec2 center = vec2(200.0, 200.0);
 
-void main (void)
+void main()
 {
     vec2 texSize = vec2(renderWidth, renderHeight);
     vec2 tc = fragTexCoord*texSize;
diff --git a/examples/resources/shaders/glsl330/bloom.fs b/examples/resources/shaders/glsl330/bloom.fs
index 47ddee30a..0307bc06e 100644
--- a/examples/resources/shaders/glsl330/bloom.fs
+++ b/examples/resources/shaders/glsl330/bloom.fs
@@ -17,7 +17,7 @@ void main()
 {
     vec4 sum = vec4(0);
     vec4 tc = vec4(0);
-    
+
     for (int i = -4; i < 4; i++)
     {
         for (int j = -3; j < 3; j++)
diff --git a/examples/resources/shaders/glsl330/phong.fs b/examples/resources/shaders/glsl330/phong.fs
index 80e3d6735..c14b346a9 100644
--- a/examples/resources/shaders/glsl330/phong.fs
+++ b/examples/resources/shaders/glsl330/phong.fs
@@ -29,6 +29,9 @@ uniform float matGlossiness = 50.0;
 uniform vec3 lightPosition;
 uniform vec3 cameraPosition;
 
+// Fragment shader output data
+out vec4 fragColor;
+
 // Calculate ambient lighting component
 vec3 AmbientLighting()
 {
diff --git a/examples/resources/shaders/glsl330/swirl.fs b/examples/resources/shaders/glsl330/swirl.fs
index da098754e..80c16cc9e 100644
--- a/examples/resources/shaders/glsl330/swirl.fs
+++ b/examples/resources/shaders/glsl330/swirl.fs
@@ -21,7 +21,7 @@ float angle = 0.8;
 
 uniform vec2 center = vec2(200.0, 200.0);
 
-void main (void)
+void main()
 {
     vec2 texSize = vec2(renderWidth, renderHeight);
     vec2 tc = fragTexCoord*texSize;
diff --git a/shaders/glsl100/base.vs b/shaders/glsl100/base.vs
index 9f339382b..e93869396 100644
--- a/shaders/glsl100/base.vs
+++ b/shaders/glsl100/base.vs
@@ -1,20 +1,26 @@
 #version 100
 
+// Input vertex attributes
 attribute vec3 vertexPosition;
 attribute vec2 vertexTexCoord;
 attribute vec3 vertexNormal;
+attribute vec4 vertexColor;
 
-varying vec2 fragTexCoord;
-
+// Input uniform values
 uniform mat4 mvpMatrix;
 
+// Output vertex attributes (to fragment shader)
+varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
 // NOTE: Add here your custom variables 
 
 void main()
 {
-    vec3 normal = vertexNormal;
-    
+    // Send vertex attributes to fragment shader
     fragTexCoord = vertexTexCoord;
+    fragColor = vertexColor;
     
+    // Calculate final vertex position
     gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
 }
\ No newline at end of file
diff --git a/shaders/glsl100/bloom.fs b/shaders/glsl100/bloom.fs
index 33754c7ef..280d2fb66 100644
--- a/shaders/glsl100/bloom.fs
+++ b/shaders/glsl100/bloom.fs
@@ -2,8 +2,11 @@
 
 precision mediump float;
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
@@ -22,21 +25,13 @@ void main()
         }
     }
     
-    if (texture2D(texture0, fragTexCoord).r < 0.3)
-    {
-        tc = sum*sum*0.012 + texture2D(texture0, fragTexCoord);
-    }
-    else
-    {
-        if (texture2D(texture0, fragTexCoord).r < 0.5)
-        {
-            tc = sum*sum*0.009 + texture2D(texture0, fragTexCoord);
-        }
-        else
-        {
-            tc = sum*sum*0.0075 + texture2D(texture0, fragTexCoord);
-        }
-    }
+    // Texel color fetching from texture sampler
+    vec4 texelColor = texture(texture0, fragTexCoord);
+    
+    // Calculate final fragment color
+    if (texelColor.r < 0.3) tc = sum*sum*0.012 + texelColor;
+    else if (texelColor.r < 0.5) tc = sum*sum*0.009 + texelColor;
+    else tc = sum*sum*0.0075 + texelColor;
     
     gl_FragColor = tc;
 }
\ No newline at end of file
diff --git a/shaders/glsl100/blur.fs b/shaders/glsl100/blur.fs
index a1069c6fd..80d408343 100644
--- a/shaders/glsl100/blur.fs
+++ b/shaders/glsl100/blur.fs
@@ -2,7 +2,11 @@
 
 precision mediump float;
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
+
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
@@ -16,6 +20,7 @@ float weight[3] = float[]( 0.2270270270, 0.3162162162, 0.0702702703 );
 
 void main() 
 { 
+    // Texel color fetching from texture sampler
     vec3 tc = texture2D(texture0, fragTexCoord).rgb*weight[0];
 
     for (int i = 1; i < 3; i++) 
diff --git a/shaders/glsl100/cross_hatching.fs b/shaders/glsl100/cross_hatching.fs
index cf01b65ed..1f7dab087 100644
--- a/shaders/glsl100/cross_hatching.fs
+++ b/shaders/glsl100/cross_hatching.fs
@@ -2,12 +2,15 @@
 
 precision mediump float;
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
-// NOTE: Add here your custom variables 
+// NOTE: Add here your custom variables
 
 float hatchOffsetY = 5.0f;
 float lumThreshold01 = 0.9f;
diff --git a/shaders/glsl100/cross_stitching.fs b/shaders/glsl100/cross_stitching.fs
index f1afef048..6fabc027c 100644
--- a/shaders/glsl100/cross_stitching.fs
+++ b/shaders/glsl100/cross_stitching.fs
@@ -2,8 +2,11 @@
 
 precision mediump float;
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
@@ -46,7 +49,7 @@ vec4 PostFX(sampler2D tex, vec2 uv)
     return c;
 }
 
-void main(void)
+void main()
 {
     vec3 tc = PostFX(texture0, fragTexCoord).rgb;
 
diff --git a/shaders/glsl100/dream_vision.fs b/shaders/glsl100/dream_vision.fs
index bb8289700..d0cdc6874 100644
--- a/shaders/glsl100/dream_vision.fs
+++ b/shaders/glsl100/dream_vision.fs
@@ -2,8 +2,11 @@
 
 precision mediump float;
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
diff --git a/shaders/glsl100/fisheye.fs b/shaders/glsl100/fisheye.fs
index e7a4485c7..9dba297b3 100644
--- a/shaders/glsl100/fisheye.fs
+++ b/shaders/glsl100/fisheye.fs
@@ -2,12 +2,15 @@
 
 precision mediump float;
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
-// NOTE: Add here your custom variables 
+// NOTE: Add here your custom variables
 
 const float PI = 3.1415926535;
 
diff --git a/shaders/glsl100/grayscale.fs b/shaders/glsl100/grayscale.fs
index e55545e22..f92ec335c 100644
--- a/shaders/glsl100/grayscale.fs
+++ b/shaders/glsl100/grayscale.fs
@@ -2,8 +2,11 @@
 
 precision mediump float;
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
@@ -11,10 +14,12 @@ uniform vec4 fragTintColor;
 
 void main()
 {
-    vec4 base = texture2D(texture0, fragTexCoord)*fragTintColor;
+    // Texel color fetching from texture sampler
+    vec4 texelColor = texture(texture0, fragTexCoord)*fragTintColor*fragColor;
     
-    // Convert to grayscale using NTSC conversion weights
-    float gray = dot(base.rgb, vec3(0.299, 0.587, 0.114));
+    // Convert texel color to grayscale using NTSC conversion weights
+    float gray = dot(texelColor.rgb, vec3(0.299, 0.587, 0.114));
     
-    gl_FragColor = vec4(gray, gray, gray, fragTintColor.a);
+    // Calculate final fragment color
+    gl_FragColor = vec4(gray, gray, gray, texelColor.a);
 }
\ No newline at end of file
diff --git a/shaders/glsl100/pixel.fs b/shaders/glsl100/pixel.fs
index 552e89004..c532f2190 100644
--- a/shaders/glsl100/pixel.fs
+++ b/shaders/glsl100/pixel.fs
@@ -2,8 +2,11 @@
 
 precision mediump float;
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
diff --git a/shaders/glsl100/posterization.fs b/shaders/glsl100/posterization.fs
index 4f4c4b935..801ca89cc 100644
--- a/shaders/glsl100/posterization.fs
+++ b/shaders/glsl100/posterization.fs
@@ -2,8 +2,11 @@
 
 precision mediump float;
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
diff --git a/shaders/glsl100/predator.fs b/shaders/glsl100/predator.fs
index 2fbdc7afb..1f0e2ce54 100644
--- a/shaders/glsl100/predator.fs
+++ b/shaders/glsl100/predator.fs
@@ -2,8 +2,11 @@
 
 precision mediump float;
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
diff --git a/shaders/glsl100/scanlines.fs b/shaders/glsl100/scanlines.fs
index 85de158d8..d885e10b3 100644
--- a/shaders/glsl100/scanlines.fs
+++ b/shaders/glsl100/scanlines.fs
@@ -2,8 +2,11 @@
 
 precision mediump float;
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
@@ -14,7 +17,7 @@ float frequency = 720/3.0;
 
 uniform float time;
 
-void main (void)
+void main()
 {
 /*
     // Scanlines method 1
diff --git a/shaders/glsl100/swirl.fs b/shaders/glsl100/swirl.fs
index b0d54b235..0d6d24f26 100644
--- a/shaders/glsl100/swirl.fs
+++ b/shaders/glsl100/swirl.fs
@@ -2,28 +2,32 @@
 
 precision mediump float;
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
 // NOTE: Add here your custom variables
 
-const float renderWidth = 1280; 
-const float renderHeight = 720; 
+const float renderWidth = 800.0;      // HARDCODED for example!
+const float renderHeight = 480.0;     // Use uniforms instead...
 
 float radius = 250.0;
 float angle = 0.8;
 
-uniform vec2 center = vec2(200, 200);
+uniform vec2 center = vec2(200.0, 200.0);
 
-void main (void)
+void main()
 {
     vec2 texSize = vec2(renderWidth, renderHeight);
     vec2 tc = fragTexCoord*texSize;
     tc -= center;
-    float dist = length(tc);
     
+    float dist = length(tc);
+
     if (dist < radius) 
     {
         float percent = (radius - dist)/radius;
@@ -33,7 +37,7 @@ void main (void)
         
         tc = vec2(dot(tc, vec2(c, -s)), dot(tc, vec2(s, c)));
     }
-    
+
     tc += center;
     vec3 color = texture2D(texture0, tc/texSize).rgb;
 
diff --git a/shaders/glsl100/template.fs b/shaders/glsl100/template.fs
index 1f4b8ccfa..a39428907 100644
--- a/shaders/glsl100/template.fs
+++ b/shaders/glsl100/template.fs
@@ -2,8 +2,11 @@
 
 precision mediump float;
 
+// Input vertex attributes (from vertex shader)
 varying vec2 fragTexCoord;
+varying vec4 fragColor;
 
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
@@ -11,6 +14,7 @@ uniform vec4 fragTintColor;
 
 void main()
 {
+    // Texel color fetching from texture sampler
     vec4 texelColor = texture2D(texture0, fragTexCoord);
     
     // NOTE: Implement here your fragment shader code
diff --git a/shaders/glsl330/base.vs b/shaders/glsl330/base.vs
index b0f930b70..638cb8aee 100644
--- a/shaders/glsl330/base.vs
+++ b/shaders/glsl330/base.vs
@@ -1,18 +1,26 @@
 #version 330
 
+// Input vertex attributes
 in vec3 vertexPosition;
 in vec2 vertexTexCoord;
 in vec3 vertexNormal;
+in vec4 vertexColor;
 
-out vec2 fragTexCoord;
-
+// Input uniform values
 uniform mat4 mvpMatrix;
 
+// Output vertex attributes (to fragment shader)
+out vec2 fragTexCoord;
+out vec4 fragColor;
+
 // NOTE: Add here your custom variables 
 
 void main()
 {
+    // Send vertex attributes to fragment shader
     fragTexCoord = vertexTexCoord;
+    fragColor = vertexColor;
     
+    // Calculate final vertex position
     gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
 }
\ No newline at end of file
diff --git a/shaders/glsl330/bloom.fs b/shaders/glsl330/bloom.fs
index 34b6295c6..0307bc06e 100644
--- a/shaders/glsl330/bloom.fs
+++ b/shaders/glsl330/bloom.fs
@@ -1,12 +1,16 @@
 #version 330
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 
 void main()
@@ -18,25 +22,17 @@ void main()
     {
         for (int j = -3; j < 3; j++)
         {
-            sum += texture(texture0, fragTexCoord + vec2(j, i)*0.004) * 0.25;
+            sum += texture(texture0, fragTexCoord + vec2(j, i)*0.004)*0.25;
         }
     }
     
-    if (texture(texture0, fragTexCoord).r < 0.3)
-    {
-        tc = sum*sum*0.012 + texture(texture0, fragTexCoord);
-    }
-    else
-    {
-        if (texture(texture0, fragTexCoord).r < 0.5)
-        {
-            tc = sum*sum*0.009 + texture(texture0, fragTexCoord);
-        }
-        else
-        {
-            tc = sum*sum*0.0075 + texture(texture0, fragTexCoord);
-        }
-    }
+    // Texel color fetching from texture sampler
+    vec4 texelColor = texture(texture0, fragTexCoord);
     
-    fragColor = tc;
+    // Calculate final fragment color
+    if (texelColor.r < 0.3) tc = sum*sum*0.012 + texelColor;
+    else if (texelColor.r < 0.5) tc = sum*sum*0.009 + texelColor;
+    else tc = sum*sum*0.0075 + texelColor;
+
+    finalColor = tc;
 }
\ No newline at end of file
diff --git a/shaders/glsl330/blur.fs b/shaders/glsl330/blur.fs
index 44ea42b14..7c31f727a 100644
--- a/shaders/glsl330/blur.fs
+++ b/shaders/glsl330/blur.fs
@@ -1,12 +1,16 @@
 #version 330
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 
 const float renderWidth = 1280.0;
@@ -17,13 +21,14 @@ float weight[3] = float[](0.2270270270, 0.3162162162, 0.0702702703);
 
 void main()
 {
-    vec3 tc = texture(texture0, fragTexCoord).rgb*weight[0];
-
+    // Texel color fetching from texture sampler
+    vec3 texelColor = texture(texture0, fragTexCoord).rgb*weight[0];
+    
     for (int i = 1; i < 3; i++) 
     {
-        tc += texture(texture0, fragTexCoord + vec2(offset[i])/renderWidth, 0.0).rgb*weight[i];
-        tc += texture(texture0, fragTexCoord - vec2(offset[i])/renderWidth, 0.0).rgb*weight[i];
+        texelColor += texture(texture0, fragTexCoord + vec2(offset[i])/renderWidth, 0.0).rgb*weight[i];
+        texelColor += texture(texture0, fragTexCoord - vec2(offset[i])/renderWidth, 0.0).rgb*weight[i];
     }
 
-    fragColor = vec4(tc, 1.0);
+    finalColor = vec4(texelColor, 1.0);
 }
\ No newline at end of file
diff --git a/shaders/glsl330/cross_hatching.fs b/shaders/glsl330/cross_hatching.fs
index 6f5df9647..c12c48cd9 100644
--- a/shaders/glsl330/cross_hatching.fs
+++ b/shaders/glsl330/cross_hatching.fs
@@ -1,13 +1,17 @@
 #version 330
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
-// NOTE: Add here your custom variables 
+// Output fragment color
+out vec4 finalColor;
+
+// NOTE: Add here your custom variables
 
 float hatchOffsetY = 5.0;
 float lumThreshold01 = 0.9;
@@ -27,18 +31,18 @@ void main()
 
     if (lum < lumThreshold02) 
     {
-        if (mod(gl_FragCoord .x - gl_FragCoord .y, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0);
+        if (mod(gl_FragCoord.x - gl_FragCoord.y, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0);
     }
 
     if (lum < lumThreshold03) 
     {
-        if (mod(gl_FragCoord .x + gl_FragCoord .y - hatchOffsetY, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0);
+        if (mod(gl_FragCoord.x + gl_FragCoord.y - hatchOffsetY, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0);
     }
 
     if (lum < lumThreshold04) 
     {
-        if (mod(gl_FragCoord .x - gl_FragCoord .y - hatchOffsetY, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0);
+        if (mod(gl_FragCoord.x - gl_FragCoord.y - hatchOffsetY, 10.0) == 0.0) tc = vec3(0.0, 0.0, 0.0);
     }
 
-    fragColor = vec4(tc, 1.0);
+    finalColor = vec4(tc, 1.0);
 }
\ No newline at end of file
diff --git a/shaders/glsl330/cross_stitching.fs b/shaders/glsl330/cross_stitching.fs
index dcb26e79b..7c87c6cdf 100644
--- a/shaders/glsl330/cross_stitching.fs
+++ b/shaders/glsl330/cross_stitching.fs
@@ -1,12 +1,16 @@
 #version 330
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 
 const float renderWidth = 1280.0;
@@ -46,9 +50,9 @@ vec4 PostFX(sampler2D tex, vec2 uv)
     return c;
 }
 
-void main(void)
+void main()
 {
     vec3 tc = PostFX(texture0, fragTexCoord).rgb;
 
-    fragColor = vec4(tc, 1.0);
+    finalColor = vec4(tc, 1.0);
 }
\ No newline at end of file
diff --git a/shaders/glsl330/depth.fs b/shaders/glsl330/depth.fs
new file mode 100644
index 000000000..06d399f9f
--- /dev/null
+++ b/shaders/glsl330/depth.fs
@@ -0,0 +1,27 @@
+#version 330
+
+// Input vertex attributes (from vertex shader)
+in vec2 fragTexCoord;
+in vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;     // Depth texture
+uniform vec4 fragTintColor;
+
+// Output fragment color
+out vec4 finalColor;
+
+// NOTE: Add here your custom variables
+
+void main()
+{
+    float zNear = 0.01; // camera z near
+    float zFar = 10.0;  // camera z far
+    float z = texture(texture0, fragTexCoord).x;
+
+    // Linearize depth value
+    float depth = (2.0*zNear)/(zFar + zNear - z*(zFar - zNear));
+    
+    // Calculate final fragment color
+    finalColor = vec4(depth, depth, depth, 1.0f);
+}
\ No newline at end of file
diff --git a/shaders/glsl330/grayscale.fs b/shaders/glsl330/grayscale.fs
index b3a695bfb..d4a8824f6 100644
--- a/shaders/glsl330/grayscale.fs
+++ b/shaders/glsl330/grayscale.fs
@@ -1,20 +1,26 @@
 #version 330
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 
 void main()
 {
-    vec4 base = texture(texture0, fragTexCoord)*fragTintColor;
+    // Texel color fetching from texture sampler
+    vec4 texelColor = texture(texture0, fragTexCoord)*fragTintColor*fragColor;
     
-    // Convert to grayscale using NTSC conversion weights
-    float gray = dot(base.rgb, vec3(0.299, 0.587, 0.114));
+    // Convert texel color to grayscale using NTSC conversion weights
+    float gray = dot(texelColor.rgb, vec3(0.299, 0.587, 0.114));
     
-    fragColor = vec4(gray, gray, gray, fragTintColor.a);
+    // Calculate final fragment color
+    finalColor = vec4(gray, gray, gray, texelColor.a);
 }
\ No newline at end of file
diff --git a/shaders/glsl330/phong.fs b/shaders/glsl330/phong.fs
index 75b7e6d73..c14b346a9 100644
--- a/shaders/glsl330/phong.fs
+++ b/shaders/glsl330/phong.fs
@@ -1,76 +1,85 @@
 #version 330
 
-// Vertex shader input data
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
 in vec3 fragNormal;
 
-// Diffuse data
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
-// Light attributes
-uniform vec3 light_ambientColor = vec3(0.6, 0.3, 0);
-uniform vec3 light_diffuseColor = vec3(1, 0.5, 0);
-uniform vec3 light_specularColor = vec3(0, 1, 0);
-uniform float light_intensity = 1;
-uniform float light_specIntensity = 1;
+// Output fragment color
+out vec4 finalColor;
 
-// Material attributes
-uniform vec3 mat_ambientColor = vec3(1, 1, 1);
-uniform vec3 mat_specularColor = vec3(1, 1, 1);
-uniform float mat_glossiness = 50;
+// NOTE: Add here your custom variables
 
-// World attributes
-uniform vec3 lightPos;
-uniform vec3 cameraPos;
+// Light uniform values
+uniform vec3 lightAmbientColor = vec3(0.6, 0.3, 0.0);
+uniform vec3 lightDiffuseColor = vec3(1.0, 0.5, 0.0);
+uniform vec3 lightSpecularColor = vec3(0.0, 1.0, 0.0);
+uniform float lightIntensity = 1.0;
+uniform float lightSpecIntensity = 1.0;
+
+// Material uniform values
+uniform vec3 matAmbientColor = vec3(1.0, 1.0, 1.0);
+uniform vec3 matSpecularColor = vec3(1.0, 1.0, 1.0);
+uniform float matGlossiness = 50.0;
+
+// World uniform values
+uniform vec3 lightPosition;
+uniform vec3 cameraPosition;
 
 // Fragment shader output data
 out vec4 fragColor;
 
+// Calculate ambient lighting component
 vec3 AmbientLighting()
 {
-   return mat_ambientColor * light_ambientColor;
+    return (matAmbientColor*lightAmbientColor);
 }
 
+// Calculate diffuse lighting component
 vec3 DiffuseLighting(in vec3 N, in vec3 L)
 {
-   // Lambertian reflection calculation
-   float diffuse = clamp(dot(N, L), 0, 1);
-   
-   return tintColor.xyz * light_diffuseColor * light_intensity * diffuse;
+    // Lambertian reflection calculation
+    float diffuse = clamp(dot(N, L), 0, 1);
+
+    return (fragTintColor.xyz*lightDiffuseColor*lightIntensity*diffuse);
 }
 
+// Calculate specular lighting component
 vec3 SpecularLighting(in vec3 N, in vec3 L, in vec3 V)
 {
-   float specular = 0;
-
-   // Calculate specular reflection only if the surface is oriented to the light source
-   if(dot(N, L) > 0)
-   {
-      // Calculate half vector
-      vec3 H = normalize(L + V);
-      
-      // Calculate specular intensity
-      specular = pow(dot(N, H), 3 + mat_glossiness);
-   }
+    float specular = 0.0;
+
+    // Calculate specular reflection only if the surface is oriented to the light source
+    if (dot(N, L) > 0)
+    {
+        // Calculate half vector
+        vec3 H = normalize(L + V);
+
+        // Calculate specular intensity
+        specular = pow(dot(N, H), 3 + matGlossiness);
+    }
    
-   return mat_specularColor * light_specularColor * light_specIntensity * specular;
+    return (matSpecularColor*lightSpecularColor*lightSpecIntensity*specular);
 }
 
 void main()
 {
     // Normalize input vectors
-    vec3 L = normalize(lightPos);
-    vec3 V = normalize(cameraPos);
+    vec3 L = normalize(lightPosition);
+    vec3 V = normalize(cameraPosition);
     vec3 N = normalize(fragNormal);
     
+    // Calculate lighting components 
     vec3 ambient = AmbientLighting();
     vec3 diffuse = DiffuseLighting(N, L);
     vec3 specular = SpecularLighting(N, L, V);
     
-    // Get base color from texture
-    vec4 textureColor = texture(texture0, fragTexCoord);
-    vec3 finalColor = textureColor.rgb;
-    
-    fragColor = vec4(finalColor * (ambient + diffuse + specular), textureColor.a);
+    // Texel color fetching from texture sampler
+    vec4 texelColor = texture(texture0, fragTexCoord);
+
+    // Calculate final fragment color
+    finalColor = vec4(texelColor.rgb*(ambient + diffuse + specular), texelColor.a);
 }
\ No newline at end of file
diff --git a/shaders/glsl330/phong.vs b/shaders/glsl330/phong.vs
index ee6d34bfa..d68d9b3fc 100644
--- a/shaders/glsl330/phong.vs
+++ b/shaders/glsl330/phong.vs
@@ -1,23 +1,25 @@
 #version 330
 
-// Vertex input data
+// Input vertex attributes
 in vec3 vertexPosition;
 in vec2 vertexTexCoord;
 in vec3 vertexNormal;
 
-// Projection and model data
+// Input uniform values
 uniform mat4 mvpMatrix;
-uniform mat4 modelMatrix;
 
-// Attributes to fragment shader
+// Output vertex attributes (to fragment shader)
 out vec2 fragTexCoord;
 out vec3 fragNormal;
 
+// NOTE: Add here your custom variables
+uniform mat4 modelMatrix;
+
 void main()
 {
-    // Send texture coord to fragment shader
+    // Send vertex attributes to fragment shader
     fragTexCoord = vertexTexCoord;
-    
+
     // Calculate view vector normal from model
     mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));
     fragNormal = normalize(normalMatrix*vertexNormal);
diff --git a/shaders/glsl330/pixel.fs b/shaders/glsl330/pixel.fs
index aa5a22fe1..9ed3ea7d0 100644
--- a/shaders/glsl330/pixel.fs
+++ b/shaders/glsl330/pixel.fs
@@ -1,13 +1,17 @@
 #version 330
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
-// NOTE: Add here your custom variables 
+// Output fragment color
+out vec4 finalColor;
+
+// NOTE: Add here your custom variables
 
 const float renderWidth = 1280.0;
 const float renderHeight = 720.0;
@@ -24,5 +28,5 @@ void main()
 
     vec3 tc = texture(texture0, coord).rgb;
 
-    fragColor = vec4(tc, 1.0);
+    finalColor = vec4(tc, 1.0);
 }
\ No newline at end of file
diff --git a/shaders/glsl330/posterization.fs b/shaders/glsl330/posterization.fs
index 5215bd8bc..f1d72a196 100644
--- a/shaders/glsl330/posterization.fs
+++ b/shaders/glsl330/posterization.fs
@@ -1,12 +1,16 @@
 #version 330
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 
 float gamma = 0.6;
@@ -14,13 +18,14 @@ float numColors = 8.0;
 
 void main()
 {
-    vec3 color = texture(texture0, fragTexCoord.xy).rgb;
+    // Texel color fetching from texture sampler
+    vec3 texelColor = texture(texture0, fragTexCoord.xy).rgb;
     
-    color = pow(color, vec3(gamma, gamma, gamma));
-    color = color*numColors;
-    color = floor(color);
-    color = color/numColors;
-    color = pow(color, vec3(1.0/gamma));
+    texelColor = pow(texelColor, vec3(gamma, gamma, gamma));
+    texelColor = texelColor*numColors;
+    texelColor = floor(texelColor);
+    texelColor = texelColor/numColors;
+    texelColor = pow(texelColor, vec3(1.0/gamma));
     
-    fragColor = vec4(color, 1.0);
+    finalColor = vec4(texelColor, 1.0);
 }
\ No newline at end of file
diff --git a/shaders/glsl330/predator.fs b/shaders/glsl330/predator.fs
index 85c93d0cd..9269dfd4c 100644
--- a/shaders/glsl330/predator.fs
+++ b/shaders/glsl330/predator.fs
@@ -1,27 +1,32 @@
 #version 330
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 
 void main()
 {
-    vec3 color = texture(texture0, fragTexCoord).rgb;
+    // Texel color fetching from texture sampler
+    vec3 texelColor = texture(texture0, fragTexCoord).rgb;
     vec3 colors[3];
     colors[0] = vec3(0.0, 0.0, 1.0);
     colors[1] = vec3(1.0, 1.0, 0.0);
     colors[2] = vec3(1.0, 0.0, 0.0);
     
-    float lum = (color.r + color.g + color.b)/3.0;
+    float lum = (texelColor.r + texelColor.g + texelColor.b)/3.0;
     
     int ix = (lum < 0.5)? 0:1;
     
     vec3 tc = mix(colors[ix], colors[ix + 1], (lum - float(ix)*0.5)/0.5);
     
-    fragColor = vec4(tc, 1.0);
+    finalColor = vec4(tc, 1.0);
 }
\ No newline at end of file
diff --git a/shaders/glsl330/scanlines.fs b/shaders/glsl330/scanlines.fs
index 0c89e6107..177f000df 100644
--- a/shaders/glsl330/scanlines.fs
+++ b/shaders/glsl330/scanlines.fs
@@ -1,12 +1,16 @@
 #version 330
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 
 float offset = 0.0;
@@ -14,7 +18,7 @@ float frequency = 720.0/3.0;
 
 uniform float time;
 
-void main (void)
+void main()
 {
 /*
     // Scanlines method 1
@@ -35,7 +39,8 @@ void main (void)
     float globalPos = (fragTexCoord.y + offset) * frequency;
     float wavePos = cos((fract(globalPos) - 0.5)*3.14);
     
-    vec4 color = texture(texture0, fragTexCoord);
+    // Texel color fetching from texture sampler
+    vec4 texelColor = texture(texture0, fragTexCoord);
 
-    fragColor = mix(vec4(0.0, 0.3, 0.0, 0.0), color, wavePos);
+    finalColor = mix(vec4(0.0, 0.3, 0.0, 0.0), texelColor, wavePos);
 }
\ No newline at end of file
diff --git a/shaders/glsl330/swirl.fs b/shaders/glsl330/swirl.fs
index 19d7468b1..80c16cc9e 100644
--- a/shaders/glsl330/swirl.fs
+++ b/shaders/glsl330/swirl.fs
@@ -1,27 +1,32 @@
 #version 330
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 
-const float renderWidth = 1280.0; 
-const float renderHeight = 720.0; 
+const float renderWidth = 800.0;      // HARDCODED for example!
+const float renderHeight = 480.0;     // Use uniforms instead...
 
 float radius = 250.0;
 float angle = 0.8;
 
 uniform vec2 center = vec2(200.0, 200.0);
 
-void main (void)
+void main()
 {
     vec2 texSize = vec2(renderWidth, renderHeight);
     vec2 tc = fragTexCoord*texSize;
     tc -= center;
+    
     float dist = length(tc);
 
     if (dist < radius) 
@@ -37,5 +42,5 @@ void main (void)
     tc += center;
     vec3 color = texture(texture0, tc/texSize).rgb;
 
-    fragColor = vec4(color, 1.0);;
+    finalColor = vec4(color, 1.0);;
 }
\ No newline at end of file
diff --git a/shaders/glsl330/template.fs b/shaders/glsl330/template.fs
index ad7210a4c..55b8d4a49 100644
--- a/shaders/glsl330/template.fs
+++ b/shaders/glsl330/template.fs
@@ -1,19 +1,24 @@
 #version 330
 
+// Input vertex attributes (from vertex shader)
 in vec2 fragTexCoord;
+in vec4 fragColor;
 
-out vec4 fragColor;
-
+// Input uniform values
 uniform sampler2D texture0;
 uniform vec4 fragTintColor;
 
+// Output fragment color
+out vec4 finalColor;
+
 // NOTE: Add here your custom variables
 
 void main()
 {
+    // Texel color fetching from texture sampler
     vec4 texelColor = texture(texture0, fragTexCoord);
     
     // NOTE: Implement here your fragment shader code
     
-    fragColor = texelColor*fragTintColor;
+    finalColor = texelColor*fragTintColor;
 }

From 037edbaa1322a2174d91c7aeacc9170f5b6913cb Mon Sep 17 00:00:00 2001
From: raysan5 <raysan5@gmail.com>
Date: Wed, 18 May 2016 13:22:14 +0200
Subject: [PATCH 13/33] Reorganize data for consistency

---
 src/models.c |  54 ++-----
 src/rlgl.c   | 431 +++++++++++++++++++++++++++++++--------------------
 src/rlgl.h   |   9 +-
 3 files changed, 283 insertions(+), 211 deletions(-)

diff --git a/src/models.c b/src/models.c
index 066b919ed..bb2d56c25 100644
--- a/src/models.c
+++ b/src/models.c
@@ -691,31 +691,14 @@ Model LoadCubicmap(Image cubicmap)
     return model;
 }
 
-// Unload 3d model from memory
+// Unload 3d model from memory (mesh and material)
 void UnloadModel(Model model)
 {
-    // Unload mesh data
-    if (model.mesh.vertices != NULL) free(model.mesh.vertices);
-    if (model.mesh.texcoords != NULL) free(model.mesh.texcoords);
-    if (model.mesh.normals != NULL) free(model.mesh.normals);
-    if (model.mesh.colors != NULL) free(model.mesh.colors);
-    if (model.mesh.tangents != NULL) free(model.mesh.tangents);
-    if (model.mesh.texcoords2 != NULL) free(model.mesh.texcoords2);
-    if (model.mesh.indices != NULL) free(model.mesh.indices);
-    
-    TraceLog(INFO, "Unloaded model data from RAM (CPU)");
-    
-    rlDeleteBuffers(model.mesh.vboId[0]);   // vertex
-    rlDeleteBuffers(model.mesh.vboId[1]);   // texcoords
-    rlDeleteBuffers(model.mesh.vboId[2]);   // normals
-    rlDeleteBuffers(model.mesh.vboId[3]);   // colors
-    rlDeleteBuffers(model.mesh.vboId[4]);   // tangents
-    rlDeleteBuffers(model.mesh.vboId[5]);   // texcoords2
-    rlDeleteBuffers(model.mesh.vboId[6]);   // indices
-
-    rlDeleteVertexArrays(model.mesh.vaoId);
-    
+    rlglUnloadMesh(&model.mesh);
+
     UnloadMaterial(model.material);
+    
+    TraceLog(INFO, "Unloaded model data from RAM and VRAM");
 }
 
 // Load material data (from file)
@@ -1247,40 +1230,27 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
     model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
     model.material.colDiffuse = tint;
     
-    rlglDrawEx(model.mesh, model.material, model.transform, false);
+    rlglDrawMesh(model.mesh, model.material, model.transform);
 }
 
 // Draw a model wires (with texture if set)
 void DrawModelWires(Model model, Vector3 position, float scale, Color tint)
 {
-    Vector3 vScale = { scale, scale, scale };
-    Vector3 rotationAxis = { 0.0f, 0.0f, 0.0f };
-
-    // Calculate transformation matrix from function parameters
-    // Get transform matrix (rotation -> scale -> translation)
-    Matrix matRotation = MatrixRotate(rotationAxis, 0.0f);
-    Matrix matScale = MatrixScale(vScale.x, vScale.y, vScale.z);
-    Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
+    rlEnableWireMode();
     
-    model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
-    model.material.colDiffuse = tint;
+    DrawModel(model, position, scale, tint);
     
-    rlglDrawEx(model.mesh, model.material, model.transform, true);
+    rlDisableWireMode();
 }
 
 // Draw a model wires (with texture if set) with extended parameters
 void DrawModelWiresEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
 {
-    // Calculate transformation matrix from function parameters
-    // Get transform matrix (rotation -> scale -> translation)
-    Matrix matRotation = MatrixRotate(rotationAxis, rotationAngle*DEG2RAD);
-    Matrix matScale = MatrixScale(scale.x, scale.y, scale.z);
-    Matrix matTranslation = MatrixTranslate(position.x, position.y, position.z);
+    rlEnableWireMode();
     
-    model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
-    model.material.colDiffuse = tint;
+    DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);
     
-    rlglDrawEx(model.mesh, model.material, model.transform, true);
+    rlDisableWireMode();
 }
 
 // Draw a billboard
diff --git a/src/rlgl.c b/src/rlgl.c
index 0c0da2218..8e7255219 100644
--- a/src/rlgl.c
+++ b/src/rlgl.c
@@ -740,6 +740,24 @@ void rlDisableDepthTest(void)
     glDisable(GL_DEPTH_TEST);
 }
 
+// Enable wire mode
+void rlEnableWireMode(void)
+{
+#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
+    // NOTE: glPolygonMode() not available on OpenGL ES
+    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+#endif
+}
+
+// Disable wire mode
+void rlDisableWireMode(void)
+{
+#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
+    // NOTE: glPolygonMode() not available on OpenGL ES
+    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+#endif
+}
+
 // Unload texture from GPU memory
 void rlDeleteTextures(unsigned int id)
 {
@@ -1033,175 +1051,15 @@ void rlglClose(void)
 void rlglDraw(void)
 {
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-    UpdateDefaultBuffers();
-    DrawDefaultBuffers();
-#endif
-}
-
-// Draw a 3d mesh with material and transform
-void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires)
-{
-#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
-    // NOTE: glPolygonMode() not available on OpenGL ES
-    if (wires) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-#endif
-
-#if defined(GRAPHICS_API_OPENGL_11)
-    glEnable(GL_TEXTURE_2D);
-    glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id);
-
-    // NOTE: On OpenGL 1.1 we use Vertex Arrays to draw model
-    glEnableClientState(GL_VERTEX_ARRAY);                   // Enable vertex array
-    glEnableClientState(GL_TEXTURE_COORD_ARRAY);            // Enable texture coords array
-    if (mesh.normals != NULL) glEnableClientState(GL_NORMAL_ARRAY);     // Enable normals array
-    if (mesh.colors != NULL) glEnableClientState(GL_COLOR_ARRAY);       // Enable colors array
-
-    glVertexPointer(3, GL_FLOAT, 0, mesh.vertices);         // Pointer to vertex coords array
-    glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords);      // Pointer to texture coords array
-    if (mesh.normals != NULL) glNormalPointer(GL_FLOAT, 0, mesh.normals);           // Pointer to normals array
-    if (mesh.colors != NULL) glColorPointer(4, GL_UNSIGNED_BYTE, 0, mesh.colors);   // Pointer to colors array
-
-    rlPushMatrix();
-        rlMultMatrixf(MatrixToFloat(transform));
-        rlColor4ub(material.colDiffuse.r, material.colDiffuse.g, material.colDiffuse.b, material.colDiffuse.a);
-        
-        if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, mesh.indices);
-        else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
-    rlPopMatrix();
-
-    glDisableClientState(GL_VERTEX_ARRAY);                  // Disable vertex array
-    glDisableClientState(GL_TEXTURE_COORD_ARRAY);           // Disable texture coords array
-    if (mesh.normals != NULL) glDisableClientState(GL_NORMAL_ARRAY);    // Disable normals array
-    if (mesh.colors != NULL) glDisableClientState(GL_NORMAL_ARRAY);     // Disable colors array
-
-    glDisable(GL_TEXTURE_2D);
-    glBindTexture(GL_TEXTURE_2D, 0);
-#endif
-
-#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
-    glUseProgram(material.shader.id);
-    
-    // At this point the modelview matrix just contains the view matrix (camera)
-    // That's because Begin3dMode() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix()
-    Matrix matView = modelview;         // View matrix (camera)
-    Matrix matProjection = projection;  // Projection matrix (perspective)
-
-    // Calculate model-view matrix combining matModel and matView
-    Matrix matModelView = MatrixMultiply(transform, matView);           // Transform to camera-space coordinates
-
-    // Calculate model-view-projection matrix (MVP)
-    Matrix matMVP = MatrixMultiply(matModelView, matProjection);        // Transform to screen-space coordinates
-
-    // Send combined model-view-projection matrix to shader
-    glUniformMatrix4fv(material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP));
-
-    // Apply color tinting (material.colDiffuse)
-    // NOTE: Just update one uniform on fragment shader
-    float vColor[4] = { (float)material.colDiffuse.r/255, (float)material.colDiffuse.g/255, (float)material.colDiffuse.b/255, (float)material.colDiffuse.a/255 };
-    glUniform4fv(material.shader.tintColorLoc, 1, vColor);
-
-    // Set shader textures (diffuse, normal, specular)
-    glActiveTexture(GL_TEXTURE0);
-    glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id);
-    glUniform1i(material.shader.mapDiffuseLoc, 0);        // Texture fits in active texture unit 0
-    
-    if ((material.texNormal.id != 0) && (material.shader.mapNormalLoc != -1))
-    {
-        glActiveTexture(GL_TEXTURE1);
-        glBindTexture(GL_TEXTURE_2D, material.texNormal.id);
-        glUniform1i(material.shader.mapNormalLoc, 1);     // Texture fits in active texture unit 1
-    }
-    
-    if ((material.texSpecular.id != 0) && (material.shader.mapSpecularLoc != -1))
-    {
-        glActiveTexture(GL_TEXTURE2);
-        glBindTexture(GL_TEXTURE_2D, material.texSpecular.id);
-        glUniform1i(material.shader.mapSpecularLoc, 2);   // Texture fits in active texture unit 2
-    }
-
-    if (vaoSupported)
-    {
-        glBindVertexArray(mesh.vaoId);
-    }
-    else
-    {
-        // Bind mesh VBO data: vertex position (shader-location = 0)
-        glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
-        glVertexAttribPointer(material.shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
-        glEnableVertexAttribArray(material.shader.vertexLoc);
-
-        // Bind mesh VBO data: vertex texcoords (shader-location = 1)
-        glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
-        glVertexAttribPointer(material.shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
-        glEnableVertexAttribArray(material.shader.texcoordLoc);
-
-        // Bind mesh VBO data: vertex normals (shader-location = 2, if available)
-        if (material.shader.normalLoc != -1)
-        {
-            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]);
-            glVertexAttribPointer(material.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0);
-            glEnableVertexAttribArray(material.shader.normalLoc);
-        }
-        
-        // Bind mesh VBO data: vertex colors (shader-location = 3, if available) , tangents, texcoords2 (if available)
-        if (material.shader.colorLoc != -1)
-        {
-            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[3]);
-            glVertexAttribPointer(material.shader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
-            glEnableVertexAttribArray(material.shader.colorLoc);
-        }
-        
-        // Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
-        if (material.shader.tangentLoc != -1)
-        {
-            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]);
-            glVertexAttribPointer(material.shader.tangentLoc, 3, GL_FLOAT, 0, 0, 0);
-            glEnableVertexAttribArray(material.shader.tangentLoc);
-        }
-        
-        // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
-        if (material.shader.texcoord2Loc != -1)
-        {
-            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[5]);
-            glVertexAttribPointer(material.shader.texcoord2Loc, 2, GL_FLOAT, 0, 0, 0);
-            glEnableVertexAttribArray(material.shader.texcoord2Loc);
-        }
-        
-        if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]);
-    }
-
-    // Draw call!
-    if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, 0); // Indexed vertices draw
-    else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
-    
-    if (material.texNormal.id != 0)
-    {
-        glActiveTexture(GL_TEXTURE1);
-        glBindTexture(GL_TEXTURE_2D, 0);
-    }
-    
-    if (material.texSpecular.id != 0)
-    {
-        glActiveTexture(GL_TEXTURE2);
-        glBindTexture(GL_TEXTURE_2D, 0);
-    }
-
-    glActiveTexture(GL_TEXTURE0);               // Set shader active texture to default 0
-    glBindTexture(GL_TEXTURE_2D, 0);            // Unbind textures
-
-    if (vaoSupported) glBindVertexArray(0);     // Unbind VAO
-    else
+/*
+    for (int i = 0; i < modelsCount; i++)
     {
-        glBindBuffer(GL_ARRAY_BUFFER, 0);      // Unbind VBOs
-        if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+        rlglDrawMesh(models[i]->mesh, models[i]->material, models[i]->transform);
     }
-
-    glUseProgram(0);        // Unbind shader program
-#endif
-
-#if defined (GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33)
-    // NOTE: glPolygonMode() not available on OpenGL ES
-    if (wires) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+*/
+    // NOTE: Default buffers always drawn at the end
+    UpdateDefaultBuffers();
+    DrawDefaultBuffers();
 #endif
 }
 
@@ -1776,6 +1634,245 @@ void rlglLoadMesh(Mesh *mesh)
 #endif
 }
 
+// Update vertex data on GPU (upload new data to one buffer)
+void rlglUpdateMesh(Mesh mesh, int buffer, int numVertex)
+{
+    // Activate mesh VAO
+    if (vaoSupported) glBindVertexArray(mesh.vaoId);
+        
+    switch (buffer)
+    {
+        case 0:     // Update vertices (vertex position)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
+            if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*numVertex, mesh.vertices, GL_DYNAMIC_DRAW);
+            else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*numVertex, mesh.vertices);
+            
+        } break;
+        case 1:     // Update texcoords (vertex texture coordinates)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
+            if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*numVertex, mesh.texcoords, GL_DYNAMIC_DRAW);
+            else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*numVertex, mesh.texcoords);
+            
+        } break;
+        case 2:     // Update normals (vertex normals)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
+            if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*numVertex, mesh.normals, GL_DYNAMIC_DRAW);
+            else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*numVertex, mesh.normals);
+            
+        } break;
+        case 3:     // Update colors (vertex colors)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]);
+            if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*numVertex, mesh.colors, GL_DYNAMIC_DRAW);
+            else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*numVertex, mesh.colors);
+            
+        } break;
+        case 4:     // Update tangents (vertex tangents)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
+            if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*numVertex, mesh.tangents, GL_DYNAMIC_DRAW);
+            else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*numVertex, mesh.tangents);
+        } break;
+        case 5:     // Update texcoords2 (vertex second texture coordinates)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
+            if (numVertex >= mesh.vertexCount) glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*numVertex, mesh.texcoords2, GL_DYNAMIC_DRAW);
+            else glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*numVertex, mesh.texcoords2);
+        } break;
+        default: break;
+    }
+    
+    // Unbind the current VAO
+    if (vaoSupported) glBindVertexArray(0);
+
+    // Another option would be using buffer mapping...
+    //mesh.vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
+    // Now we can modify vertices
+    //glUnmapBuffer(GL_ARRAY_BUFFER);
+}
+
+// Draw a 3d mesh with material and transform
+void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
+{
+#if defined(GRAPHICS_API_OPENGL_11)
+    glEnable(GL_TEXTURE_2D);
+    glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id);
+
+    // NOTE: On OpenGL 1.1 we use Vertex Arrays to draw model
+    glEnableClientState(GL_VERTEX_ARRAY);                   // Enable vertex array
+    glEnableClientState(GL_TEXTURE_COORD_ARRAY);            // Enable texture coords array
+    if (mesh.normals != NULL) glEnableClientState(GL_NORMAL_ARRAY);     // Enable normals array
+    if (mesh.colors != NULL) glEnableClientState(GL_COLOR_ARRAY);       // Enable colors array
+
+    glVertexPointer(3, GL_FLOAT, 0, mesh.vertices);         // Pointer to vertex coords array
+    glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords);      // Pointer to texture coords array
+    if (mesh.normals != NULL) glNormalPointer(GL_FLOAT, 0, mesh.normals);           // Pointer to normals array
+    if (mesh.colors != NULL) glColorPointer(4, GL_UNSIGNED_BYTE, 0, mesh.colors);   // Pointer to colors array
+
+    rlPushMatrix();
+        rlMultMatrixf(MatrixToFloat(transform));
+        rlColor4ub(material.colDiffuse.r, material.colDiffuse.g, material.colDiffuse.b, material.colDiffuse.a);
+        
+        if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, mesh.indices);
+        else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
+    rlPopMatrix();
+
+    glDisableClientState(GL_VERTEX_ARRAY);                  // Disable vertex array
+    glDisableClientState(GL_TEXTURE_COORD_ARRAY);           // Disable texture coords array
+    if (mesh.normals != NULL) glDisableClientState(GL_NORMAL_ARRAY);    // Disable normals array
+    if (mesh.colors != NULL) glDisableClientState(GL_NORMAL_ARRAY);     // Disable colors array
+
+    glDisable(GL_TEXTURE_2D);
+    glBindTexture(GL_TEXTURE_2D, 0);
+#endif
+
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+    glUseProgram(material.shader.id);
+    
+    // At this point the modelview matrix just contains the view matrix (camera)
+    // That's because Begin3dMode() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix()
+    Matrix matView = modelview;         // View matrix (camera)
+    Matrix matProjection = projection;  // Projection matrix (perspective)
+
+    // Calculate model-view matrix combining matModel and matView
+    Matrix matModelView = MatrixMultiply(transform, matView);           // Transform to camera-space coordinates
+
+    // Calculate model-view-projection matrix (MVP)
+    Matrix matMVP = MatrixMultiply(matModelView, matProjection);        // Transform to screen-space coordinates
+
+    // Send combined model-view-projection matrix to shader
+    glUniformMatrix4fv(material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP));
+
+    // Apply color tinting (material.colDiffuse)
+    // NOTE: Just update one uniform on fragment shader
+    float vColor[4] = { (float)material.colDiffuse.r/255, (float)material.colDiffuse.g/255, (float)material.colDiffuse.b/255, (float)material.colDiffuse.a/255 };
+    glUniform4fv(material.shader.tintColorLoc, 1, vColor);
+
+    // Set shader textures (diffuse, normal, specular)
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id);
+    glUniform1i(material.shader.mapDiffuseLoc, 0);        // Texture fits in active texture unit 0
+    
+    if ((material.texNormal.id != 0) && (material.shader.mapNormalLoc != -1))
+    {
+        glActiveTexture(GL_TEXTURE1);
+        glBindTexture(GL_TEXTURE_2D, material.texNormal.id);
+        glUniform1i(material.shader.mapNormalLoc, 1);     // Texture fits in active texture unit 1
+    }
+    
+    if ((material.texSpecular.id != 0) && (material.shader.mapSpecularLoc != -1))
+    {
+        glActiveTexture(GL_TEXTURE2);
+        glBindTexture(GL_TEXTURE_2D, material.texSpecular.id);
+        glUniform1i(material.shader.mapSpecularLoc, 2);   // Texture fits in active texture unit 2
+    }
+
+    if (vaoSupported)
+    {
+        glBindVertexArray(mesh.vaoId);
+    }
+    else
+    {
+        // Bind mesh VBO data: vertex position (shader-location = 0)
+        glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[0]);
+        glVertexAttribPointer(material.shader.vertexLoc, 3, GL_FLOAT, 0, 0, 0);
+        glEnableVertexAttribArray(material.shader.vertexLoc);
+
+        // Bind mesh VBO data: vertex texcoords (shader-location = 1)
+        glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[1]);
+        glVertexAttribPointer(material.shader.texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
+        glEnableVertexAttribArray(material.shader.texcoordLoc);
+
+        // Bind mesh VBO data: vertex normals (shader-location = 2, if available)
+        if (material.shader.normalLoc != -1)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[2]);
+            glVertexAttribPointer(material.shader.normalLoc, 3, GL_FLOAT, 0, 0, 0);
+            glEnableVertexAttribArray(material.shader.normalLoc);
+        }
+        
+        // Bind mesh VBO data: vertex colors (shader-location = 3, if available) , tangents, texcoords2 (if available)
+        if (material.shader.colorLoc != -1)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[3]);
+            glVertexAttribPointer(material.shader.colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
+            glEnableVertexAttribArray(material.shader.colorLoc);
+        }
+        
+        // Bind mesh VBO data: vertex tangents (shader-location = 4, if available)
+        if (material.shader.tangentLoc != -1)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[4]);
+            glVertexAttribPointer(material.shader.tangentLoc, 3, GL_FLOAT, 0, 0, 0);
+            glEnableVertexAttribArray(material.shader.tangentLoc);
+        }
+        
+        // Bind mesh VBO data: vertex texcoords2 (shader-location = 5, if available)
+        if (material.shader.texcoord2Loc != -1)
+        {
+            glBindBuffer(GL_ARRAY_BUFFER, mesh.vboId[5]);
+            glVertexAttribPointer(material.shader.texcoord2Loc, 2, GL_FLOAT, 0, 0, 0);
+            glEnableVertexAttribArray(material.shader.texcoord2Loc);
+        }
+        
+        if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quads.vboId[3]);
+    }
+
+    // Draw call!
+    if (mesh.indices != NULL) glDrawElements(GL_TRIANGLES, mesh.triangleCount*3, GL_UNSIGNED_SHORT, 0); // Indexed vertices draw
+    else glDrawArrays(GL_TRIANGLES, 0, mesh.vertexCount);
+    
+    if (material.texNormal.id != 0)
+    {
+        glActiveTexture(GL_TEXTURE1);
+        glBindTexture(GL_TEXTURE_2D, 0);
+    }
+    
+    if (material.texSpecular.id != 0)
+    {
+        glActiveTexture(GL_TEXTURE2);
+        glBindTexture(GL_TEXTURE_2D, 0);
+    }
+
+    glActiveTexture(GL_TEXTURE0);               // Set shader active texture to default 0
+    glBindTexture(GL_TEXTURE_2D, 0);            // Unbind textures
+
+    if (vaoSupported) glBindVertexArray(0);     // Unbind VAO
+    else
+    {
+        glBindBuffer(GL_ARRAY_BUFFER, 0);      // Unbind VBOs
+        if (mesh.indices != NULL) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    }
+
+    glUseProgram(0);        // Unbind shader program
+#endif
+}
+
+// Unload mesh data from CPU and GPU
+void rlglUnloadMesh(Mesh *mesh)
+{
+    if (mesh->vertices != NULL) free(mesh->vertices);
+    if (mesh->texcoords != NULL) free(mesh->texcoords);
+    if (mesh->normals != NULL) free(mesh->normals);
+    if (mesh->colors != NULL) free(mesh->colors);
+    if (mesh->tangents != NULL) free(mesh->tangents);
+    if (mesh->texcoords2 != NULL) free(mesh->texcoords2);
+    if (mesh->indices != NULL) free(mesh->indices);
+
+    rlDeleteBuffers(mesh->vboId[0]);   // vertex
+    rlDeleteBuffers(mesh->vboId[1]);   // texcoords
+    rlDeleteBuffers(mesh->vboId[2]);   // normals
+    rlDeleteBuffers(mesh->vboId[3]);   // colors
+    rlDeleteBuffers(mesh->vboId[4]);   // tangents
+    rlDeleteBuffers(mesh->vboId[5]);   // texcoords2
+    rlDeleteBuffers(mesh->vboId[6]);   // indices
+
+    rlDeleteVertexArrays(mesh->vaoId);
+}
+
 // Read screen pixel data (color buffer)
 unsigned char *rlglReadScreenPixels(int width, int height)
 {
diff --git a/src/rlgl.h b/src/rlgl.h
index 7b88bc9ea..a33e3a0a1 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -256,6 +256,8 @@ void rlEnableRenderTexture(unsigned int id);    // Enable render texture (fbo)
 void rlDisableRenderTexture(void);              // Disable render texture (fbo), return to default framebuffer
 void rlEnableDepthTest(void);                   // Enable depth test
 void rlDisableDepthTest(void);                  // Disable depth test
+void rlEnableWireMode(void);                    // Enable wire mode
+void rlDisableWireMode(void);                   // Disable wire mode
 void rlDeleteTextures(unsigned int id);         // Delete OpenGL texture from GPU
 void rlDeleteRenderTextures(RenderTexture2D target);    // Delete render textures (fbo) from GPU
 void rlDeleteShader(unsigned int id);           // Delete OpenGL shader program from GPU
@@ -277,8 +279,11 @@ unsigned int rlglLoadTexture(void *data, int width, int height, int textureForma
 RenderTexture2D rlglLoadRenderTexture(int width, int height);   // Load a texture to be used for rendering (fbo with color and depth attachments)
 void rlglUpdateTexture(unsigned int id, int width, int height, int format, void *data);         // Update GPU texture with new data
 void rlglGenerateMipmaps(Texture2D texture);                             // Generate mipmap data for selected texture
-void rlglLoadMesh(Mesh *mesh);           // Upload vertex data into GPU and provided VAO/VBO ids
-void rlglDrawEx(Mesh mesh, Material material, Matrix transform, bool wires);
+
+void rlglLoadMesh(Mesh *mesh);                                      // Upload vertex data into GPU and provided VAO/VBO ids
+void rlglUpdateMesh(Mesh mesh, int buffer, int numVertex);          // Update vertex data on GPU (upload new data to one buffer)
+void rlglDrawMesh(Mesh mesh, Material material, Matrix transform);  // Draw a 3d mesh with material and transform
+void rlglUnloadMesh(Mesh *mesh);                                    // Unload mesh data from CPU and GPU
 
 Vector3 rlglUnproject(Vector3 source, Matrix proj, Matrix view);    // Get world coordinates from screen coordinates
 

From 8bbbe8cd76d93bc85810fd13a6cb6c4df18bd30d Mon Sep 17 00:00:00 2001
From: raysan5 <raysan5@gmail.com>
Date: Thu, 19 May 2016 13:50:29 +0200
Subject: [PATCH 14/33] Corrected namings

---
 src/rlgl.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/rlgl.c b/src/rlgl.c
index 8e7255219..888a93131 100644
--- a/src/rlgl.c
+++ b/src/rlgl.c
@@ -2425,12 +2425,12 @@ static void LoadDefaultShaderLocations(Shader *shader)
     //          vertex texcoord2 location = 5
     
     // Get handles to GLSL input attibute locations
-    shader->vertexLoc = glGetAttribLocation(shader->id, "vertexPosition");
-    shader->texcoordLoc = glGetAttribLocation(shader->id, "vertexTexCoord");
-    shader->normalLoc = glGetAttribLocation(shader->id, "vertexNormal");
-    shader->colorLoc = glGetAttribLocation(shader->id, "vertexColor");
-    shader->tangentLoc = glGetAttribLocation(shader->id, "vertexTangent");
-    shader->texcoord2Loc = glGetAttribLocation(shader->id, "vertexTexCoord2");
+    shader->vertexLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_POSITION_NAME);
+    shader->texcoordLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TEXCOORD_NAME);
+    shader->normalLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_NORMAL_NAME);
+    shader->colorLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_COLOR_NAME);
+    shader->tangentLoc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TANGENT_NAME);
+    shader->texcoord2Loc = glGetAttribLocation(shader->id, DEFAULT_ATTRIB_TEXCOORD2_NAME);
 
     // Get handles to GLSL uniform locations (vertex shader)
     shader->mvpLoc  = glGetUniformLocation(shader->id, "mvpMatrix");
@@ -2447,8 +2447,8 @@ static void UnloadDefaultShader(void)
 {
     glUseProgram(0);
 
-    //glDetachShader(defaultShaderProgram, vertexShader);
-    //glDetachShader(defaultShaderProgram, fragmentShader);
+    //glDetachShader(defaultShader, vertexShader);
+    //glDetachShader(defaultShader, fragmentShader);
     //glDeleteShader(vertexShader);     // Already deleted on shader compilation
     //glDeleteShader(fragmentShader);   // Already deleted on sahder compilation
     glDeleteProgram(defaultShader.id);

From b10425492ac692d7c53001290e3d0b678df634b0 Mon Sep 17 00:00:00 2001
From: Joshua Reisenauer <kd7tck@msn.com>
Date: Thu, 19 May 2016 15:22:12 -0700
Subject: [PATCH 15/33] name correction

---
 src/audio.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/audio.c b/src/audio.c
index 584d3ad14..6d8f876c3 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -59,9 +59,9 @@
 //----------------------------------------------------------------------------------
 // Defines and Macros
 //----------------------------------------------------------------------------------
-#define MAX_STREAM_BUFFERS          2
-#define MAX_AUDIO_CONTEXTS          4             // Number of open AL sources
-#define MAX_MUSIC_STREAMS           2
+#define MAX_STREAM_BUFFERS          2             // Number of buffers for each alSource
+#define MAX_MIX_CHANNELS            4             // Number of open AL sources
+#define MAX_MUSIC_STREAMS           2             // Number of simultanious music sources
 
 #if defined(PLATFORM_RPI) || defined(PLATFORM_ANDROID)
     // NOTE: On RPI and Android should be lower to avoid frame-stalls
@@ -96,12 +96,12 @@ typedef struct MixChannel_t {
 typedef struct Music {
     stb_vorbis *stream;
     jar_xm_context_t *chipctx; // Stores jar_xm mixc
-    MixChannel_t *mixc; // mix channel
+    MixChannel_t *mixc;        // mix channel
     
     int totalSamplesLeft;
     float totalLengthSeconds;
     bool loop;
-    bool chipTune; // True if chiptune is loaded
+    bool chipTune;             // True if chiptune is loaded
 } Music;
 
 #if defined(AUDIO_STANDALONE)
@@ -111,7 +111,7 @@ typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 //----------------------------------------------------------------------------------
-static MixChannel_t* mixChannelsActive_g[MAX_AUDIO_CONTEXTS];      // What mix channels are currently active
+static MixChannel_t* mixChannelsActive_g[MAX_MIX_CHANNELS];        // What mix channels are currently active
 static bool musicEnabled_g = false;
 static Music currentMusic[MAX_MUSIC_STREAMS];                      // Current music loaded, up to two can play at the same time
 
@@ -123,7 +123,7 @@ static Wave LoadOGG(char *fileName);               // Load OGG file
 static void UnloadWave(Wave wave);                 // Unload wave data
 
 static bool BufferMusicStream(int index, int numBuffers); // Fill music buffers with data
-static void EmptyMusicStream(int index); // Empty music buffers
+static void EmptyMusicStream(int index);                  // Empty music buffers
 
 
 static MixChannel_t* InitMixChannel(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint); // For streaming into mix channels.
@@ -212,7 +212,7 @@ bool IsAudioDeviceReady(void)
 // exmple usage is InitMixChannel(48000, 0, 2, true); // mixchannel 1, 48khz, stereo, floating point
 static MixChannel_t* InitMixChannel(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint)
 {
-    if(mixChannel >= MAX_AUDIO_CONTEXTS) return NULL;
+    if(mixChannel >= MAX_MIX_CHANNELS) return NULL;
     if(!IsAudioDeviceReady()) InitAudioDevice();
     
     if(!mixChannelsActive_g[mixChannel]){
@@ -380,10 +380,10 @@ static void ResampleByteToFloat(char *chars, float *floats, unsigned short len)
 RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint)
 {
     int mixIndex;
-    for(mixIndex = 0; mixIndex < MAX_AUDIO_CONTEXTS; mixIndex++) // find empty mix channel slot
+    for(mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot
     {
         if(mixChannelsActive_g[mixIndex] == NULL) break;
-        else if(mixIndex = MAX_AUDIO_CONTEXTS - 1) return -1; // error
+        else if(mixIndex = MAX_MIX_CHANNELS - 1) return -1; // error
     }
     
     if(InitMixChannel(sampleRate, mixIndex, channels, floatingPoint))
@@ -755,10 +755,10 @@ int PlayMusicStream(int musicIndex, char *fileName)
     
     if(currentMusic[musicIndex].stream || currentMusic[musicIndex].chipctx) return 1; // error
     
-    for(mixIndex = 0; mixIndex < MAX_AUDIO_CONTEXTS; mixIndex++) // find empty mix channel slot
+    for(mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot
     {
         if(mixChannelsActive_g[mixIndex] == NULL) break;
-        else if(mixIndex = MAX_AUDIO_CONTEXTS - 1) return 2; // error
+        else if(mixIndex = MAX_MIX_CHANNELS - 1) return 2; // error
     }
     
     if (strcmp(GetExtension(fileName),"ogg") == 0)

From 41c5f3a0178027e9b74e563ab102f603a53e35bf Mon Sep 17 00:00:00 2001
From: Joshua Reisenauer <kd7tck@msn.com>
Date: Thu, 19 May 2016 20:44:09 -0700
Subject: [PATCH 16/33] Buffer for raw audio

---
 src/audio.c  | 22 ++++++++++++++++++----
 src/audio.h  |  4 ++++
 src/raylib.h |  6 +++++-
 3 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/src/audio.c b/src/audio.c
index 6d8f876c3..43e8be14e 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -128,8 +128,8 @@ static void EmptyMusicStream(int index);                  // Empty music buffers
 
 static MixChannel_t* InitMixChannel(unsigned short sampleRate, unsigned char mixChannel, unsigned char channels, bool floatingPoint); // For streaming into mix channels.
 static void CloseMixChannel(MixChannel_t* mixc); // Frees mix channel
-static unsigned short BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements); // Pushes more audio data into mixc mix channel, if NULL is passed it pauses
-static unsigned short FillAlBufferWithSilence(MixChannel_t *mixc, ALuint buffer); // Fill buffer with zeros, returns number processed
+static int BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements); // Pushes more audio data into mixc mix channel, if NULL is passed it pauses
+static int FillAlBufferWithSilence(MixChannel_t *mixc, ALuint buffer); // Fill buffer with zeros, returns number processed
 static void ResampleShortToFloat(short *shorts, float *floats, unsigned short len); // Pass two arrays of the same legnth in
 static void ResampleByteToFloat(char *chars, float *floats, unsigned short len); // Pass two arrays of same length in
 static int IsMusicStreamReadyForBuffering(int index); // Checks if music buffer is ready to be refilled
@@ -292,7 +292,7 @@ static void CloseMixChannel(MixChannel_t* mixc)
 // Pushes more audio data into mixc mix channel, only one buffer per call
 // Call "BufferMixChannel(mixc, NULL, 0)" if you want to pause the audio.
 // @Returns number of samples that where processed.
-static unsigned short BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements)
+static int BufferMixChannel(MixChannel_t* mixc, void *data, int numberElements)
 {
     if(!mixc || mixChannelsActive_g[mixc->mixChannel] != mixc) return 0; // when there is two channels there must be an even number of samples
     
@@ -331,7 +331,7 @@ static unsigned short BufferMixChannel(MixChannel_t* mixc, void *data, int numbe
 }
 
 // fill buffer with zeros, returns number processed
-static unsigned short FillAlBufferWithSilence(MixChannel_t *mixc, ALuint buffer)
+static int FillAlBufferWithSilence(MixChannel_t *mixc, ALuint buffer)
 {
     if(mixc->floatingPoint){
         float pcm[MUSIC_BUFFER_SIZE_FLOAT] = {0.f};
@@ -377,6 +377,7 @@ static void ResampleByteToFloat(char *chars, float *floats, unsigned short len)
 }
 
 // used to output raw audio streams, returns negative numbers on error
+// if floating point is false the data size is 16bit short, otherwise it is float 32bit
 RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint)
 {
     int mixIndex;
@@ -398,6 +399,19 @@ void CloseRawAudioContext(RawAudioContext ctx)
         CloseMixChannel(mixChannelsActive_g[ctx]);
 }
 
+int BufferRawAudioContext(RawAudioContext ctx, void *data, int numberElements)
+{
+    int numBuffered = 0;
+    if(ctx >= 0)
+    {
+        MixChannel_t* mixc = mixChannelsActive_g[ctx];
+        numBuffered = BufferMixChannel(mixc, data, numberElements);
+    }
+    return numBuffered;
+}
+
+
+
 
 
 //----------------------------------------------------------------------------------
diff --git a/src/audio.h b/src/audio.h
index d3276bf6e..1140a60a8 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -102,8 +102,12 @@ float GetMusicTimePlayed(int index);                            // Get current m
 int getMusicStreamCount(void);
 void SetMusicPitch(int index, float pitch);
 
+// used to output raw audio streams, returns negative numbers on error
+// if floating point is false the data size is 16bit short, otherwise it is float 32bit
 RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint);
+
 void CloseRawAudioContext(RawAudioContext ctx);
+int BufferRawAudioContext(RawAudioContext ctx, void *data, int numberElements); // returns number of elements buffered
 
 #ifdef __cplusplus
 }
diff --git a/src/raylib.h b/src/raylib.h
index 6efde7102..986dc7bfe 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -896,8 +896,12 @@ float GetMusicTimePlayed(int index);                            // Get current m
 int getMusicStreamCount(void);
 void SetMusicPitch(int index, float pitch);
 
-RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint); // used to output raw audio streams, returns negative numbers on error
+// used to output raw audio streams, returns negative numbers on error
+// if floating point is false the data size is 16bit short, otherwise it is float 32bit
+RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingPoint);
+
 void CloseRawAudioContext(RawAudioContext ctx);
+int BufferRawAudioContext(RawAudioContext ctx, void *data, int numberElements); // returns number of elements buffered
 
 #ifdef __cplusplus
 }

From 179f2f9e4fd9ad43e120f186484a78984a2ac063 Mon Sep 17 00:00:00 2001
From: Joshua Reisenauer <kd7tck@msn.com>
Date: Thu, 19 May 2016 20:56:38 -0700
Subject: [PATCH 17/33] windows automated compile

Only works when raylib is installed on windows system.
---
 src/windows_compile.bat | 2 ++
 1 file changed, 2 insertions(+)
 create mode 100644 src/windows_compile.bat

diff --git a/src/windows_compile.bat b/src/windows_compile.bat
new file mode 100644
index 000000000..f1d0fb29d
--- /dev/null
+++ b/src/windows_compile.bat
@@ -0,0 +1,2 @@
+set PATH=C:\raylib\MinGW\bin;%PATH%
+mingw32-make
\ No newline at end of file

From 7d1d9ff143cd7c6c55d3fd891b43e143431ea15f Mon Sep 17 00:00:00 2001
From: raysan5 <raysan5@gmail.com>
Date: Fri, 20 May 2016 09:36:02 +0200
Subject: [PATCH 18/33] Support DYNAMIC_DRAW mesh loading

---
 src/models.c | 10 +++++-----
 src/raylib.h |  2 +-
 src/rlgl.c   | 17 ++++++++++-------
 src/rlgl.h   |  2 +-
 4 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/src/models.c b/src/models.c
index bb2d56c25..6d72d1e3b 100644
--- a/src/models.c
+++ b/src/models.c
@@ -553,7 +553,7 @@ Model LoadModel(const char *fileName)
     if (model.mesh.vertexCount == 0) TraceLog(WARNING, "Model could not be loaded");
     else
     {
-        rlglLoadMesh(&model.mesh);  // Upload vertex data to GPU
+        rlglLoadMesh(&model.mesh, false);  // Upload vertex data to GPU (static model)
         
         model.transform = MatrixIdentity();
         model.material = LoadDefaultMaterial();
@@ -563,13 +563,13 @@ Model LoadModel(const char *fileName)
 }
 
 // Load a 3d model (from vertex data)
-Model LoadModelEx(Mesh data)
+Model LoadModelEx(Mesh data, bool dynamic)
 {
     Model model = { 0 };
 
     model.mesh = data;
     
-    rlglLoadMesh(&model.mesh);      // Upload vertex data to GPU
+    rlglLoadMesh(&model.mesh, dynamic);  // Upload vertex data to GPU
     
     model.transform = MatrixIdentity();
     model.material = LoadDefaultMaterial();
@@ -668,7 +668,7 @@ Model LoadHeightmap(Image heightmap, Vector3 size)
     
     model.mesh = GenMeshHeightmap(heightmap, size);
     
-    rlglLoadMesh(&model.mesh);
+    rlglLoadMesh(&model.mesh, false);  // Upload vertex data to GPU (static model)
     
     model.transform = MatrixIdentity();
     model.material = LoadDefaultMaterial();
@@ -683,7 +683,7 @@ Model LoadCubicmap(Image cubicmap)
     
     model.mesh = GenMeshCubicmap(cubicmap, (Vector3){ 1.0, 1.0, 1.5f });
     
-    rlglLoadMesh(&model.mesh);
+    rlglLoadMesh(&model.mesh, false);  // Upload vertex data to GPU (static model)
     
     model.transform = MatrixIdentity();
     model.material = LoadDefaultMaterial();
diff --git a/src/raylib.h b/src/raylib.h
index 986dc7bfe..8a46ec358 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -803,7 +803,7 @@ void DrawGizmo(Vector3 position);
 // Model 3d Loading and Drawing Functions (Module: models)
 //------------------------------------------------------------------------------------
 Model LoadModel(const char *fileName);                          // Load a 3d model (.OBJ)
-Model LoadModelEx(Mesh data);                                   // Load a 3d model (from mesh data)
+Model LoadModelEx(Mesh data, bool dynamic);                     // Load a 3d model (from mesh data)
 Model LoadModelFromRES(const char *rresName, int resId);        // Load a 3d model from rRES file (raylib Resource)
 Model LoadHeightmap(Image heightmap, Vector3 size);             // Load a heightmap image as a 3d model
 Model LoadCubicmap(Image cubicmap);                             // Load a map image as a 3d model (cubes based)
diff --git a/src/rlgl.c b/src/rlgl.c
index 888a93131..cc2b89429 100644
--- a/src/rlgl.c
+++ b/src/rlgl.c
@@ -1500,7 +1500,7 @@ void rlglGenerateMipmaps(Texture2D texture)
 }
 
 // Upload vertex data into a VAO (if supported) and VBO
-void rlglLoadMesh(Mesh *mesh)
+void rlglLoadMesh(Mesh *mesh, bool dynamic)
 {
     mesh->vaoId = 0;        // Vertex Array Object
     mesh->vboId[0] = 0;     // Vertex positions VBO
@@ -1510,6 +1510,9 @@ void rlglLoadMesh(Mesh *mesh)
     mesh->vboId[4] = 0;     // Vertex tangents VBO
     mesh->vboId[5] = 0;     // Vertex texcoords2 VBO
     mesh->vboId[6] = 0;     // Vertex indices VBO
+    
+    int drawHint = GL_STATIC_DRAW;
+    if (dynamic) drawHint = GL_DYNAMIC_DRAW;
 
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
     GLuint vaoId = 0;       // Vertex Array Objects (VAO)
@@ -1527,14 +1530,14 @@ void rlglLoadMesh(Mesh *mesh)
     // Enable vertex attributes: position (shader-location = 0)
     glGenBuffers(1, &vboId[0]);
     glBindBuffer(GL_ARRAY_BUFFER, vboId[0]);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->vertices, GL_STATIC_DRAW);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->vertices, drawHint);
     glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0);
     glEnableVertexAttribArray(0);
 
     // Enable vertex attributes: texcoords (shader-location = 1)
     glGenBuffers(1, &vboId[1]);
     glBindBuffer(GL_ARRAY_BUFFER, vboId[1]);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords, GL_STATIC_DRAW);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords, drawHint);
     glVertexAttribPointer(1, 2, GL_FLOAT, 0, 0, 0);
     glEnableVertexAttribArray(1);
 
@@ -1543,7 +1546,7 @@ void rlglLoadMesh(Mesh *mesh)
     {
         glGenBuffers(1, &vboId[2]);
         glBindBuffer(GL_ARRAY_BUFFER, vboId[2]);
-        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->normals, GL_STATIC_DRAW);
+        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->normals, drawHint);
         glVertexAttribPointer(2, 3, GL_FLOAT, 0, 0, 0);
         glEnableVertexAttribArray(2);
     }
@@ -1559,7 +1562,7 @@ void rlglLoadMesh(Mesh *mesh)
     {
         glGenBuffers(1, &vboId[3]);
         glBindBuffer(GL_ARRAY_BUFFER, vboId[3]);
-        glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*mesh->vertexCount, mesh->colors, GL_STATIC_DRAW);
+        glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*mesh->vertexCount, mesh->colors, drawHint);
         glVertexAttribPointer(3, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
         glEnableVertexAttribArray(3);
     }
@@ -1575,7 +1578,7 @@ void rlglLoadMesh(Mesh *mesh)
     {
         glGenBuffers(1, &vboId[4]);
         glBindBuffer(GL_ARRAY_BUFFER, vboId[4]);
-        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->tangents, GL_STATIC_DRAW);
+        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->vertexCount, mesh->tangents, drawHint);
         glVertexAttribPointer(4, 3, GL_FLOAT, 0, 0, 0);
         glEnableVertexAttribArray(4);
     }
@@ -1591,7 +1594,7 @@ void rlglLoadMesh(Mesh *mesh)
     {
         glGenBuffers(1, &vboId[5]);
         glBindBuffer(GL_ARRAY_BUFFER, vboId[5]);
-        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords2, GL_STATIC_DRAW);
+        glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->vertexCount, mesh->texcoords2, drawHint);
         glVertexAttribPointer(5, 2, GL_FLOAT, 0, 0, 0);
         glEnableVertexAttribArray(5);
     }
diff --git a/src/rlgl.h b/src/rlgl.h
index a33e3a0a1..a557ffa27 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -280,7 +280,7 @@ RenderTexture2D rlglLoadRenderTexture(int width, int height);   // Load a textur
 void rlglUpdateTexture(unsigned int id, int width, int height, int format, void *data);         // Update GPU texture with new data
 void rlglGenerateMipmaps(Texture2D texture);                             // Generate mipmap data for selected texture
 
-void rlglLoadMesh(Mesh *mesh);                                      // Upload vertex data into GPU and provided VAO/VBO ids
+void rlglLoadMesh(Mesh *mesh, bool dynamic);                        // Upload vertex data into GPU and provided VAO/VBO ids
 void rlglUpdateMesh(Mesh mesh, int buffer, int numVertex);          // Update vertex data on GPU (upload new data to one buffer)
 void rlglDrawMesh(Mesh mesh, Material material, Matrix transform);  // Draw a 3d mesh with material and transform
 void rlglUnloadMesh(Mesh *mesh);                                    // Unload mesh data from CPU and GPU

From 03cc031d00ab97ab46b61b66a6281a175c33541f Mon Sep 17 00:00:00 2001
From: raysan5 <raysan5@gmail.com>
Date: Fri, 20 May 2016 09:40:48 +0200
Subject: [PATCH 19/33] Remove TODO comments (already done)

---
 src/raylib.h | 1 -
 src/shapes.c | 1 -
 2 files changed, 2 deletions(-)

diff --git a/src/raylib.h b/src/raylib.h
index 8a46ec358..32cd54a6c 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -423,7 +423,6 @@ typedef struct Material {
 } Material;
 
 // 3d Model type
-// TODO: Replace shader/testure by material
 typedef struct Model {
     Mesh mesh;                  // Vertex data buffers (RAM and VRAM)
     Matrix transform;           // Local transform matrix
diff --git a/src/shapes.c b/src/shapes.c
index 14d113150..5b66e5ef1 100644
--- a/src/shapes.c
+++ b/src/shapes.c
@@ -446,7 +446,6 @@ bool CheckCollisionCircleRec(Vector2 center, float radius, Rectangle rec)
 }
 
 // Get collision rectangle for two rectangles collision
-// TODO: Depending on rec1 and rec2 order, it fails -> Review!
 Rectangle GetCollisionRec(Rectangle rec1, Rectangle rec2)
 {
     Rectangle retRec = { 0, 0, 0, 0 };

From c9e30f77540e9693ddecffc353964eb71e854842 Mon Sep 17 00:00:00 2001
From: raysan5 <raysan5@gmail.com>
Date: Fri, 20 May 2016 10:53:31 +0200
Subject: [PATCH 20/33] Review struct typedef to avoid pointers for users

---
 examples/physics_basic_rigidbody.c | 17 +++++++++--------
 examples/physics_forces.c          | 14 +++++++-------
 src/physac.c                       | 12 ++++++------
 src/raylib.h                       | 12 ++++++------
 4 files changed, 28 insertions(+), 27 deletions(-)

diff --git a/examples/physics_basic_rigidbody.c b/examples/physics_basic_rigidbody.c
index 917813ad8..cd09f0701 100644
--- a/examples/physics_basic_rigidbody.c
+++ b/examples/physics_basic_rigidbody.c
@@ -30,26 +30,26 @@ int main()
     bool isDebug = false;
     
     // Create rectangle physic object
-    PhysicObject *rectangle = CreatePhysicObject((Vector2){ screenWidth*0.25f, screenHeight/2 }, 0.0f, (Vector2){ 75, 50 });
+    PhysicObject rectangle = CreatePhysicObject((Vector2){ screenWidth*0.25f, screenHeight/2 }, 0.0f, (Vector2){ 75, 50 });
     rectangle->rigidbody.enabled = true;       // Enable physic object rigidbody behaviour
     rectangle->rigidbody.applyGravity = true;
     rectangle->rigidbody.friction = 0.1f;
     rectangle->rigidbody.bounciness = 6.0f;
     
     // Create square physic object
-    PhysicObject *square = CreatePhysicObject((Vector2){ screenWidth*0.75f, screenHeight/2 }, 0.0f, (Vector2){ 50, 50 });
+    PhysicObject square = CreatePhysicObject((Vector2){ screenWidth*0.75f, screenHeight/2 }, 0.0f, (Vector2){ 50, 50 });
     square->rigidbody.enabled = true;      // Enable physic object rigidbody behaviour
     square->rigidbody.applyGravity = true;
     square->rigidbody.friction = 0.1f;
     
     // Create walls physic objects
-    PhysicObject *floor = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.95f }, 0.0f, (Vector2){ screenWidth*0.9f, 100 });
-    PhysicObject *leftWall = CreatePhysicObject((Vector2){ 0.0f, screenHeight/2 }, 0.0f, (Vector2){ screenWidth*0.1f, screenHeight });
-    PhysicObject *rightWall = CreatePhysicObject((Vector2){ screenWidth, screenHeight/2 }, 0.0f, (Vector2){ screenWidth*0.1f, screenHeight });
-    PhysicObject *roof = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.05f }, 0.0f, (Vector2){ screenWidth*0.9f, 100 });
+    PhysicObject floor = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.95f }, 0.0f, (Vector2){ screenWidth*0.9f, 100 });
+    PhysicObject leftWall = CreatePhysicObject((Vector2){ 0.0f, screenHeight/2 }, 0.0f, (Vector2){ screenWidth*0.1f, screenHeight });
+    PhysicObject rightWall = CreatePhysicObject((Vector2){ screenWidth, screenHeight/2 }, 0.0f, (Vector2){ screenWidth*0.1f, screenHeight });
+    PhysicObject roof = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.05f }, 0.0f, (Vector2){ screenWidth*0.9f, 100 });
     
     // Create pplatform physic object
-    PhysicObject *platform = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.7f }, 0.0f, (Vector2){ screenWidth*0.25f, 20 });
+    PhysicObject platform = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight*0.7f }, 0.0f, (Vector2){ screenWidth*0.25f, 20 });
     
     //--------------------------------------------------------------------------------------
 
@@ -114,7 +114,8 @@ int main()
 
     // De-Initialization
     //--------------------------------------------------------------------------------------
-    ClosePhysics();       // Unitialize physics module
+    ClosePhysics();       // Unitialize physics (including all loaded objects)
+    
     CloseWindow();        // Close window and OpenGL context
     //--------------------------------------------------------------------------------------
 
diff --git a/examples/physics_forces.c b/examples/physics_forces.c
index 74b40d57e..f4eefa051 100644
--- a/examples/physics_forces.c
+++ b/examples/physics_forces.c
@@ -17,7 +17,7 @@
 #define LINE_LENGTH         75
 #define TRIANGLE_LENGTH     12
 
-void DrawRigidbodyCircle(PhysicObject *obj, Color color);
+void DrawRigidbodyCircle(PhysicObject obj, Color color);
 
 int main()
 {
@@ -36,7 +36,7 @@ int main()
     bool isDebug = false;
     
     // Create rectangle physic objects
-    PhysicObject *rectangles[3];
+    PhysicObject rectangles[3];
     for (int i = 0; i < 3; i++)
     {
         rectangles[i] = CreatePhysicObject((Vector2){ screenWidth/4*(i+1), (((i % 2) == 0) ? (screenHeight/3) : (screenHeight/1.5f)) }, 0.0f, (Vector2){ 50, 50 });
@@ -46,7 +46,7 @@ int main()
     
     // Create circles physic objects
     // NOTE: when creating circle physic objects, transform.scale must be { 0, 0 } and object radius must be defined in collider.radius and use this value to draw the circle.
-    PhysicObject *circles[3];
+    PhysicObject circles[3];
     for (int i = 0; i < 3; i++)
     {
         circles[i] = CreatePhysicObject((Vector2){ screenWidth/4*(i+1), (((i % 2) == 0) ? (screenHeight/1.5f) : (screenHeight/4)) }, 0.0f, (Vector2){ 0, 0 });
@@ -57,10 +57,10 @@ int main()
     }
     
     // Create walls physic objects
-    PhysicObject *leftWall = CreatePhysicObject((Vector2){ -25, screenHeight/2 }, 0.0f, (Vector2){ 50, screenHeight });
-    PhysicObject *rightWall = CreatePhysicObject((Vector2){ screenWidth + 25, screenHeight/2 }, 0.0f, (Vector2){ 50, screenHeight });
-    PhysicObject *topWall = CreatePhysicObject((Vector2){ screenWidth/2, -25 }, 0.0f, (Vector2){ screenWidth, 50 });
-    PhysicObject *bottomWall = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight + 25 }, 0.0f, (Vector2){ screenWidth, 50 });
+    PhysicObject leftWall = CreatePhysicObject((Vector2){ -25, screenHeight/2 }, 0.0f, (Vector2){ 50, screenHeight });
+    PhysicObject rightWall = CreatePhysicObject((Vector2){ screenWidth + 25, screenHeight/2 }, 0.0f, (Vector2){ 50, screenHeight });
+    PhysicObject topWall = CreatePhysicObject((Vector2){ screenWidth/2, -25 }, 0.0f, (Vector2){ screenWidth, 50 });
+    PhysicObject bottomWall = CreatePhysicObject((Vector2){ screenWidth/2, screenHeight + 25 }, 0.0f, (Vector2){ screenWidth, 50 });
     
     //--------------------------------------------------------------------------------------
 
diff --git a/src/physac.c b/src/physac.c
index ed7074745..181488ac7 100644
--- a/src/physac.c
+++ b/src/physac.c
@@ -49,7 +49,7 @@
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 //----------------------------------------------------------------------------------
-static PhysicObject *physicObjects[MAX_PHYSIC_OBJECTS];             // Physic objects pool
+static PhysicObject physicObjects[MAX_PHYSIC_OBJECTS];              // Physic objects pool
 static int physicObjectsCount;                                      // Counts current enabled physic objects
 static Vector2 gravityForce;                                        // Gravity force
 
@@ -463,10 +463,10 @@ void ClosePhysics()
 }
 
 // Create a new physic object dinamically, initialize it and add to pool
-PhysicObject *CreatePhysicObject(Vector2 position, float rotation, Vector2 scale)
+PhysicObject CreatePhysicObject(Vector2 position, float rotation, Vector2 scale)
 {
     // Allocate dynamic memory
-    PhysicObject *obj = (PhysicObject *)malloc(sizeof(PhysicObject));
+    PhysicObject obj = (PhysicObject)malloc(sizeof(PhysicObjectData));
     
     // Initialize physic object values with generic values
     obj->id = physicObjectsCount;
@@ -498,7 +498,7 @@ PhysicObject *CreatePhysicObject(Vector2 position, float rotation, Vector2 scale
 }
 
 // Destroy a specific physic object and take it out of the list
-void DestroyPhysicObject(PhysicObject *pObj)
+void DestroyPhysicObject(PhysicObject pObj)
 {
     // Free dynamic memory allocation
     free(physicObjects[pObj->id]);
@@ -520,7 +520,7 @@ void DestroyPhysicObject(PhysicObject *pObj)
 }
 
 // Apply directional force to a physic object
-void ApplyForce(PhysicObject *pObj, Vector2 force)
+void ApplyForce(PhysicObject pObj, Vector2 force)
 {
     if (pObj->rigidbody.enabled)
     {
@@ -571,7 +571,7 @@ Rectangle TransformToRectangle(Transform transform)
 }
 
 // Draw physic object information at screen position
-void DrawPhysicObjectInfo(PhysicObject *pObj, Vector2 position, int fontSize)
+void DrawPhysicObjectInfo(PhysicObject pObj, Vector2 position, int fontSize)
 {
     // Draw physic object ID
     DrawText(FormatText("PhysicObject ID: %i - Enabled: %i", pObj->id, pObj->enabled), position.x, position.y, fontSize, BLACK);
diff --git a/src/raylib.h b/src/raylib.h
index 32cd54a6c..fc1914bb6 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -535,13 +535,13 @@ typedef struct Collider {
     int radius;             // Used for COLLIDER_CIRCLE
 } Collider;
 
-typedef struct PhysicObject {
+typedef struct PhysicObjectData {
     unsigned int id;
     Transform transform;
     Rigidbody rigidbody;
     Collider collider;
     bool enabled;
-} PhysicObject;
+} PhysicObjectData, *PhysicObject;
 
 #ifdef __cplusplus
 extern "C" {            // Prevents name mangling of functions
@@ -856,14 +856,14 @@ void InitPhysics(Vector2 gravity);
 void UpdatePhysics();                                                                   // Update physic objects, calculating physic behaviours and collisions detection
 void ClosePhysics();                                                                    // Unitialize all physic objects and empty the objects pool
 
-PhysicObject *CreatePhysicObject(Vector2 position, float rotation, Vector2 scale);      // Create a new physic object dinamically, initialize it and add to pool
-void DestroyPhysicObject(PhysicObject *pObj);                                           // Destroy a specific physic object and take it out of the list
+PhysicObject CreatePhysicObject(Vector2 position, float rotation, Vector2 scale);       // Create a new physic object dinamically, initialize it and add to pool
+void DestroyPhysicObject(PhysicObject pObj);                                            // Destroy a specific physic object and take it out of the list
 
-void ApplyForce(PhysicObject *pObj, Vector2 force);                                     // Apply directional force to a physic object
+void ApplyForce(PhysicObject pObj, Vector2 force);                                      // Apply directional force to a physic object
 void ApplyForceAtPosition(Vector2 position, float force, float radius);                 // Apply radial force to all physic objects in range
 
 Rectangle TransformToRectangle(Transform transform);                                    // Convert Transform data type to Rectangle (position and scale)
-void DrawPhysicObjectInfo(PhysicObject *pObj, Vector2 position, int fontSize);          // Draw physic object information at screen position
+void DrawPhysicObjectInfo(PhysicObject pObj, Vector2 position, int fontSize);           // Draw physic object information at screen position
 
 //------------------------------------------------------------------------------------
 // Audio Loading and Playing Functions (Module: audio)

From af890cf21021e4a306bf3f6e4397496b95c1c93a Mon Sep 17 00:00:00 2001
From: raysan5 <raysan5@gmail.com>
Date: Fri, 20 May 2016 10:53:58 +0200
Subject: [PATCH 21/33] Updated to avoid pointers

---
 src/physac.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/physac.h b/src/physac.h
index 37544686b..6cef480ad 100644
--- a/src/physac.h
+++ b/src/physac.h
@@ -66,13 +66,13 @@ typedef struct Collider {
     int radius;             // Used for COLLIDER_CIRCLE
 } Collider;
 
-typedef struct PhysicObject {
+typedef struct PhysicObjectData {
     unsigned int id;
     Transform transform;
     Rigidbody rigidbody;
     Collider collider;
     bool enabled;
-} PhysicObject;
+} PhysicObjectData, *PhysicObject;
 
 #ifdef __cplusplus
 extern "C" {            // Prevents name mangling of functions
@@ -85,14 +85,14 @@ void InitPhysics(Vector2 gravity);
 void UpdatePhysics();                                                                   // Update physic objects, calculating physic behaviours and collisions detection
 void ClosePhysics();                                                                    // Unitialize all physic objects and empty the objects pool
 
-PhysicObject *CreatePhysicObject(Vector2 position, float rotation, Vector2 scale);      // Create a new physic object dinamically, initialize it and add to pool
-void DestroyPhysicObject(PhysicObject *pObj);                                           // Destroy a specific physic object and take it out of the list
+PhysicObject CreatePhysicObject(Vector2 position, float rotation, Vector2 scale);       // Create a new physic object dinamically, initialize it and add to pool
+void DestroyPhysicObject(PhysicObject pObj);                                            // Destroy a specific physic object and take it out of the list
 
-void ApplyForce(PhysicObject *pObj, Vector2 force);                                     // Apply directional force to a physic object
+void ApplyForce(PhysicObject pObj, Vector2 force);                                      // Apply directional force to a physic object
 void ApplyForceAtPosition(Vector2 position, float force, float radius);                 // Apply radial force to all physic objects in range
 
 Rectangle TransformToRectangle(Transform transform);                                    // Convert Transform data type to Rectangle (position and scale)
-void DrawPhysicObjectInfo(PhysicObject *pObj, Vector2 position, int fontSize);          // Draw physic object information at screen position
+void DrawPhysicObjectInfo(PhysicObject pObj, Vector2 position, int fontSize);           // Draw physic object information at screen position
 
 #ifdef __cplusplus
 }

From dcf5f45f687f2a534286aecd5e6471a0440b0c21 Mon Sep 17 00:00:00 2001
From: raysan5 <raysan5@gmail.com>
Date: Fri, 20 May 2016 12:28:07 +0200
Subject: [PATCH 22/33] Add lighting system -IN PROGRESS-

Improved materials
---
 src/models.c |  12 ++++
 src/raylib.h |  30 ++++++++-
 src/rlgl.c   | 167 +++++++++++++++++++++++++++++++++++++++++++++++++--
 src/rlgl.h   |  25 ++++++++
 4 files changed, 228 insertions(+), 6 deletions(-)

diff --git a/src/models.c b/src/models.c
index 6d72d1e3b..44e30390c 100644
--- a/src/models.c
+++ b/src/models.c
@@ -732,6 +732,18 @@ Material LoadDefaultMaterial(void)
     return material;
 }
 
+// Load standard material (uses standard models shader)
+// NOTE: Standard shader supports multiple maps and lights
+Material LoadStandardMaterial(void)
+{
+    Material material = LoadDefaultMaterial();
+    
+    //material.shader = GetStandardShader();
+
+    return material;
+}
+
+// Unload material from memory
 void UnloadMaterial(Material material)
 {
     rlDeleteTextures(material.texDiffuse.id);
diff --git a/src/raylib.h b/src/raylib.h
index fc1914bb6..d98a0797f 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -422,13 +422,38 @@ typedef struct Material {
     float normalDepth;          // Normal map depth
 } Material;
 
-// 3d Model type
+// Model type
 typedef struct Model {
     Mesh mesh;                  // Vertex data buffers (RAM and VRAM)
     Matrix transform;           // Local transform matrix
     Material material;          // Shader and textures data
 } Model;
 
+// Light type
+// TODO: Review contained data to support different light types and features
+typedef struct LightData {
+    int id;
+    int type;           // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT
+    bool enabled;
+    
+    Vector3 position;
+    Vector3 direction;  // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction)
+    float attenuation;  // Lost of light intensity with distance (use radius?)
+    
+    Color diffuse;      // Use Vector3 diffuse (including intensities)?
+    float intensity;
+    
+    Color specular;
+    //float specFactor;   // Specular intensity ?
+
+    //Color ambient;    // Required?
+    
+    float coneAngle;         // SpotLight
+} LightData, *Light;
+
+// Light types
+typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType;
+
 // Ray type (useful for raycast)
 typedef struct Ray {
     Vector3 position;
@@ -849,6 +874,9 @@ void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat);       // S
 
 void SetBlendMode(int mode);                                        // Set blending mode (alpha, additive, multiplied)
 
+Light CreateLight(int type, Vector3 position, Color diffuse);       // Create a new light, initialize it and add to pool
+void DestroyLight(Light light);                                     // Destroy a light and take it out of the list
+
 //----------------------------------------------------------------------------------
 // Physics System Functions (Module: physac)
 //----------------------------------------------------------------------------------
diff --git a/src/rlgl.c b/src/rlgl.c
index cc2b89429..e971d747f 100644
--- a/src/rlgl.c
+++ b/src/rlgl.c
@@ -71,6 +71,8 @@
 #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)
                                         // NOTE: Every vertex are 3 floats (12 bytes)
+                                        
+#define MAX_LIGHTS                  8   // Max lights supported by standard shader
 
 #ifndef GL_SHADING_LANGUAGE_VERSION
     #define GL_SHADING_LANGUAGE_VERSION         0x8B8C
@@ -199,6 +201,10 @@ static bool texCompETC1Supported = false;    // ETC1 texture compression support
 static bool texCompETC2Supported = false;    // ETC2/EAC texture compression support
 static bool texCompPVRTSupported = false;    // PVR texture compression support
 static bool texCompASTCSupported = false;    // ASTC texture compression support
+
+// Lighting data
+static Light lights[MAX_LIGHTS];              // Lights pool
+static int lightsCount;                       // Counts current enabled physic objects
 #endif
 
 // Compressed textures support flags
@@ -227,6 +233,7 @@ static void LoadCompressedTexture(unsigned char *data, int width, int height, in
 static unsigned int LoadShaderProgram(char *vShaderStr, char *fShaderStr);  // Load custom shader strings and return program id
 
 static Shader LoadDefaultShader(void);      // Load default shader (just vertex positioning and texture coloring)
+static Shader LoadStandardShader(void);     // Load standard shader (support materials and lighting)
 static void LoadDefaultShaderLocations(Shader *shader); // Bind default shader locations (attributes and uniforms)
 static void UnloadDefaultShader(void);      // Unload default shader
 
@@ -235,6 +242,8 @@ static void UpdateDefaultBuffers(void);     // Update default internal buffers (
 static void DrawDefaultBuffers(void);       // Draw default internal buffers vertex data
 static void UnloadDefaultBuffers(void);     // Unload default internal buffers vertex data from CPU and GPU
 
+static void SetShaderLights(Shader shader); // Sets shader uniform values for lights array
+
 static char *ReadTextFile(const char *fileName);
 #endif
 
@@ -1749,11 +1758,19 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
     // Send combined model-view-projection matrix to shader
     glUniformMatrix4fv(material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP));
 
-    // Apply color tinting (material.colDiffuse)
-    // NOTE: Just update one uniform on fragment shader
-    float vColor[4] = { (float)material.colDiffuse.r/255, (float)material.colDiffuse.g/255, (float)material.colDiffuse.b/255, (float)material.colDiffuse.a/255 };
-    glUniform4fv(material.shader.tintColorLoc, 1, vColor);
-
+    // Setup shader uniforms for material related data
+    // TODO: Check if using standard shader to get location points
+    
+    // Upload to shader material.colDiffuse
+    float vColorDiffuse[4] = { (float)material.colDiffuse.r/255, (float)material.colDiffuse.g/255, (float)material.colDiffuse.b/255, (float)material.colDiffuse.a/255 };
+    glUniform4fv(material.shader.tintColorLoc, 1, vColorDiffuse);
+    
+    // TODO: Upload to shader material.colAmbient
+    // glUniform4f(???, (float)material.colAmbient.r/255, (float)material.colAmbient.g/255, (float)material.colAmbient.b/255, (float)material.colAmbient.a/255);
+    
+    // TODO: Upload to shader material.colSpecular
+    // glUniform4f(???, (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255);
+    
     // Set shader textures (diffuse, normal, specular)
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, material.texDiffuse.id);
@@ -1764,6 +1781,9 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
         glActiveTexture(GL_TEXTURE1);
         glBindTexture(GL_TEXTURE_2D, material.texNormal.id);
         glUniform1i(material.shader.mapNormalLoc, 1);     // Texture fits in active texture unit 1
+        
+        // TODO: Upload to shader normalDepth
+        //glUniform1f(???, material.normalDepth);
     }
     
     if ((material.texSpecular.id != 0) && (material.shader.mapSpecularLoc != -1))
@@ -1771,7 +1791,13 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
         glActiveTexture(GL_TEXTURE2);
         glBindTexture(GL_TEXTURE_2D, material.texSpecular.id);
         glUniform1i(material.shader.mapSpecularLoc, 2);   // Texture fits in active texture unit 2
+        
+        // TODO: Upload to shader glossiness
+        //glUniform1f(???, material.glossiness);
     }
+    
+    // Setup shader uniforms for lights
+    SetShaderLights(material.shader);
 
     if (vaoSupported)
     {
@@ -2198,6 +2224,55 @@ void SetBlendMode(int mode)
     }
 }
 
+// Create a new light, initialize it and add to pool
+// TODO: Review creation parameters (only generic ones)
+Light CreateLight(int type, Vector3 position, Color diffuse)
+{
+    // Allocate dynamic memory
+    Light light = (Light)malloc(sizeof(LightData));
+    
+    // Initialize light values with generic values
+    light->id = lightsCount;
+    light->type = type;
+    light->enabled = true;
+    
+    light->position = position;
+    light->direction = (Vector3){ 0.0f, 0.0f, 0.0f };
+    light->intensity = 1.0f;
+    light->diffuse = diffuse;
+    light->specular = WHITE;
+    
+    // Add new light to the array
+    lights[lightsCount] = light;
+    
+    // Increase enabled lights count
+    lightsCount++;
+    
+    return light;
+}
+
+// Destroy a light and take it out of the list
+void DestroyLight(Light light)
+{
+    // Free dynamic memory allocation
+    free(lights[light->id]);
+    
+    // Remove *obj from the pointers array
+    for (int i = light->id; i < lightsCount; i++)
+    {
+        // Resort all the following pointers of the array
+        if ((i + 1) < lightsCount)
+        {
+            lights[i] = lights[i + 1];
+            lights[i]->id = lights[i + 1]->id;
+        }
+        else free(lights[i]);
+    }
+    
+    // Decrease enabled physic objects count
+    lightsCount--;
+}
+
 //----------------------------------------------------------------------------------
 // Module specific Functions Definition
 //----------------------------------------------------------------------------------
@@ -2415,6 +2490,32 @@ static Shader LoadDefaultShader(void)
     return shader;
 }
 
+// Load standard shader
+// NOTE: This shader supports: 
+//      - Up to 3 different maps: diffuse, normal, specular
+//      - Material properties: colDiffuse, colAmbient, colSpecular, glossiness, normalDepth
+//      - Up to 8 lights: Point, Directional or Spot
+static Shader LoadStandardShader(void)
+{
+    Shader shader;
+    
+    char *vShaderStr;
+    char *fShaderStr;
+    
+    // TODO: Implement standard uber-shader, supporting all features (GLSL 100 / GLSL 330)
+    
+    // NOTE: Shader could be quite extensive so it could be implemented in external files (standard.vs/standard.fs)
+    
+    shader.id = LoadShaderProgram(vShaderStr, fShaderStr);
+
+    if (shader.id != 0) TraceLog(INFO, "[SHDR ID %i] Standard shader loaded successfully", shader.id);
+    else TraceLog(WARNING, "[SHDR ID %i] Standard shader could not be loaded", shader.id);
+
+    if (shader.id != 0) LoadDefaultShaderLocations(&shader);    // TODO: Review locations fetching
+
+    return shader;
+}
+
 // Get location handlers to for shader attributes and uniforms
 // NOTE: If any location is not found, loc point becomes -1
 static void LoadDefaultShaderLocations(Shader *shader)
@@ -2900,6 +3001,62 @@ static void UnloadDefaultBuffers(void)
     free(quads.indices);
 }
 
+// Sets shader uniform values for lights array
+// NOTE: It would be far easier with shader UBOs but are not supported on OpenGL ES 2.0f
+// TODO: Review memcpy() and parameters pass
+static void SetShaderLights(Shader shader)
+{
+    /*
+    // NOTE: Standard Shader must include the following data:
+        
+    // Shader Light struct
+    struct Light {
+        vec3 position;
+        vec3 direction;
+        
+        vec3 diffuse;
+        float intensity;
+    }
+
+    const int maxLights = 8;
+    uniform int lightsCount;            // Number of lights
+    uniform Light lights[maxLights];
+    */
+    
+    int locPoint;
+    char locName[32] = "lights[x].position\0";
+    
+    glUseProgram(shader.id);
+
+    locPoint = glGetUniformLocation(shader.id, "lightsCount");
+    glUniform1i(locPoint, lightsCount);
+
+    for (int i = 0; i < lightsCount; i++)
+    {
+        locName[7] = '0' + i;
+        
+        memcpy(&locName[10], "position\0", strlen("position\0"));
+        locPoint = glGetUniformLocation(shader.id, locName);
+        glUniform3f(locPoint, lights[i]->position.x, lights[i]->position.y, lights[i]->position.z);
+        
+        memcpy(&locName[10], "direction\0", strlen("direction\0"));
+        locPoint = glGetUniformLocation(shader.id, locName);       
+        glUniform3f(locPoint, lights[i]->direction.x, lights[i]->direction.y, lights[i]->direction.z);
+
+        memcpy(&locName[10], "diffuse\0", strlen("diffuse\0"));
+        locPoint = glGetUniformLocation(shader.id, locName);
+        glUniform4f(locPoint, (float)lights[i]->diffuse.r/255, (float)lights[i]->diffuse.g/255, (float)lights[i]->diffuse.b/255, (float)lights[i]->diffuse.a/255 );
+        
+        memcpy(&locName[10], "intensity\0", strlen("intensity\0"));
+        locPoint = glGetUniformLocation(shader.id, locName);
+        glUniform1f(locPoint, lights[i]->intensity);
+        
+        // TODO: Pass to the shader any other required data from LightData struct
+    }
+    
+    glUseProgram(0);
+}
+
 // Read text data from file
 // NOTE: text chars array should be freed manually
 static char *ReadTextFile(const char *fileName)
diff --git a/src/rlgl.h b/src/rlgl.h
index a557ffa27..39941b33c 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -209,6 +209,28 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion;
         float glossiness;
         float normalDepth;
     } Material;
+    
+    // Light type
+    // TODO: Review contained data to support different light types and features
+    typedef struct LightData {
+        int id;
+        int type;           // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT
+        bool enabled;
+        
+        Vector3 position;
+        Vector3 direction;  // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction)
+        float attenuation;  // Lost of light intensity with distance (use radius?)
+        
+        Color diffuse;      // Use Vector3 diffuse (including intensities)?
+        float intensity;
+        
+        Color specular;
+        //float specFactor;   // Specular intensity ?
+
+        //Color ambient;    // Required?
+        
+        float coneAngle;         // SpotLight
+    } LightData, *Light;
 	
     // Color blending modes (pre-defined)
     typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode;
@@ -311,6 +333,9 @@ void SetShaderValuei(Shader shader, int uniformLoc, int *value, int size);  // S
 void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat);       // Set shader uniform value (matrix 4x4)
 
 void SetBlendMode(int mode);                                        // Set blending mode (alpha, additive, multiplied)
+
+Light CreateLight(int type, Vector3 position, Color diffuse);       // Create a new light, initialize it and add to pool
+void DestroyLight(Light light);                                     // Destroy a light and take it out of the list
 #endif
 
 #ifdef __cplusplus

From 90c62c4cc0bc79ea51ae114467757a8d80c38fa6 Mon Sep 17 00:00:00 2001
From: victorfisac <victorfisac@gmail.com>
Date: Fri, 20 May 2016 14:07:50 +0200
Subject: [PATCH 23/33] Fix small warning

Material glossiness is a float type value...
---
 src/models.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/models.c b/src/models.c
index 44e30390c..0e59242bb 100644
--- a/src/models.c
+++ b/src/models.c
@@ -2068,7 +2068,7 @@ static Material LoadMTL(const char *fileName)
             {
                 if (buffer[1] == 's')       // Ns int   Shininess (specular exponent). Ranges from 0 to 1000.
                 {
-                    sscanf(buffer, "Ns %i", &material.glossiness);
+                    sscanf(buffer, "Ns %f", &material.glossiness);
                 }
                 else if (buffer[1] == 'i')  // Ni int   Refraction index.
                 {

From 3fa6fdacf2be438cfc81d3ae5ef2b58801aecce6 Mon Sep 17 00:00:00 2001
From: victorfisac <victorfisac@gmail.com>
Date: Fri, 20 May 2016 14:24:53 +0200
Subject: [PATCH 24/33] Improved MTL loading shininess value

---
 src/models.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/models.c b/src/models.c
index 0e59242bb..414f6716d 100644
--- a/src/models.c
+++ b/src/models.c
@@ -2068,7 +2068,11 @@ static Material LoadMTL(const char *fileName)
             {
                 if (buffer[1] == 's')       // Ns int   Shininess (specular exponent). Ranges from 0 to 1000.
                 {
-                    sscanf(buffer, "Ns %f", &material.glossiness);
+                    int shininess = 0;
+                    sscanf(buffer, "Ns %i", &shininess);
+                    
+                    // Normalize shininess value to material glossiness attribute
+                    material.glossiness = (float)shininess/1000;
                 }
                 else if (buffer[1] == 'i')  // Ni int   Refraction index.
                 {

From 6dac1efefef137ae487fa9f4c782b80538f784ba Mon Sep 17 00:00:00 2001
From: raysan5 <raysan5@gmail.com>
Date: Fri, 20 May 2016 15:01:36 +0200
Subject: [PATCH 25/33] Comented buggy code to avoid problems...

...on model drawing
---
 src/rlgl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/rlgl.c b/src/rlgl.c
index e971d747f..c5048affe 100644
--- a/src/rlgl.c
+++ b/src/rlgl.c
@@ -1797,7 +1797,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
     }
     
     // Setup shader uniforms for lights
-    SetShaderLights(material.shader);
+    //SetShaderLights(material.shader);
 
     if (vaoSupported)
     {

From 30c8058fca39e4d6566b2fc06ae2498c48c00717 Mon Sep 17 00:00:00 2001
From: victorfisac <victorfisac@gmail.com>
Date: Fri, 20 May 2016 17:18:07 +0200
Subject: [PATCH 26/33] Add standard lighting (1/3)

- Ambient and lambert lighting added.
- Ambient and diffuse colors linked to standard shader.
- Single light linked to standard shader.
- LoadStandardMaterial() and depending functions added.
---
 src/models.c |   6 +--
 src/raylib.h |   9 ++--
 src/rlgl.c   | 149 ++++++++++++++++++++++++++++++++++++++++++---------
 3 files changed, 131 insertions(+), 33 deletions(-)

diff --git a/src/models.c b/src/models.c
index 414f6716d..2629dffdb 100644
--- a/src/models.c
+++ b/src/models.c
@@ -732,13 +732,13 @@ Material LoadDefaultMaterial(void)
     return material;
 }
 
-// Load standard material (uses standard models shader)
+// Load standard material (uses material attributes and lighting shader)
 // NOTE: Standard shader supports multiple maps and lights
 Material LoadStandardMaterial(void)
 {
     Material material = LoadDefaultMaterial();
     
-    //material.shader = GetStandardShader();
+    material.shader = GetStandardShader();
 
     return material;
 }
@@ -1240,7 +1240,7 @@ void DrawModelEx(Model model, Vector3 position, Vector3 rotationAxis, float rota
     //Matrix matModel = MatrixMultiply(model.transform, matTransform);    // Transform to world-space coordinates
     
     model.transform = MatrixMultiply(MatrixMultiply(matScale, matRotation), matTranslation);
-    model.material.colDiffuse = tint;
+    // model.material.colDiffuse = tint;
     
     rlglDrawMesh(model.mesh, model.material, model.transform);
 }
diff --git a/src/raylib.h b/src/raylib.h
index d98a0797f..48534fd6d 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -398,7 +398,7 @@ typedef struct Shader {
 
     // Uniform locations
     int mvpLoc;           // ModelView-Projection matrix uniform location point (vertex shader)
-    int tintColorLoc;     // Color uniform location point (fragment shader)
+    int tintColorLoc;     // Diffuse color uniform location point (fragment shader)
     
     // Texture map locations
     int mapDiffuseLoc;    // Diffuse map texture uniform location point (fragment shader)
@@ -444,11 +444,8 @@ typedef struct LightData {
     float intensity;
     
     Color specular;
-    //float specFactor;   // Specular intensity ?
-
-    //Color ambient;    // Required?
     
-    float coneAngle;         // SpotLight
+    float coneAngle;    // SpotLight
 } LightData, *Light;
 
 // Light types
@@ -836,6 +833,7 @@ void SetModelTexture(Model *model, Texture2D texture);          // Link a textur
 
 Material LoadMaterial(const char *fileName);                    // Load material data (from file)
 Material LoadDefaultMaterial(void);                             // Load default material (uses default models shader)
+Material LoadStandardMaterial(void);                            // Load standard material (uses material attributes and lighting shader)
 void UnloadMaterial(Material material);                         // Unload material textures from VRAM
 
 void DrawModel(Model model, Vector3 position, float scale, Color tint);                            // Draw a model (with texture if set)
@@ -865,6 +863,7 @@ void UnloadShader(Shader shader);                                   // Unload a
 void SetDefaultShader(void);                                        // Set default shader to be used in batch draw
 void SetCustomShader(Shader shader);                                // Set custom shader to be used in batch draw
 Shader GetDefaultShader(void);                                      // Get default shader
+Shader GetStandardShader(void);                                     // Get default shader
 Texture2D GetDefaultTexture(void);                                  // Get default texture
 
 int GetShaderLocation(Shader shader, const char *uniformName);              // Get shader uniform location
diff --git a/src/rlgl.c b/src/rlgl.c
index c5048affe..e2195e4d1 100644
--- a/src/rlgl.c
+++ b/src/rlgl.c
@@ -191,6 +191,7 @@ static bool useTempBuffer = false;
 
 // Shader Programs
 static Shader defaultShader;
+static Shader standardShader;
 static Shader currentShader;            // By default, defaultShader
 
 // Flags for supported extensions
@@ -236,6 +237,7 @@ static Shader LoadDefaultShader(void);      // Load default shader (just vertex
 static Shader LoadStandardShader(void);     // Load standard shader (support materials and lighting)
 static void LoadDefaultShaderLocations(Shader *shader); // Bind default shader locations (attributes and uniforms)
 static void UnloadDefaultShader(void);      // Unload default shader
+static void UnloadStandardShader(void);      // Unload standard shader
 
 static void LoadDefaultBuffers(void);       // Load default internal buffers (lines, triangles, quads)
 static void UpdateDefaultBuffers(void);     // Update default internal buffers (VAOs/VBOs) with vertex data
@@ -1018,6 +1020,7 @@ void rlglInit(void)
 
     // Init default Shader (customized for GL 3.3 and ES2)
     defaultShader = LoadDefaultShader();
+    standardShader = LoadStandardShader();
     currentShader = defaultShader;
 
     LoadDefaultBuffers();        // Initialize default vertex arrays buffers (lines, triangles, quads)
@@ -1046,6 +1049,7 @@ void rlglClose(void)
 {
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
     UnloadDefaultShader();
+    UnloadStandardShader();
     UnloadDefaultBuffers();
     
     // Delete default white texture
@@ -1757,19 +1761,30 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
 
     // Send combined model-view-projection matrix to shader
     glUniformMatrix4fv(material.shader.mvpLoc, 1, false, MatrixToFloat(matMVP));
-
-    // Setup shader uniforms for material related data
-    // TODO: Check if using standard shader to get location points
     
     // Upload to shader material.colDiffuse
     float vColorDiffuse[4] = { (float)material.colDiffuse.r/255, (float)material.colDiffuse.g/255, (float)material.colDiffuse.b/255, (float)material.colDiffuse.a/255 };
     glUniform4fv(material.shader.tintColorLoc, 1, vColorDiffuse);
+
+    // Check if using standard shader to get location points
+    // NOTE: standard shader specific locations are got at render time to keep Shader struct as simple as possible (with just default shader locations)
+    if(material.shader.id == standardShader.id)
+    {
+        // Send model transformations matrix to shader
+        glUniformMatrix4fv(glGetUniformLocation(material.shader.id, "modelMatrix"), 1, false, MatrixToFloat(transform));
+        
+        // Setup shader uniforms for lights
+        SetShaderLights(material.shader);
+        
+        // Upload to shader material.colAmbient
+        glUniform4f(glGetUniformLocation(material.shader.id, "colAmbient"), (float)material.colAmbient.r/255, (float)material.colAmbient.g/255, (float)material.colAmbient.b/255, (float)material.colAmbient.a/255);
+        
+        // Upload to shader material.colSpecular
+        glUniform4f(glGetUniformLocation(material.shader.id, "colSpecular"), (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255);
     
-    // TODO: Upload to shader material.colAmbient
-    // glUniform4f(???, (float)material.colAmbient.r/255, (float)material.colAmbient.g/255, (float)material.colAmbient.b/255, (float)material.colAmbient.a/255);
-    
-    // TODO: Upload to shader material.colSpecular
-    // glUniform4f(???, (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255);
+        // TODO: Upload to shader glossiness
+        //glUniform1f(???, material.glossiness);
+    }    
     
     // Set shader textures (diffuse, normal, specular)
     glActiveTexture(GL_TEXTURE0);
@@ -1791,13 +1806,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
         glActiveTexture(GL_TEXTURE2);
         glBindTexture(GL_TEXTURE_2D, material.texSpecular.id);
         glUniform1i(material.shader.mapSpecularLoc, 2);   // Texture fits in active texture unit 2
-        
-        // TODO: Upload to shader glossiness
-        //glUniform1f(???, material.glossiness);
     }
-    
-    // Setup shader uniforms for lights
-    //SetShaderLights(material.shader);
 
     if (vaoSupported)
     {
@@ -2148,6 +2157,17 @@ Shader GetDefaultShader(void)
 #endif
 }
 
+// Get default shader
+Shader GetStandardShader(void)
+{
+#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+    return standardShader;
+#else
+    Shader shader = { 0 };
+    return shader;
+#endif
+}
+
 // Get shader uniform location
 int GetShaderLocation(Shader shader, const char *uniformName)
 {
@@ -2499,13 +2519,75 @@ static Shader LoadStandardShader(void)
 {
     Shader shader;
     
-    char *vShaderStr;
-    char *fShaderStr;
-    
-    // TODO: Implement standard uber-shader, supporting all features (GLSL 100 / GLSL 330)
-    
-    // NOTE: Shader could be quite extensive so it could be implemented in external files (standard.vs/standard.fs)
-    
+    // Vertex shader directly defined, no external file required
+#if defined(GRAPHICS_API_OPENGL_33)
+    char vShaderStr[] = "#version 330       \n"
+        "in vec3 vertexPosition;            \n"
+        "in vec3 vertexNormal;              \n"
+        "in vec2 vertexTexCoord;            \n"
+        "in vec4 vertexColor;               \n"
+        "out vec2 fragTexCoord;             \n"
+        "out vec4 fragColor;                \n"
+        "out vec3 fragNormal;               \n"
+#elif defined(GRAPHICS_API_OPENGL_ES2)
+    char vShaderStr[] = "#version 100       \n"
+        "attribute vec3 vertexPosition;     \n"
+        "attribute vec3 vertexNormal;       \n"
+        "attribute vec2 vertexTexCoord;     \n"
+        "attribute vec4 vertexColor;        \n"
+        "varying vec2 fragTexCoord;         \n"
+        "varying vec4 fragColor;            \n"
+        "varying vec3 fragNormal;           \n"
+#endif
+        "uniform mat4 mvpMatrix;            \n"
+        "uniform mat4 modelMatrix;          \n"
+        "void main()                        \n"
+        "{                                  \n"
+        "   fragTexCoord = vertexTexCoord; \n"
+        "   fragColor = vertexColor;       \n"
+        "   mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));  \n"
+        "   fragNormal = normalize(normalMatrix*vertexNormal);  \n"
+        "   gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);  \n"
+        "}                                  \n";
+
+    // TODO: add specular calculation, multi-lights structs and light type calculations (directional, point, spot)
+    // Fragment shader directly defined, no external file required
+#if defined(GRAPHICS_API_OPENGL_33)
+    char fShaderStr[] = "#version 330       \n"
+        "in vec2 fragTexCoord;              \n"
+        "in vec4 fragColor;                 \n"
+        "in vec3 fragNormal;                \n"
+        "out vec4 finalColor;               \n"
+#elif defined(GRAPHICS_API_OPENGL_ES2)
+    char fShaderStr[] = "#version 100       \n"
+        "precision mediump float;           \n"     // precision required for OpenGL ES2 (WebGL)
+        "varying vec2 fragTexCoord;         \n"
+        "varying vec4 fragColor;            \n"
+        "varying vec3 fragNormal;           \n"
+#endif
+        "uniform sampler2D texture0;        \n"
+        "uniform vec4 fragTintColor;        \n"
+        "uniform vec4 colAmbient;           \n"
+        "uniform vec4 colSpecular;          \n"
+        "uniform vec3 lightDir;             \n"
+        "vec3 LambertLighting(in vec3 n, in vec3 l)     \n"
+        "{                                  \n"
+        "   return clamp(dot(n, l), 0, 1)*fragTintColor.rgb;  \n"
+        "}                                  \n"
+        
+        "void main()                        \n"
+        "{                                  \n"
+        "   vec3 n = normalize(fragNormal); \n"
+        "   vec3 l = normalize(lightDir);   \n"
+#if defined(GRAPHICS_API_OPENGL_33)
+        "   vec4 texelColor = texture(texture0, fragTexCoord);   \n"
+        "   finalColor = vec4(texelColor.rgb*(colAmbient.rgb + LambertLighting(n, l)) - colSpecular.rgb + colSpecular.rgb, texelColor.a*fragTintColor.a);     \n"   // Stupid specular color operation to avoid shader location errors
+#elif defined(GRAPHICS_API_OPENGL_ES2)
+        "   vec4 texelColor = texture2D(texture0, fragTexCoord); \n" // NOTE: texture2D() is deprecated on OpenGL 3.3 and ES 3.0
+        "   gl_FragColor = texelColor*fragTintColor*fragColor;   \n"
+#endif
+        "}                                  \n";
+
     shader.id = LoadShaderProgram(vShaderStr, fShaderStr);
 
     if (shader.id != 0) TraceLog(INFO, "[SHDR ID %i] Standard shader loaded successfully", shader.id);
@@ -2554,10 +2636,23 @@ static void UnloadDefaultShader(void)
     //glDetachShader(defaultShader, vertexShader);
     //glDetachShader(defaultShader, fragmentShader);
     //glDeleteShader(vertexShader);     // Already deleted on shader compilation
-    //glDeleteShader(fragmentShader);   // Already deleted on sahder compilation
+    //glDeleteShader(fragmentShader);   // Already deleted on shader compilation
     glDeleteProgram(defaultShader.id);
 }
 
+// Unload standard shader 
+static void UnloadStandardShader(void)
+{
+    glUseProgram(0);
+
+    //glDetachShader(defaultShader, vertexShader);
+    //glDetachShader(defaultShader, fragmentShader);
+    //glDeleteShader(vertexShader);     // Already deleted on shader compilation
+    //glDeleteShader(fragmentShader);   // Already deleted on shader compilation
+    glDeleteProgram(standardShader.id);
+}
+
+
 // Load default internal buffers (lines, triangles, quads)
 static void LoadDefaultBuffers(void)
 {
@@ -3006,6 +3101,9 @@ static void UnloadDefaultBuffers(void)
 // TODO: Review memcpy() and parameters pass
 static void SetShaderLights(Shader shader)
 {
+    // Note: currently working with one light (index 0)
+    // TODO: add multi-lights feature (http://www.learnopengl.com/#!Lighting/Multiple-lights)
+    
     /*
     // NOTE: Standard Shader must include the following data:
         
@@ -3023,7 +3121,7 @@ static void SetShaderLights(Shader shader)
     uniform Light lights[maxLights];
     */
     
-    int locPoint;
+    /*int locPoint;
     char locName[32] = "lights[x].position\0";
     
     glUseProgram(shader.id);
@@ -3052,9 +3150,10 @@ static void SetShaderLights(Shader shader)
         glUniform1f(locPoint, lights[i]->intensity);
         
         // TODO: Pass to the shader any other required data from LightData struct
-    }
+    }*/
     
-    glUseProgram(0);
+    int locPoint = GetShaderLocation(shader, "lightDir");
+    glUniform3f(locPoint, lights[0]->position.x, lights[0]->position.y, lights[0]->position.z);
 }
 
 // Read text data from file

From c0983f34007877bdf730471715163aff32ce89f1 Mon Sep 17 00:00:00 2001
From: Gordon McShane <gordonmcshane@gmail.com>
Date: Fri, 20 May 2016 11:03:44 -0700
Subject: [PATCH 27/33] fix example

- fix gamepad axis query in example broken by db4585b Improved gamepad support
---
 examples/core_input_gamepad.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/examples/core_input_gamepad.c b/examples/core_input_gamepad.c
index 1de2d424e..6c3568297 100644
--- a/examples/core_input_gamepad.c
+++ b/examples/core_input_gamepad.c
@@ -36,7 +36,8 @@ int main()
         //----------------------------------------------------------------------------------
         if (IsGamepadAvailable(GAMEPAD_PLAYER1))
         {
-            gamepadMovement = GetGamepadMovement(GAMEPAD_PLAYER1);
+            gamepadMovement.x = GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_LEFT_X);
+            gamepadMovement.y = GetGamepadAxisMovement(GAMEPAD_PLAYER1, GAMEPAD_XBOX_AXIS_LEFT_Y);
 
             ballPosition.x += gamepadMovement.x;
             ballPosition.y -= gamepadMovement.y;

From c9ac176fa794a4601e9f5ec789b9f6ab5d11e9af Mon Sep 17 00:00:00 2001
From: Gordon McShane <gordonmcshane@gmail.com>
Date: Fri, 20 May 2016 11:26:06 -0700
Subject: [PATCH 28/33] remove user-specific ant files

---
 .gitignore                                 |  1 +
 src_android/local.properties               | 10 ----------
 templates/android_project/local.properties | 10 ----------
 3 files changed, 1 insertion(+), 20 deletions(-)
 delete mode 100644 src_android/local.properties
 delete mode 100644 templates/android_project/local.properties

diff --git a/.gitignore b/.gitignore
index 34affc870..d6a55b263 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ src_android/obj/
 templates/android_project/bin/
 templates/android_project/obj/
 templates/android_project/libs/
+local.properties
 
 # Ignore thumbnails created by windows
 Thumbs.db
diff --git a/src_android/local.properties b/src_android/local.properties
deleted file mode 100644
index f46293eac..000000000
--- a/src_android/local.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must *NOT* be checked into Version Control Systems,
-# as it contains information specific to your local configuration.
-
-# location of the SDK. This is only used by Ant
-# For customization when using a Version Control System, please read the
-# header note.
-sdk.dir=C:\\android-sdk
diff --git a/templates/android_project/local.properties b/templates/android_project/local.properties
deleted file mode 100644
index f46293eac..000000000
--- a/templates/android_project/local.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must *NOT* be checked into Version Control Systems,
-# as it contains information specific to your local configuration.
-
-# location of the SDK. This is only used by Ant
-# For customization when using a Version Control System, please read the
-# header note.
-sdk.dir=C:\\android-sdk

From cf71e1242e593de5b77d6ff219569e8c0d2c7fd9 Mon Sep 17 00:00:00 2001
From: victorfisac <victorfisac@gmail.com>
Date: Sat, 21 May 2016 18:08:09 +0200
Subject: [PATCH 29/33] Fix some audio module compile warnings

---
 src/audio.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/audio.c b/src/audio.c
index 43e8be14e..0c61c0fa8 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -384,7 +384,7 @@ RawAudioContext InitRawAudioContext(int sampleRate, int channels, bool floatingP
     for(mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot
     {
         if(mixChannelsActive_g[mixIndex] == NULL) break;
-        else if(mixIndex = MAX_MIX_CHANNELS - 1) return -1; // error
+        else if(mixIndex == MAX_MIX_CHANNELS - 1) return -1; // error
     }
     
     if(InitMixChannel(sampleRate, mixIndex, channels, floatingPoint))
@@ -772,7 +772,7 @@ int PlayMusicStream(int musicIndex, char *fileName)
     for(mixIndex = 0; mixIndex < MAX_MIX_CHANNELS; mixIndex++) // find empty mix channel slot
     {
         if(mixChannelsActive_g[mixIndex] == NULL) break;
-        else if(mixIndex = MAX_MIX_CHANNELS - 1) return 2; // error
+        else if(mixIndex == MAX_MIX_CHANNELS - 1) return 2; // error
     }
     
     if (strcmp(GetExtension(fileName),"ogg") == 0)
@@ -956,7 +956,7 @@ float GetMusicTimeLength(int index)
 // Get current music time played (in seconds)
 float GetMusicTimePlayed(int index)
 {
-    float secondsPlayed;
+    float secondsPlayed = 0.0f;
     if(index < MAX_MUSIC_STREAMS && currentMusic[index].mixc)
     {
         if (currentMusic[index].chipTune)
@@ -972,7 +972,6 @@ float GetMusicTimePlayed(int index)
             secondsPlayed = (float)samplesPlayed / (currentMusic[index].mixc->sampleRate * currentMusic[index].mixc->channels);
         }
     }
-    
 
     return secondsPlayed;
 }

From 30941c0dd1f7904b5a0b50c05ec17265f8d69baa Mon Sep 17 00:00:00 2001
From: victorfisac <victorfisac@gmail.com>
Date: Sat, 21 May 2016 18:10:06 +0200
Subject: [PATCH 30/33] Add Draw3DLine function and fixed MLT glossiness import
 value

In standard shader, material glossiness is a value from 0 to 1000 like
in MLT files. So, it doesn't need to be normalized.
---
 src/models.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/src/models.c b/src/models.c
index 2629dffdb..aef79626b 100644
--- a/src/models.c
+++ b/src/models.c
@@ -65,6 +65,16 @@ static Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
 // Module Functions Definition
 //----------------------------------------------------------------------------------
 
+// Draw a line in 3D world space
+void Draw3DLine(Vector3 startPos, Vector3 endPos, Color color)
+{
+    rlBegin(RL_LINES);
+        rlColor4ub(color.r, color.g, color.b, color.a);
+        rlVertex3f(startPos.x, startPos.y, startPos.z);
+        rlVertex3f(endPos.x, endPos.y, endPos.z);
+    rlEnd();
+}
+
 // Draw cube
 // NOTE: Cube position is the center position
 void DrawCube(Vector3 position, float width, float height, float length, Color color)
@@ -2071,8 +2081,7 @@ static Material LoadMTL(const char *fileName)
                     int shininess = 0;
                     sscanf(buffer, "Ns %i", &shininess);
                     
-                    // Normalize shininess value to material glossiness attribute
-                    material.glossiness = (float)shininess/1000;
+                    material.glossiness = (float)shininess;
                 }
                 else if (buffer[1] == 'i')  // Ni int   Refraction index.
                 {

From 80eb4f3f50bb9773dd0e5d4b70c50e18df8996e5 Mon Sep 17 00:00:00 2001
From: victorfisac <victorfisac@gmail.com>
Date: Sat, 21 May 2016 18:11:25 +0200
Subject: [PATCH 31/33] Remove deprecated phong lighting shaders and example

---
 examples/resources/shaders/glsl330/phong.fs |  85 ----------
 examples/resources/shaders/glsl330/phong.vs |  29 ----
 examples/shaders_basic_lighting.c           | 171 --------------------
 3 files changed, 285 deletions(-)
 delete mode 100644 examples/resources/shaders/glsl330/phong.fs
 delete mode 100644 examples/resources/shaders/glsl330/phong.vs
 delete mode 100644 examples/shaders_basic_lighting.c

diff --git a/examples/resources/shaders/glsl330/phong.fs b/examples/resources/shaders/glsl330/phong.fs
deleted file mode 100644
index c14b346a9..000000000
--- a/examples/resources/shaders/glsl330/phong.fs
+++ /dev/null
@@ -1,85 +0,0 @@
-#version 330
-
-// Input vertex attributes (from vertex shader)
-in vec2 fragTexCoord;
-in vec3 fragNormal;
-
-// Input uniform values
-uniform sampler2D texture0;
-uniform vec4 fragTintColor;
-
-// Output fragment color
-out vec4 finalColor;
-
-// NOTE: Add here your custom variables
-
-// Light uniform values
-uniform vec3 lightAmbientColor = vec3(0.6, 0.3, 0.0);
-uniform vec3 lightDiffuseColor = vec3(1.0, 0.5, 0.0);
-uniform vec3 lightSpecularColor = vec3(0.0, 1.0, 0.0);
-uniform float lightIntensity = 1.0;
-uniform float lightSpecIntensity = 1.0;
-
-// Material uniform values
-uniform vec3 matAmbientColor = vec3(1.0, 1.0, 1.0);
-uniform vec3 matSpecularColor = vec3(1.0, 1.0, 1.0);
-uniform float matGlossiness = 50.0;
-
-// World uniform values
-uniform vec3 lightPosition;
-uniform vec3 cameraPosition;
-
-// Fragment shader output data
-out vec4 fragColor;
-
-// Calculate ambient lighting component
-vec3 AmbientLighting()
-{
-    return (matAmbientColor*lightAmbientColor);
-}
-
-// Calculate diffuse lighting component
-vec3 DiffuseLighting(in vec3 N, in vec3 L)
-{
-    // Lambertian reflection calculation
-    float diffuse = clamp(dot(N, L), 0, 1);
-
-    return (fragTintColor.xyz*lightDiffuseColor*lightIntensity*diffuse);
-}
-
-// Calculate specular lighting component
-vec3 SpecularLighting(in vec3 N, in vec3 L, in vec3 V)
-{
-    float specular = 0.0;
-
-    // Calculate specular reflection only if the surface is oriented to the light source
-    if (dot(N, L) > 0)
-    {
-        // Calculate half vector
-        vec3 H = normalize(L + V);
-
-        // Calculate specular intensity
-        specular = pow(dot(N, H), 3 + matGlossiness);
-    }
-   
-    return (matSpecularColor*lightSpecularColor*lightSpecIntensity*specular);
-}
-
-void main()
-{
-    // Normalize input vectors
-    vec3 L = normalize(lightPosition);
-    vec3 V = normalize(cameraPosition);
-    vec3 N = normalize(fragNormal);
-    
-    // Calculate lighting components 
-    vec3 ambient = AmbientLighting();
-    vec3 diffuse = DiffuseLighting(N, L);
-    vec3 specular = SpecularLighting(N, L, V);
-    
-    // Texel color fetching from texture sampler
-    vec4 texelColor = texture(texture0, fragTexCoord);
-
-    // Calculate final fragment color
-    finalColor = vec4(texelColor.rgb*(ambient + diffuse + specular), texelColor.a);
-}
\ No newline at end of file
diff --git a/examples/resources/shaders/glsl330/phong.vs b/examples/resources/shaders/glsl330/phong.vs
deleted file mode 100644
index d68d9b3fc..000000000
--- a/examples/resources/shaders/glsl330/phong.vs
+++ /dev/null
@@ -1,29 +0,0 @@
-#version 330
-
-// Input vertex attributes
-in vec3 vertexPosition;
-in vec2 vertexTexCoord;
-in vec3 vertexNormal;
-
-// Input uniform values
-uniform mat4 mvpMatrix;
-
-// Output vertex attributes (to fragment shader)
-out vec2 fragTexCoord;
-out vec3 fragNormal;
-
-// NOTE: Add here your custom variables
-uniform mat4 modelMatrix;
-
-void main()
-{
-    // Send vertex attributes to fragment shader
-    fragTexCoord = vertexTexCoord;
-
-    // Calculate view vector normal from model
-    mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));
-    fragNormal = normalize(normalMatrix*vertexNormal);
-    
-    // Calculate final vertex position
-    gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
-}
\ No newline at end of file
diff --git a/examples/shaders_basic_lighting.c b/examples/shaders_basic_lighting.c
deleted file mode 100644
index d72eb4176..000000000
--- a/examples/shaders_basic_lighting.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*******************************************************************************************
-*
-*   raylib [shaders] example - Basic lighting: Blinn-Phong
-*
-*   This example has been created using raylib 1.3 (www.raylib.com)
-*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
-*
-*   Copyright (c) 2014 Ramon Santamaria (@raysan5)
-*
-********************************************************************************************/
-
-#include "raylib.h"
-
-#define SHININESS_SPEED 1.0f
-#define LIGHT_SPEED 0.25f
-
-// Light type
-typedef struct Light {
-    Vector3 position;
-    Vector3 direction;
-    float intensity;
-    float specIntensity;
-    Color diffuse;
-    Color ambient;
-    Color specular;
-} Light;
-
-int main()
-{
-    // Initialization
-    //--------------------------------------------------------------------------------------
-    const int screenWidth = 800;
-    const int screenHeight = 450;
-    
-    SetConfigFlags(FLAG_MSAA_4X_HINT);
-    InitWindow(screenWidth, screenHeight, "raylib [shaders] example - basic lighting");
-    
-    // Camera initialization
-    Camera camera = {{ 8.0f, 8.0f, 8.0f }, { 0.0f, 3.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f };
-    
-    // Model initialization
-    Vector3 position = { 0.0f, 0.0f, 0.0f };
-    Model model = LoadModel("resources/model/dwarf.obj");
-    Shader shader = LoadShader("resources/shaders/glsl330/phong.vs", "resources/shaders/glsl330/phong.fs");
-    SetModelShader(&model, shader);
-    
-    // Shader locations initialization
-    int lIntensityLoc = GetShaderLocation(shader, "lightIntensity");
-    int lAmbientLoc = GetShaderLocation(shader, "lightAmbientColor");
-    int lDiffuseLoc = GetShaderLocation(shader, "lightDiffuseColor");
-    int lSpecularLoc = GetShaderLocation(shader, "lightSpecularColor");
-    int lSpecIntensityLoc = GetShaderLocation(shader, "lightSpecIntensity");
-    
-    int mAmbientLoc = GetShaderLocation(shader, "matAmbientColor");
-    int mSpecularLoc = GetShaderLocation(shader, "matSpecularColor");
-    int mGlossLoc = GetShaderLocation(shader, "matGlossiness");
-    
-    // Camera and light vectors shader locations
-    int cameraLoc = GetShaderLocation(shader, "cameraPosition");
-    int lightLoc = GetShaderLocation(shader, "lightPosition");
-    
-    // Model and View matrix locations (required for lighting)
-    int modelLoc = GetShaderLocation(shader, "modelMatrix");
-    //int viewLoc = GetShaderLocation(shader, "viewMatrix");        // Not used
-    
-    // Light and material definitions
-    Light light;
-    Material matBlinn;
-    
-    // Light initialization
-    light.position = (Vector3){ 4.0f, 2.0f, 0.0f };
-    light.direction = (Vector3){ 5.0f, 1.0f, 1.0f };
-    light.intensity = 1.0f;
-    light.diffuse = WHITE;
-    light.ambient = (Color){ 150, 75, 0, 255 };
-    light.specular = WHITE;
-    light.specIntensity = 1.0f;
-    
-    // Material initialization
-    matBlinn.colDiffuse = WHITE;
-    matBlinn.colAmbient = (Color){ 50, 50, 50, 255 };
-    matBlinn.colSpecular = WHITE;
-    matBlinn.glossiness = 50.0f;
-    
-    // Setup camera
-    SetCameraMode(CAMERA_FREE);             // Set camera mode
-    SetCameraPosition(camera.position);     // Set internal camera position to match our camera position
-    SetCameraTarget(camera.target);         // Set internal camera target to match our camera target
-    
-    SetTargetFPS(60);
-    //--------------------------------------------------------------------------------------
-    
-    // Main game loop
-    while (!WindowShouldClose())    // Detect window close button or ESC key
-    {
-        // Update
-        //----------------------------------------------------------------------------------
-        UpdateCamera(&camera);      // Update camera position
-        
-        // NOTE: Model transform can be set in model.transform or directly with params at draw... WATCH OUT!
-        SetShaderValueMatrix(shader, modelLoc, model.transform);            // Send model matrix to shader
-        //SetShaderValueMatrix(shader, viewLoc, GetCameraMatrix(camera));   // Not used
-        
-        // Glossiness input control
-        if(IsKeyDown(KEY_UP)) matBlinn.glossiness += SHININESS_SPEED;
-        else if(IsKeyDown(KEY_DOWN))
-        {
-            matBlinn.glossiness -= SHININESS_SPEED;
-            if( matBlinn.glossiness < 0) matBlinn.glossiness = 0.0f;
-        }
-        
-        // Light X movement
-        if (IsKeyDown(KEY_D)) light.position.x += LIGHT_SPEED;
-        else if(IsKeyDown(KEY_A)) light.position.x -= LIGHT_SPEED;
-        
-        // Light Y movement
-        if (IsKeyDown(KEY_LEFT_SHIFT)) light.position.y += LIGHT_SPEED;
-        else if (IsKeyDown(KEY_LEFT_CONTROL)) light.position.y -= LIGHT_SPEED;
-
-        // Light Z movement
-        if (IsKeyDown(KEY_S)) light.position.z += LIGHT_SPEED;
-        else if (IsKeyDown(KEY_W)) light.position.z -= LIGHT_SPEED;
-        
-        // Send light values to shader
-        SetShaderValue(shader, lIntensityLoc, &light.intensity, 1);
-        SetShaderValue(shader, lAmbientLoc, ColorToFloat(light.ambient), 3);
-        SetShaderValue(shader, lDiffuseLoc, ColorToFloat(light.diffuse), 3);
-        SetShaderValue(shader, lSpecularLoc, ColorToFloat(light.specular), 3);
-        SetShaderValue(shader, lSpecIntensityLoc, &light.specIntensity, 1);
-        
-        // Send material values to shader
-        SetShaderValue(shader, mAmbientLoc, ColorToFloat(matBlinn.colAmbient), 3);
-        SetShaderValue(shader, mSpecularLoc, ColorToFloat(matBlinn.colSpecular), 3);
-        SetShaderValue(shader, mGlossLoc, &matBlinn.glossiness, 1);
-        
-        // Send camera and light transform values to shader
-        SetShaderValue(shader, cameraLoc, VectorToFloat(camera.position), 3);
-        SetShaderValue(shader, lightLoc, VectorToFloat(light.position), 3);
-        //----------------------------------------------------------------------------------
-        
-        // Draw
-        //----------------------------------------------------------------------------------
-        BeginDrawing();
-        
-            ClearBackground(RAYWHITE);
-            
-            Begin3dMode(camera);
-                
-                DrawModel(model, position, 4.0f, matBlinn.colDiffuse);
-                DrawSphere(light.position, 0.5f, GOLD);
-                
-                DrawGrid(20, 1.0f);
-                
-            End3dMode();
-            
-            DrawFPS(10, 10);                // Draw FPS
-            
-        EndDrawing();
-        //----------------------------------------------------------------------------------
-    }
-
-    // De-Initialization
-    //--------------------------------------------------------------------------------------
-    UnloadShader(shader);
-    UnloadModel(model);
-
-    CloseWindow();        // Close window and OpenGL context
-    //--------------------------------------------------------------------------------------
-    
-    return 0;
-}

From c320a21f2b0e96f7605624e84048ccab9700b516 Mon Sep 17 00:00:00 2001
From: victorfisac <victorfisac@gmail.com>
Date: Sat, 21 May 2016 18:16:39 +0200
Subject: [PATCH 32/33] Add standard lighting (2/3)

- 3 light types added (point, directional, spot).
- DrawLights() function added using line shapes.
- Standard lighting example added.
- Removed useless struct variables from material and light.
- Fixed light attributes dynamic locations errors.
- Standard vertex and fragment shaders temporally added until rewrite it
as char pointers in rlgl.
TODO:
- Add normal and specular maps calculations in standard shader.
- Add control structs to handle which attributes needs to be calculated
(textures, specular...).
- Adapt standard shader to version 110.
- Rewrite standard shader as char pointers in rlgl.
---
 examples/resources/shaders/standard.fs | 136 ++++++++++++++++
 examples/resources/shaders/standard.vs |  23 +++
 examples/shaders_standard_lighting.c   | 118 ++++++++++++++
 src/raylib.h                           |  15 +-
 src/rlgl.c                             | 213 +++++++++++--------------
 src/rlgl.h                             |  32 ++--
 6 files changed, 388 insertions(+), 149 deletions(-)
 create mode 100644 examples/resources/shaders/standard.fs
 create mode 100644 examples/resources/shaders/standard.vs
 create mode 100644 examples/shaders_standard_lighting.c

diff --git a/examples/resources/shaders/standard.fs b/examples/resources/shaders/standard.fs
new file mode 100644
index 000000000..30c841d2d
--- /dev/null
+++ b/examples/resources/shaders/standard.fs
@@ -0,0 +1,136 @@
+#version 330
+
+in vec3 fragPosition;
+in vec2 fragTexCoord;
+in vec4 fragColor;
+in vec3 fragNormal;
+
+out vec4 finalColor;
+
+uniform sampler2D texture0;
+
+uniform vec4 colAmbient;
+uniform vec4 colDiffuse;
+uniform vec4 colSpecular;
+uniform float glossiness;
+
+uniform mat4 modelMatrix;
+uniform vec3 viewDir;
+
+struct Light {
+    int enabled;
+    int type;
+    vec3 position;
+    vec3 direction;
+    vec4 diffuse;
+    float intensity;
+    float attenuation;
+    float coneAngle;
+};
+
+const int maxLights = 8;
+uniform int lightsCount;
+uniform Light lights[maxLights];
+
+vec3 CalcPointLight(Light l, vec3 n, vec3 v)
+{
+    vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1));
+    vec3 surfaceToLight = l.position - surfacePos;
+    
+    // Diffuse shading
+    float brightness = clamp(dot(n, surfaceToLight)/(length(surfaceToLight)*length(n)), 0, 1);
+    float diff = 1.0/dot(surfaceToLight/l.attenuation, surfaceToLight/l.attenuation)*brightness*l.intensity;
+    
+    // Specular shading
+    float spec = 0.0;
+    if(diff > 0.0)
+    {
+        vec3 h = normalize(-l.direction + v);
+        spec = pow(dot(n, h), 3 + glossiness);
+    }
+    
+    return (diff*l.diffuse.rgb*colDiffuse.rgb + spec*colSpecular.rgb);
+}
+
+vec3 CalcDirectionalLight(Light l, vec3 n, vec3 v)
+{
+    vec3 lightDir = normalize(-l.direction);
+    
+    // Diffuse shading
+    float diff = clamp(dot(n, lightDir), 0.0, 1.0)*l.intensity;
+    
+    // Specular shading
+    float spec = 0.0;
+    if(diff > 0.0)
+    {
+        vec3 h = normalize(lightDir + v);
+        spec = pow(dot(n, h), 3 + glossiness);
+    }
+    
+    // Combine results
+    return (diff*l.intensity*l.diffuse.rgb*colDiffuse.rgb + spec*colSpecular.rgb);
+}
+
+vec3 CalcSpotLight(Light l, vec3 n, vec3 v)
+{
+    vec3 surfacePos = vec3(modelMatrix*vec4(fragPosition, 1));
+    vec3 lightToSurface = normalize(surfacePos - l.position);
+    vec3 lightDir = normalize(-l.direction);
+    
+    // Diffuse shading
+    float diff = clamp(dot(n, lightDir), 0.0, 1.0)*l.intensity;
+    
+    // Spot attenuation
+    float attenuation = clamp(dot(n, lightToSurface), 0.0, 1.0);
+    attenuation = dot(lightToSurface, -lightDir);
+    float lightToSurfaceAngle = degrees(acos(attenuation));
+    if(lightToSurfaceAngle > l.coneAngle) attenuation = 0.0;
+    float falloff = (l.coneAngle - lightToSurfaceAngle)/l.coneAngle;
+    
+    // Combine diffuse and attenuation
+    float diffAttenuation = diff*attenuation;
+    
+    // Specular shading
+    float spec = 0.0;
+    if(diffAttenuation > 0.0)
+    {
+        vec3 h = normalize(lightDir + v);
+        spec = pow(dot(n, h), 3 + glossiness);
+    }
+    
+    return falloff*(diffAttenuation*l.diffuse.rgb + spec*colSpecular.rgb);
+}
+
+void main()
+{
+    // Calculate fragment normal in screen space
+    mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));
+    vec3 normal = normalize(normalMatrix*fragNormal);
+   
+    // Normalize normal and view direction vectors
+    vec3 n = normalize(normal);
+    vec3 v = normalize(viewDir);
+
+    // Calculate diffuse texture color fetching
+    vec4 texelColor = texture(texture0, fragTexCoord);
+    vec3 lighting = colAmbient.rgb;
+    
+    for(int i = 0; i < lightsCount; i++)
+    {
+        // Check if light is enabled
+        if(lights[i].enabled == 1)
+        {
+            // Calculate lighting based on light type
+            switch(lights[i].type)
+            {
+                case 0: lighting += CalcPointLight(lights[i], n, v); break;
+                case 1: lighting += CalcDirectionalLight(lights[i], n, v); break;
+                case 2: lighting += CalcSpotLight(lights[i], n, v); break;
+                default: break;
+            }
+        }
+    }
+    
+    // Calculate final fragment color
+    finalColor = vec4(texelColor.rgb*lighting, texelColor.a);
+}
diff --git a/examples/resources/shaders/standard.vs b/examples/resources/shaders/standard.vs
new file mode 100644
index 000000000..fc0a5ff40
--- /dev/null
+++ b/examples/resources/shaders/standard.vs
@@ -0,0 +1,23 @@
+#version 330 
+
+in vec3 vertexPosition;
+in vec3 vertexNormal;
+in vec2 vertexTexCoord;
+in vec4 vertexColor;
+
+out vec3 fragPosition;
+out vec2 fragTexCoord;
+out vec4 fragColor;
+out vec3 fragNormal;
+
+uniform mat4 mvpMatrix;
+
+void main()
+{
+    fragPosition = vertexPosition;
+    fragTexCoord = vertexTexCoord;
+    fragColor = vertexColor;
+    fragNormal = vertexNormal;
+
+    gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);
+}
\ No newline at end of file
diff --git a/examples/shaders_standard_lighting.c b/examples/shaders_standard_lighting.c
new file mode 100644
index 000000000..7a9cc086d
--- /dev/null
+++ b/examples/shaders_standard_lighting.c
@@ -0,0 +1,118 @@
+/*******************************************************************************************
+*
+*   raylib [shaders] example - Standard lighting (materials and lights)
+*
+*   NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
+*         OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
+*
+*   NOTE: Shaders used in this example are #version 330 (OpenGL 3.3), to test this example
+*         on OpenGL ES 2.0 platforms (Android, Raspberry Pi, HTML5), use #version 100 shaders
+*         raylib comes with shaders ready for both versions, check raylib/shaders install folder
+*
+*   This example has been created using raylib 1.3 (www.raylib.com)
+*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
+*
+*   Copyright (c) 2016 Ramon Santamaria (@raysan5)
+*
+********************************************************************************************/
+
+#include "raylib.h"
+#include "raymath.h"
+
+int main()
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    int screenWidth = 800;
+    int screenHeight = 450;
+    
+    SetConfigFlags(FLAG_MSAA_4X_HINT);      // Enable Multi Sampling Anti Aliasing 4x (if available)
+
+    InitWindow(screenWidth, screenHeight, "raylib [shaders] example - model shader");
+
+    // Define the camera to look into our 3d world
+    Camera camera = {{ 4.0f, 4.0f, 4.0f }, { 0.0f, 1.5f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f };
+    Vector3 position = { 0.0f, 0.0f, 0.0f };   // Set model position
+    
+    Model dwarf = LoadModel("resources/model/dwarf.obj");                   // Load OBJ model
+    Texture2D texDiffuse = LoadTexture("resources/model/dwarf_diffuse.png");   // Load model diffuse texture
+
+    Material material = LoadStandardMaterial();
+    material.texDiffuse = texDiffuse;
+    material.colDiffuse = (Color){255, 255, 255, 255};
+    material.colAmbient = (Color){0, 0, 10, 255};
+    material.colSpecular = (Color){255, 255, 255, 255};
+    material.glossiness = 50.0f;
+    dwarf.material = material;      // Apply material to model
+    
+    Light spotLight = CreateLight(LIGHT_SPOT, (Vector3){3.0f, 5.0f, 2.0f}, (Color){255, 255, 255, 255});
+    spotLight->target = (Vector3){0.0f, 0.0f, 0.0f};
+    spotLight->intensity = 2.0f;
+    spotLight->diffuse = (Color){255, 100, 100, 255};
+    spotLight->coneAngle = 60.0f;
+    
+    Light dirLight = CreateLight(LIGHT_DIRECTIONAL, (Vector3){0.0f, -3.0f, -3.0f}, (Color){255, 255, 255, 255});
+    dirLight->target = (Vector3){1.0f, -2.0f, -2.0f};
+    dirLight->intensity = 2.0f;
+    dirLight->diffuse = (Color){100, 255, 100, 255};
+    
+    Light pointLight = CreateLight(LIGHT_POINT, (Vector3){0.0f, 4.0f, 5.0f}, (Color){255, 255, 255, 255});
+    pointLight->intensity = 2.0f;
+    pointLight->diffuse = (Color){100, 100, 255, 255};
+    pointLight->attenuation = 3.0f;
+
+    // Setup orbital camera
+    SetCameraMode(CAMERA_ORBITAL);          // Set a orbital camera mode
+    SetCameraPosition(camera.position);     // Set internal camera position to match our camera position
+    SetCameraTarget(camera.target);         // Set internal camera target to match our camera target
+
+    SetTargetFPS(60);                       // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
+
+    // Main game loop
+    while (!WindowShouldClose())            // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        UpdateCamera(&camera);              // Update internal camera and our camera
+        //----------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            Begin3dMode(camera);
+
+                DrawModel(dwarf, position, 2.0f, WHITE);   // Draw 3d model with texture
+                
+                DrawLights();   // Draw all created lights in 3D world
+
+                DrawGrid(10, 1.0f);     // Draw a grid
+
+            End3dMode();
+            
+            DrawText("(c) Dwarf 3D model by David Moreno", screenWidth - 200, screenHeight - 20, 10, GRAY);
+
+            DrawFPS(10, 10);
+
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadMaterial(material);   // Unload material and assigned textures
+    UnloadModel(dwarf);         // Unload model
+    
+    // Destroy all created lights
+    DestroyLight(pointLight);
+    DestroyLight(dirLight);
+    DestroyLight(spotLight);
+
+    CloseWindow();              // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}
\ No newline at end of file
diff --git a/src/raylib.h b/src/raylib.h
index 48534fd6d..9cd02fd8d 100644
--- a/src/raylib.h
+++ b/src/raylib.h
@@ -418,7 +418,7 @@ typedef struct Material {
     Color colAmbient;           // Ambient color
     Color colSpecular;          // Specular color
     
-    float glossiness;           // Glossiness level
+    float glossiness;           // Glossiness level (Ranges from 0 to 1000)
     float normalDepth;          // Normal map depth
 } Material;
 
@@ -430,22 +430,19 @@ typedef struct Model {
 } Model;
 
 // Light type
-// TODO: Review contained data to support different light types and features
 typedef struct LightData {
     int id;
     int type;           // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT
     bool enabled;
     
     Vector3 position;
-    Vector3 direction;  // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction)
-    float attenuation;  // Lost of light intensity with distance (use radius?)
+    Vector3 target;     // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target)
+    float attenuation;  // Lost of light intensity with distance (world distance)
     
-    Color diffuse;      // Use Vector3 diffuse (including intensities)?
+    Color diffuse;      // Use Vector3 diffuse
     float intensity;
     
-    Color specular;
-    
-    float coneAngle;    // SpotLight
+    float coneAngle;    // Spot light max angle
 } LightData, *Light;
 
 // Light types
@@ -805,6 +802,7 @@ const char *SubText(const char *text, int position, int length);
 //------------------------------------------------------------------------------------
 // Basic 3d Shapes Drawing Functions (Module: models)
 //------------------------------------------------------------------------------------
+void Draw3DLine(Vector3 startPos, Vector3 endPos, Color color);                                    // Draw a line in 3D world space
 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
@@ -874,6 +872,7 @@ void SetShaderValueMatrix(Shader shader, int uniformLoc, Matrix mat);       // S
 void SetBlendMode(int mode);                                        // Set blending mode (alpha, additive, multiplied)
 
 Light CreateLight(int type, Vector3 position, Color diffuse);       // Create a new light, initialize it and add to pool
+void DrawLights(void);                                              // Draw all created lights in 3D world
 void DestroyLight(Light light);                                     // Destroy a light and take it out of the list
 
 //----------------------------------------------------------------------------------
diff --git a/src/rlgl.c b/src/rlgl.c
index e2195e4d1..55677f3e8 100644
--- a/src/rlgl.c
+++ b/src/rlgl.c
@@ -1773,6 +1773,9 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
         // Send model transformations matrix to shader
         glUniformMatrix4fv(glGetUniformLocation(material.shader.id, "modelMatrix"), 1, false, MatrixToFloat(transform));
         
+        // Send view transformation matrix to shader. View matrix 8, 9 and 10 are view direction vector axis values (target - position)
+        glUniform3f(glGetUniformLocation(material.shader.id, "viewDir"), matView.m8, matView.m9, matView.m10);
+        
         // Setup shader uniforms for lights
         SetShaderLights(material.shader);
         
@@ -1782,8 +1785,8 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
         // Upload to shader material.colSpecular
         glUniform4f(glGetUniformLocation(material.shader.id, "colSpecular"), (float)material.colSpecular.r/255, (float)material.colSpecular.g/255, (float)material.colSpecular.b/255, (float)material.colSpecular.a/255);
     
-        // TODO: Upload to shader glossiness
-        //glUniform1f(???, material.glossiness);
+        // Upload to shader glossiness
+        glUniform1f(glGetUniformLocation(material.shader.id, "glossiness"), material.glossiness);
     }    
     
     // Set shader textures (diffuse, normal, specular)
@@ -2245,7 +2248,6 @@ void SetBlendMode(int mode)
 }
 
 // Create a new light, initialize it and add to pool
-// TODO: Review creation parameters (only generic ones)
 Light CreateLight(int type, Vector3 position, Color diffuse)
 {
     // Allocate dynamic memory
@@ -2257,10 +2259,9 @@ Light CreateLight(int type, Vector3 position, Color diffuse)
     light->enabled = true;
     
     light->position = position;
-    light->direction = (Vector3){ 0.0f, 0.0f, 0.0f };
+    light->target = (Vector3){ 0.0f, 0.0f, 0.0f };
     light->intensity = 1.0f;
     light->diffuse = diffuse;
-    light->specular = WHITE;
     
     // Add new light to the array
     lights[lightsCount] = light;
@@ -2271,6 +2272,31 @@ Light CreateLight(int type, Vector3 position, Color diffuse)
     return light;
 }
 
+// Draw all created lights in 3D world
+void DrawLights(void)
+{
+    for (int i = 0; i < lightsCount; i++)
+    {
+        switch (lights[i]->type)
+        {
+            case LIGHT_POINT: DrawSphereWires(lights[i]->position, 0.3f*lights[i]->intensity, 4, 8, (lights[i]->enabled ? lights[i]->diffuse : BLACK)); break;
+            case LIGHT_DIRECTIONAL:
+            {                
+                Draw3DLine(lights[i]->position, lights[i]->target, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
+                DrawSphereWires(lights[i]->position, 0.3f*lights[i]->intensity, 4, 8, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
+                DrawCubeWires(lights[i]->target, 0.3f, 0.3f, 0.3f, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
+            }
+            case LIGHT_SPOT:
+            {                
+                Draw3DLine(lights[i]->position, lights[i]->target, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
+                DrawCylinderWires(lights[i]->position, 0.0f, 0.3f*lights[i]->coneAngle/50, 0.6f, 5, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
+                DrawCubeWires(lights[i]->target, 0.3f, 0.3f, 0.3f, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
+            } break;
+            default: break;
+        }
+    }
+}
+
 // Destroy a light and take it out of the list
 void DestroyLight(Light light)
 {
@@ -2488,15 +2514,15 @@ static Shader LoadDefaultShader(void)
         "varying vec4 fragColor;            \n"
 #endif
         "uniform sampler2D texture0;        \n"
-        "uniform vec4 fragTintColor;        \n"
+        "uniform vec4 colDiffuse;           \n"
         "void main()                        \n"
         "{                                  \n"
 #if defined(GRAPHICS_API_OPENGL_33)
         "    vec4 texelColor = texture(texture0, fragTexCoord);   \n"
-        "    finalColor = texelColor*fragTintColor*fragColor;     \n"
+        "    finalColor = texelColor*colDiffuse*fragColor;        \n"
 #elif defined(GRAPHICS_API_OPENGL_ES2)
         "    vec4 texelColor = texture2D(texture0, fragTexCoord); \n" // NOTE: texture2D() is deprecated on OpenGL 3.3 and ES 3.0
-        "    gl_FragColor = texelColor*fragTintColor*fragColor;   \n"
+        "    gl_FragColor = texelColor*colDiffuse*fragColor;      \n"
 #endif
         "}                                  \n";
 
@@ -2513,87 +2539,17 @@ static Shader LoadDefaultShader(void)
 // Load standard shader
 // NOTE: This shader supports: 
 //      - Up to 3 different maps: diffuse, normal, specular
-//      - Material properties: colDiffuse, colAmbient, colSpecular, glossiness, normalDepth
+//      - Material properties: colAmbient, colDiffuse, colSpecular, glossiness, normalDepth
 //      - Up to 8 lights: Point, Directional or Spot
 static Shader LoadStandardShader(void)
 {
-    Shader shader;
-    
-    // Vertex shader directly defined, no external file required
-#if defined(GRAPHICS_API_OPENGL_33)
-    char vShaderStr[] = "#version 330       \n"
-        "in vec3 vertexPosition;            \n"
-        "in vec3 vertexNormal;              \n"
-        "in vec2 vertexTexCoord;            \n"
-        "in vec4 vertexColor;               \n"
-        "out vec2 fragTexCoord;             \n"
-        "out vec4 fragColor;                \n"
-        "out vec3 fragNormal;               \n"
-#elif defined(GRAPHICS_API_OPENGL_ES2)
-    char vShaderStr[] = "#version 100       \n"
-        "attribute vec3 vertexPosition;     \n"
-        "attribute vec3 vertexNormal;       \n"
-        "attribute vec2 vertexTexCoord;     \n"
-        "attribute vec4 vertexColor;        \n"
-        "varying vec2 fragTexCoord;         \n"
-        "varying vec4 fragColor;            \n"
-        "varying vec3 fragNormal;           \n"
-#endif
-        "uniform mat4 mvpMatrix;            \n"
-        "uniform mat4 modelMatrix;          \n"
-        "void main()                        \n"
-        "{                                  \n"
-        "   fragTexCoord = vertexTexCoord; \n"
-        "   fragColor = vertexColor;       \n"
-        "   mat3 normalMatrix = transpose(inverse(mat3(modelMatrix)));  \n"
-        "   fragNormal = normalize(normalMatrix*vertexNormal);  \n"
-        "   gl_Position = mvpMatrix*vec4(vertexPosition, 1.0);  \n"
-        "}                                  \n";
-
-    // TODO: add specular calculation, multi-lights structs and light type calculations (directional, point, spot)
-    // Fragment shader directly defined, no external file required
-#if defined(GRAPHICS_API_OPENGL_33)
-    char fShaderStr[] = "#version 330       \n"
-        "in vec2 fragTexCoord;              \n"
-        "in vec4 fragColor;                 \n"
-        "in vec3 fragNormal;                \n"
-        "out vec4 finalColor;               \n"
-#elif defined(GRAPHICS_API_OPENGL_ES2)
-    char fShaderStr[] = "#version 100       \n"
-        "precision mediump float;           \n"     // precision required for OpenGL ES2 (WebGL)
-        "varying vec2 fragTexCoord;         \n"
-        "varying vec4 fragColor;            \n"
-        "varying vec3 fragNormal;           \n"
-#endif
-        "uniform sampler2D texture0;        \n"
-        "uniform vec4 fragTintColor;        \n"
-        "uniform vec4 colAmbient;           \n"
-        "uniform vec4 colSpecular;          \n"
-        "uniform vec3 lightDir;             \n"
-        "vec3 LambertLighting(in vec3 n, in vec3 l)     \n"
-        "{                                  \n"
-        "   return clamp(dot(n, l), 0, 1)*fragTintColor.rgb;  \n"
-        "}                                  \n"
-        
-        "void main()                        \n"
-        "{                                  \n"
-        "   vec3 n = normalize(fragNormal); \n"
-        "   vec3 l = normalize(lightDir);   \n"
-#if defined(GRAPHICS_API_OPENGL_33)
-        "   vec4 texelColor = texture(texture0, fragTexCoord);   \n"
-        "   finalColor = vec4(texelColor.rgb*(colAmbient.rgb + LambertLighting(n, l)) - colSpecular.rgb + colSpecular.rgb, texelColor.a*fragTintColor.a);     \n"   // Stupid specular color operation to avoid shader location errors
-#elif defined(GRAPHICS_API_OPENGL_ES2)
-        "   vec4 texelColor = texture2D(texture0, fragTexCoord); \n" // NOTE: texture2D() is deprecated on OpenGL 3.3 and ES 3.0
-        "   gl_FragColor = texelColor*fragTintColor*fragColor;   \n"
-#endif
-        "}                                  \n";
-
-    shader.id = LoadShaderProgram(vShaderStr, fShaderStr);
+    // Load standard shader (TODO: rewrite as char pointers)
+    Shader shader = LoadShader("resources/shaders/standard.vs", "resources/shaders/standard.fs");
 
     if (shader.id != 0) TraceLog(INFO, "[SHDR ID %i] Standard shader loaded successfully", shader.id);
     else TraceLog(WARNING, "[SHDR ID %i] Standard shader could not be loaded", shader.id);
 
-    if (shader.id != 0) LoadDefaultShaderLocations(&shader);    // TODO: Review locations fetching
+    if (shader.id != 0) LoadDefaultShaderLocations(&shader);
 
     return shader;
 }
@@ -2622,7 +2578,7 @@ static void LoadDefaultShaderLocations(Shader *shader)
     shader->mvpLoc  = glGetUniformLocation(shader->id, "mvpMatrix");
 
     // Get handles to GLSL uniform locations (fragment shader)
-    shader->tintColorLoc = glGetUniformLocation(shader->id, "fragTintColor");
+    shader->tintColorLoc = glGetUniformLocation(shader->id, "colDiffuse");
     shader->mapDiffuseLoc = glGetUniformLocation(shader->id, "texture0");
     shader->mapNormalLoc = glGetUniformLocation(shader->id, "texture1");
     shader->mapSpecularLoc = glGetUniformLocation(shader->id, "texture2");
@@ -3098,62 +3054,75 @@ static void UnloadDefaultBuffers(void)
 
 // Sets shader uniform values for lights array
 // NOTE: It would be far easier with shader UBOs but are not supported on OpenGL ES 2.0f
-// TODO: Review memcpy() and parameters pass
 static void SetShaderLights(Shader shader)
 {
-    // Note: currently working with one light (index 0)
-    // TODO: add multi-lights feature (http://www.learnopengl.com/#!Lighting/Multiple-lights)
-    
-    /*
-    // NOTE: Standard Shader must include the following data:
-        
-    // Shader Light struct
-    struct Light {
-        vec3 position;
-        vec3 direction;
-        
-        vec3 diffuse;
-        float intensity;
-    }
-
-    const int maxLights = 8;
-    uniform int lightsCount;            // Number of lights
-    uniform Light lights[maxLights];
-    */
+    int locPoint = glGetUniformLocation(shader.id, "lightsCount");
+    glUniform1i(locPoint, lightsCount);
     
-    /*int locPoint;
     char locName[32] = "lights[x].position\0";
-    
-    glUseProgram(shader.id);
-
-    locPoint = glGetUniformLocation(shader.id, "lightsCount");
-    glUniform1i(locPoint, lightsCount);
 
     for (int i = 0; i < lightsCount; i++)
     {
         locName[7] = '0' + i;
         
-        memcpy(&locName[10], "position\0", strlen("position\0"));
-        locPoint = glGetUniformLocation(shader.id, locName);
-        glUniform3f(locPoint, lights[i]->position.x, lights[i]->position.y, lights[i]->position.z);
+        memcpy(&locName[10], "enabled\0", strlen("enabled\0") + 1);
+        locPoint = GetShaderLocation(shader, locName);
+        glUniform1i(locPoint, lights[i]->enabled);
         
-        memcpy(&locName[10], "direction\0", strlen("direction\0"));
-        locPoint = glGetUniformLocation(shader.id, locName);       
-        glUniform3f(locPoint, lights[i]->direction.x, lights[i]->direction.y, lights[i]->direction.z);
-
-        memcpy(&locName[10], "diffuse\0", strlen("diffuse\0"));
+        memcpy(&locName[10], "type\0", strlen("type\0") + 1);
+        locPoint = GetShaderLocation(shader, locName);
+        glUniform1i(locPoint, lights[i]->type);
+        
+        memcpy(&locName[10], "diffuse\0", strlen("diffuse\0") + 2);
         locPoint = glGetUniformLocation(shader.id, locName);
-        glUniform4f(locPoint, (float)lights[i]->diffuse.r/255, (float)lights[i]->diffuse.g/255, (float)lights[i]->diffuse.b/255, (float)lights[i]->diffuse.a/255 );
+        glUniform4f(locPoint, (float)lights[i]->diffuse.r/255, (float)lights[i]->diffuse.g/255, (float)lights[i]->diffuse.b/255, (float)lights[i]->diffuse.a/255);
         
         memcpy(&locName[10], "intensity\0", strlen("intensity\0"));
         locPoint = glGetUniformLocation(shader.id, locName);
         glUniform1f(locPoint, lights[i]->intensity);
         
+        switch(lights[i]->type)
+        {
+            case LIGHT_POINT:
+            {
+                memcpy(&locName[10], "position\0", strlen("position\0") + 1);
+                locPoint = GetShaderLocation(shader, locName);
+                glUniform3f(locPoint, lights[i]->position.x, lights[i]->position.y, lights[i]->position.z);
+                
+                memcpy(&locName[10], "attenuation\0", strlen("attenuation\0"));
+                locPoint = GetShaderLocation(shader, locName);
+                glUniform1f(locPoint, lights[i]->attenuation);
+            } break;
+            case LIGHT_DIRECTIONAL:
+            {
+                memcpy(&locName[10], "direction\0", strlen("direction\0") + 2);
+                locPoint = GetShaderLocation(shader, locName);
+                Vector3 direction = { lights[i]->target.x - lights[i]->position.x, lights[i]->target.y - lights[i]->position.y, lights[i]->target.z - lights[i]->position.z };
+                VectorNormalize(&direction);
+                glUniform3f(locPoint, direction.x, direction.y, direction.z);
+            } break;
+            case LIGHT_SPOT:
+            {
+                memcpy(&locName[10], "position\0", strlen("position\0") + 1);
+                locPoint = GetShaderLocation(shader, locName);
+                glUniform3f(locPoint, lights[i]->position.x, lights[i]->position.y, lights[i]->position.z);
+                
+                memcpy(&locName[10], "direction\0", strlen("direction\0") + 2);
+                locPoint = GetShaderLocation(shader, locName);
+                
+                Vector3 direction = { lights[i]->target.x - lights[i]->position.x, lights[i]->target.y - lights[i]->position.y, lights[i]->target.z - lights[i]->position.z };
+                VectorNormalize(&direction);
+                glUniform3f(locPoint, direction.x, direction.y, direction.z);
+                
+                memcpy(&locName[10], "coneAngle\0", strlen("coneAngle\0"));
+                locPoint = GetShaderLocation(shader, locName);
+                glUniform1f(locPoint, lights[i]->coneAngle);
+            } break;
+            default: break;
+        }
+        
         // TODO: Pass to the shader any other required data from LightData struct
-    }*/
-    
-    int locPoint = GetShaderLocation(shader, "lightDir");
-    glUniform3f(locPoint, lights[0]->position.x, lights[0]->position.y, lights[0]->position.z);
+    }
 }
 
 // Read text data from file
diff --git a/src/rlgl.h b/src/rlgl.h
index 39941b33c..0765a8a7a 100644
--- a/src/rlgl.h
+++ b/src/rlgl.h
@@ -196,40 +196,34 @@ typedef enum { OPENGL_11 = 1, OPENGL_33, OPENGL_ES_20 } GlVersion;
     
     // Material type
     typedef struct Material {
-        Shader shader;
+        Shader shader;              // Standard shader (supports 3 map types: diffuse, normal, specular)
 
-        Texture2D texDiffuse;      // Diffuse texture
-        Texture2D texNormal;       // Normal texture
-        Texture2D texSpecular;     // Specular texture
+        Texture2D texDiffuse;       // Diffuse texture
+        Texture2D texNormal;        // Normal texture
+        Texture2D texSpecular;      // Specular texture
         
-        Color colDiffuse;
-        Color colAmbient;
-        Color colSpecular;
+        Color colDiffuse;           // Diffuse color
+        Color colAmbient;           // Ambient color
+        Color colSpecular;          // Specular color
         
-        float glossiness;
-        float normalDepth;
+        float glossiness;           // Glossiness level (Ranges from 0 to 1000)
+        float normalDepth;          // Normal map depth
     } Material;
     
     // Light type
-    // TODO: Review contained data to support different light types and features
     typedef struct LightData {
         int id;
         int type;           // LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT
         bool enabled;
         
         Vector3 position;
-        Vector3 direction;  // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction)
-        float attenuation;  // Lost of light intensity with distance (use radius?)
+        Vector3 target;     // Used on LIGHT_DIRECTIONAL and LIGHT_SPOT (cone direction target)
+        float attenuation;  // Lost of light intensity with distance (world distance)
         
-        Color diffuse;      // Use Vector3 diffuse (including intensities)?
+        Color diffuse;      // Use Vector3 diffuse
         float intensity;
         
-        Color specular;
-        //float specFactor;   // Specular intensity ?
-
-        //Color ambient;    // Required?
-        
-        float coneAngle;         // SpotLight
+        float coneAngle;    // Spot light max angle
     } LightData, *Light;
 	
     // Color blending modes (pre-defined)

From dcd6942ed1ab703625f5c7072cbcfd823c681db7 Mon Sep 17 00:00:00 2001
From: victorfisac <victorfisac@gmail.com>
Date: Sat, 21 May 2016 18:22:15 +0200
Subject: [PATCH 33/33] Fix small bug and spacing

---
 examples/resources/shaders/standard.fs | 14 ++++----
 src/models.c                           | 46 +++++++++++++-------------
 src/rlgl.c                             | 10 +++---
 3 files changed, 35 insertions(+), 35 deletions(-)

diff --git a/examples/resources/shaders/standard.fs b/examples/resources/shaders/standard.fs
index 30c841d2d..3c3bef4b4 100644
--- a/examples/resources/shaders/standard.fs
+++ b/examples/resources/shaders/standard.fs
@@ -43,7 +43,7 @@ vec3 CalcPointLight(Light l, vec3 n, vec3 v)
     
     // Specular shading
     float spec = 0.0;
-    if(diff > 0.0)
+    if (diff > 0.0)
     {
         vec3 h = normalize(-l.direction + v);
         spec = pow(dot(n, h), 3 + glossiness);
@@ -61,7 +61,7 @@ vec3 CalcDirectionalLight(Light l, vec3 n, vec3 v)
     
     // Specular shading
     float spec = 0.0;
-    if(diff > 0.0)
+    if (diff > 0.0)
     {
         vec3 h = normalize(lightDir + v);
         spec = pow(dot(n, h), 3 + glossiness);
@@ -84,7 +84,7 @@ vec3 CalcSpotLight(Light l, vec3 n, vec3 v)
     float attenuation = clamp(dot(n, lightToSurface), 0.0, 1.0);
     attenuation = dot(lightToSurface, -lightDir);
     float lightToSurfaceAngle = degrees(acos(attenuation));
-    if(lightToSurfaceAngle > l.coneAngle) attenuation = 0.0;
+    if (lightToSurfaceAngle > l.coneAngle) attenuation = 0.0;
     float falloff = (l.coneAngle - lightToSurfaceAngle)/l.coneAngle;
     
     // Combine diffuse and attenuation
@@ -92,7 +92,7 @@ vec3 CalcSpotLight(Light l, vec3 n, vec3 v)
     
     // Specular shading
     float spec = 0.0;
-    if(diffAttenuation > 0.0)
+    if (diffAttenuation > 0.0)
     {
         vec3 h = normalize(lightDir + v);
         spec = pow(dot(n, h), 3 + glossiness);
@@ -115,13 +115,13 @@ void main()
     vec4 texelColor = texture(texture0, fragTexCoord);
     vec3 lighting = colAmbient.rgb;
     
-    for(int i = 0; i < lightsCount; i++)
+    for (int i = 0; i < lightsCount; i++)
     {
         // Check if light is enabled
-        if(lights[i].enabled == 1)
+        if (lights[i].enabled == 1)
         {
             // Calculate lighting based on light type
-            switch(lights[i].type)
+            switch (lights[i].type)
             {
                 case 0: lighting += CalcPointLight(lights[i], n, v); break;
                 case 1: lighting += CalcDirectionalLight(lights[i], n, v); break;
diff --git a/src/models.c b/src/models.c
index aef79626b..07dee7209 100644
--- a/src/models.c
+++ b/src/models.c
@@ -302,9 +302,9 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
         rlBegin(RL_TRIANGLES);
             rlColor4ub(color.r, color.g, color.b, color.a);
 
-            for(int i = 0; i < (rings + 2); i++)
+            for (int i = 0; i < (rings + 2); i++)
             {
-                for(int j = 0; j < slices; j++)
+                for (int j = 0; j < slices; j++)
                 {
                     rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i)) * sin(DEG2RAD*(j*360/slices)),
                                sin(DEG2RAD*(270+(180/(rings + 1))*i)),
@@ -341,9 +341,9 @@ void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Col
         rlBegin(RL_LINES);
             rlColor4ub(color.r, color.g, color.b, color.a);
 
-            for(int i = 0; i < (rings + 2); i++)
+            for (int i = 0; i < (rings + 2); i++)
             {
-                for(int j = 0; j < slices; j++)
+                for (int j = 0; j < slices; j++)
                 {
                     rlVertex3f(cos(DEG2RAD*(270+(180/(rings + 1))*i)) * sin(DEG2RAD*(j*360/slices)),
                                sin(DEG2RAD*(270+(180/(rings + 1))*i)),
@@ -386,7 +386,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
             if (radiusTop > 0)
             {
                 // Draw Body -------------------------------------------------------------------------------------
-                for(int i = 0; i < 360; i += 360/sides)
+                for (int i = 0; i < 360; i += 360/sides)
                 {
                     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
@@ -398,7 +398,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
                 }
 
                 // Draw Cap --------------------------------------------------------------------------------------
-                for(int i = 0; i < 360; i += 360/sides)
+                for (int i = 0; i < 360; i += 360/sides)
                 {
                     rlVertex3f(0, height, 0);
                     rlVertex3f(sin(DEG2RAD*i) * radiusTop, height, cos(DEG2RAD*i) * radiusTop);
@@ -408,7 +408,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
             else
             {
                 // Draw Cone -------------------------------------------------------------------------------------
-                for(int i = 0; i < 360; i += 360/sides)
+                for (int i = 0; i < 360; i += 360/sides)
                 {
                     rlVertex3f(0, height, 0);
                     rlVertex3f(sin(DEG2RAD*i) * radiusBottom, 0, cos(DEG2RAD*i) * radiusBottom);
@@ -417,7 +417,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
             }
 
             // Draw Base -----------------------------------------------------------------------------------------
-            for(int i = 0; i < 360; i += 360/sides)
+            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);
@@ -431,7 +431,7 @@ void DrawCylinder(Vector3 position, float radiusTop, float radiusBottom, float h
 // NOTE: It could be also used for pyramid and cone
 void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, float height, int sides, Color color)
 {
-    if(sides < 3) sides = 3;
+    if (sides < 3) sides = 3;
 
     rlPushMatrix();
         rlTranslatef(position.x, position.y, position.z);
@@ -439,7 +439,7 @@ void DrawCylinderWires(Vector3 position, float radiusTop, float radiusBottom, fl
         rlBegin(RL_LINES);
             rlColor4ub(color.r, color.g, color.b, color.a);
 
-            for(int i = 0; i < 360; i += 360/sides)
+            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);
@@ -500,7 +500,7 @@ void DrawGrid(int slices, float spacing)
     int halfSlices = slices / 2;
 
     rlBegin(RL_LINES);
-        for(int i = -halfSlices; i <= halfSlices; i++)
+        for (int i = -halfSlices; i <= halfSlices; i++)
         {
             if (i == 0)
             {
@@ -798,9 +798,9 @@ static Mesh GenMeshHeightmap(Image heightmap, Vector3 size)
 
     Vector3 scaleFactor = { size.x/mapX, size.y/255.0f, size.z/mapZ };
 
-    for(int z = 0; z < mapZ-1; z++)
+    for (int z = 0; z < mapZ-1; z++)
     {
-        for(int x = 0; x < mapX-1; x++)
+        for (int x = 0; x < mapX-1; x++)
         {
             // Fill vertices array with data
             //----------------------------------------------------------
@@ -1417,7 +1417,7 @@ bool CheckCollisionRaySphere(Ray ray, Vector3 spherePosition, float sphereRadius
     float vector = VectorDotProduct(raySpherePos, ray.direction);
     float d = sphereRadius*sphereRadius - (distance*distance - vector*vector);
     
-    if(d >= 0.0f) collision = true;
+    if (d >= 0.0f) collision = true;
     
     return collision;
 }
@@ -1432,14 +1432,14 @@ bool CheckCollisionRaySphereEx(Ray ray, Vector3 spherePosition, float sphereRadi
     float vector = VectorDotProduct(raySpherePos, ray.direction);
     float d = sphereRadius*sphereRadius - (distance*distance - vector*vector);
     
-    if(d >= 0.0f) collision = true;
+    if (d >= 0.0f) collision = true;
     
     // Calculate collision point
     Vector3 offset = ray.direction;
     float collisionDistance = 0;
     
     // Check if ray origin is inside the sphere to calculate the correct collision point
-    if(distance < sphereRadius) collisionDistance = vector + sqrt(d);
+    if (distance < sphereRadius) collisionDistance = vector + sqrt(d);
     else collisionDistance = vector - sqrt(d);
     
     VectorScale(&offset, collisionDistance);
@@ -1777,11 +1777,11 @@ static Mesh LoadOBJ(const char *fileName)
     // First reading pass: Get numVertex, numNormals, numTexCoords, numTriangles
     // NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition)
     // NOTE: faces MUST be defined as TRIANGLES (3 vertex per face)
-    while(!feof(objFile))
+    while (!feof(objFile))
     {
         fscanf(objFile, "%c", &dataType);
 
-        switch(dataType)
+        switch (dataType)
         {
             case '#':   // Comments
             case 'o':   // Object name (One OBJ file can contain multible named meshes)
@@ -1842,11 +1842,11 @@ static Mesh LoadOBJ(const char *fileName)
     // Second reading pass: Get vertex data to fill intermediate arrays
     // NOTE: This second pass is required in case of multiple meshes defined in same OBJ
     // TODO: Consider that different meshes can have different vertex data available (position, texcoords, normals)
-    while(!feof(objFile))
+    while (!feof(objFile))
     {
         fscanf(objFile, "%c", &dataType);
 
-        switch(dataType)
+        switch (dataType)
         {
             case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'f': fgets(comments, 200, objFile); break;
             case 'v':
@@ -1903,11 +1903,11 @@ static Mesh LoadOBJ(const char *fileName)
     if (numNormals == 0) TraceLog(INFO, "[%s] No normals data on OBJ, normals will be generated from faces data", fileName);
 
     // Third reading pass: Get faces (triangles) data and fill VertexArray
-    while(!feof(objFile))
+    while (!feof(objFile))
     {
         fscanf(objFile, "%c", &dataType);
 
-        switch(dataType)
+        switch (dataType)
         {
             case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'v': fgets(comments, 200, objFile); break;
             case 'f':
@@ -2023,7 +2023,7 @@ static Material LoadMTL(const char *fileName)
         return material;
     }
 
-    while(!feof(mtlFile))
+    while (!feof(mtlFile))
     {
         fgets(buffer, MAX_BUFFER_SIZE, mtlFile);
         
diff --git a/src/rlgl.c b/src/rlgl.c
index 55677f3e8..85c0cae29 100644
--- a/src/rlgl.c
+++ b/src/rlgl.c
@@ -1397,7 +1397,7 @@ RenderTexture2D rlglLoadRenderTexture(int width, int height)
     {
         TraceLog(WARNING, "Framebuffer object could not be created...");
         
-        switch(status)
+        switch (status)
         {
             case GL_FRAMEBUFFER_UNSUPPORTED: TraceLog(WARNING, "Framebuffer is unsupported"); break;
             case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: TraceLog(WARNING, "Framebuffer incomplete attachment"); break;
@@ -1768,7 +1768,7 @@ void rlglDrawMesh(Mesh mesh, Material material, Matrix transform)
 
     // Check if using standard shader to get location points
     // NOTE: standard shader specific locations are got at render time to keep Shader struct as simple as possible (with just default shader locations)
-    if(material.shader.id == standardShader.id)
+    if (material.shader.id == standardShader.id)
     {
         // Send model transformations matrix to shader
         glUniformMatrix4fv(glGetUniformLocation(material.shader.id, "modelMatrix"), 1, false, MatrixToFloat(transform));
@@ -2285,7 +2285,7 @@ void DrawLights(void)
                 Draw3DLine(lights[i]->position, lights[i]->target, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
                 DrawSphereWires(lights[i]->position, 0.3f*lights[i]->intensity, 4, 8, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
                 DrawCubeWires(lights[i]->target, 0.3f, 0.3f, 0.3f, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
-            }
+            } break;
             case LIGHT_SPOT:
             {                
                 Draw3DLine(lights[i]->position, lights[i]->target, (lights[i]->enabled ? lights[i]->diffuse : BLACK));
@@ -3081,7 +3081,7 @@ static void SetShaderLights(Shader shader)
         locPoint = glGetUniformLocation(shader.id, locName);
         glUniform1f(locPoint, lights[i]->intensity);
         
-        switch(lights[i]->type)
+        switch (lights[i]->type)
         {
             case LIGHT_POINT:
             {
@@ -3295,7 +3295,7 @@ static void TraceLog(int msgType, const char *text, ...)
     va_list args;
     va_start(args, text);
 
-    switch(msgType)
+    switch (msgType)
     {
         case INFO: fprintf(stdout, "INFO: "); break;
         case ERROR: fprintf(stdout, "ERROR: "); break;