Browse Source

raylib 1.1

View CHANGELOG for a detailed list of changes
raysan5 11 years ago
parent
commit
f06a15ac8b
17 changed files with 1541 additions and 1082 deletions
  1. 34 1
      CHANGELOG
  2. 2 2
      HELPME.md
  3. 52 19
      README.md
  4. 6 6
      ROADMAP.md
  5. 346 284
      src/audio.c
  6. 7 8
      src/core.c
  7. 343 304
      src/models.c
  8. 56 48
      src/raylib.h
  9. 20 2
      src/raymath.c
  10. 1 0
      src/raymath.h
  11. 359 114
      src/rlgl.c
  12. 26 31
      src/rlgl.h
  13. 18 21
      src/shapes.c
  14. 17 26
      src/text.c
  15. 204 137
      src/textures.c
  16. 44 72
      src/utils.c
  17. 6 7
      src/utils.h

+ 34 - 1
CHANGELOG

@@ -1,11 +1,44 @@
 changelog
 changelog
 ---------
 ---------
 
 
-Current Release:    raylib 1.0.6 (March 2014)
+Current Release:    raylib 1.1.0 (April 2014)
 
 
 NOTE: Only versions marked as 'Release' are available on release folder, updates are only available as source.
 NOTE: Only versions marked as 'Release' are available on release folder, updates are only available as source.
 NOTE: Current Release includes all previous updates.
 NOTE: Current Release includes all previous updates.
 
 
+-----------------------------------------------
+Release:     raylib 1.1.0 (19 April 2014)
+-----------------------------------------------
+NOTE: 
+  This version supposed a complete internal redesign of the library to support OpenGL 3.3+ and OpenGL ES 2.0.
+  New module [rlgl] has been added to 'translate' immediate mode style functions (i.e. rlVertex3f()) to GL 1.1, 3.3+ or ES2.
+  Another new module [raymath] has also been added with lot of useful 3D math vector-matrix-quaternion functions.
+
+[rlgl] New module, abstracts OpenGL rendering (multiple versions support)
+[raymath] New module, useful 3D math vector-matrix-quaternion functions
+[core] Adapt all OpenGL code (initialization, drawing) to use [rlgl]
+[shapes] Rewrite all shapes drawing functions to use [rlgl]
+[textures] Adapt texture GPU loading to use [rlgl]
+[textures] Added support for DDS images (compressed and uncompressed)
+[textures] CreateTexture() - Redesigned to add mipmap automatic generation
+[textures] DrawTexturePro() - Redesigned and corrected bugs
+[models] Rewrite all 3d-shapes drawing functions to use [rlgl]
+[models] Adapt model loading and drawing to use [rlgl]
+[models] Model struct updated to include texture id
+[models] SetModelTexture() - Added, link a texture to a model
+[models] DrawModelEx() - Redesigned with extended parameters
+[audio] Added music streaming support (OGG files)
+[audio] Added support for OGG files as Sound
+[audio] PlayMusicStream() - Added, open a new music stream and play it
+[audio] StopMusicStream() - Added, stop music stream playing and close stream
+[audio] PauseMusicStream() - Added, pause music stream playing
+[audio] MusicIsPlaying() - Added, to check if music is playing
+[audio] SetMusicVolume() - Added, set volume for music
+[audio] GetMusicTimeLength() - Added, get current music time length (in seconds)
+[audio] GetMusicTimePlayed() - Added, get current music time played (in seconds)
+[utils] Added log tracing functionality - TraceLog(), TraceLogOpen(), TraceLogClose()
+[*] Log tracing messages all around the code
+
 -----------------------------------------------
 -----------------------------------------------
 Release:     raylib 1.0.6 (16 March 2014)
 Release:     raylib 1.0.6 (16 March 2014)
 -----------------------------------------------
 -----------------------------------------------

+ 2 - 2
HELPME.md

@@ -10,7 +10,7 @@ The following help is highly appreciated:
 	- Translators / Localizators - Can you translate raylib to another language?
 	- Translators / Localizators - Can you translate raylib to another language?
 	- Documentation / Tutorials / Example writters - Can you write some tutorial / example?
 	- Documentation / Tutorials / Example writters - Can you write some tutorial / example?
 	- Web Development - Can you help with the web? Can you setup a forum?
 	- Web Development - Can you help with the web? Can you setup a forum?
-	- Porting to Linux and OSX - Can you compile and test raylib on another OS?
+	- Porting to Linux, OSX... - Can you compile and test raylib on another OS?
 	- Testers of current features and multiple systems - Can you find some bug on raylib?
 	- Testers of current features and multiple systems - Can you find some bug on raylib?
 
 
 If you can not help on any of the above points but you still want to contribute in some way... please, consider helping 
 If you can not help on any of the above points but you still want to contribute in some way... please, consider helping 
@@ -34,4 +34,4 @@ contact
    * Facebook: [http://www.facebook.com/raylibgames](http://www.facebook.com/raylibgames)
    * Facebook: [http://www.facebook.com/raylibgames](http://www.facebook.com/raylibgames)
 
 
    
    
-[raysan5]: mailto:raysan@raysanweb.com "Ramon Santamaria - Ray San"
+[raysan5]: mailto:raysan5@gmail.com "Ramon Santamaria - Ray San"

+ 52 - 19
README.md

@@ -23,29 +23,51 @@ a simple PONG and some of them even a BREAKOUT!
 
 
 But WinBGI was not the clearer and most organized lib. There were a lot of things I found useless and 
 But WinBGI was not the clearer and most organized lib. There were a lot of things I found useless and 
 confusing and some function names were not clear enough for most of the students; not to mention points 
 confusing and some function names were not clear enough for most of the students; not to mention points 
-like no transparencies support or no hardware acceleration. 
+like no transparencies support or no hardware acceleration.
 
 
 So, I decided to create my own lib, hardware accelerated, clear function names, quite organized, well structured, 
 So, I decided to create my own lib, hardware accelerated, clear function names, quite organized, well structured, 
 plain C coding and, the most important, primarily intended to LEARN videogames programming.
 plain C coding and, the most important, primarily intended to LEARN videogames programming.
 
 
-I've coded quite a lot in C# and XNA and I really love it (in fact, my students learn C# with XNA after C), 
+I've coded quite a lot in C# and XNA and I really love it (in fact, my students learn C# after C), 
 so, I decided to use C# language notation and XNA naming conventions. That way, students can jump from 
 so, I decided to use C# language notation and XNA naming conventions. That way, students can jump from 
-raylib to XNA (or MonoGame) extremely easily.
+raylib to XNA, MonoGame or similar libs extremely easily.
 
 
-raylib started as a weekend project and after three months of hard work, here it is the first version. 
+raylib started as a weekend project and after three months of hard work, first version was published.
+
+Enjoy it.
+
+notes on raylib 1.1
+-------------------
+
+On April 2014, after 6 month of first raylib release, raybil 1.1 has been released. This new version presents a
+complete internal redesign of the library to support OpenGL 1.1, OpenGL 3.3+ and OpenGL ES 2.0.
+
+A new module named [rlgl] (https://github.com/raysan5/raylib/blob/master/src/rlgl.h) has been added to the library. This new module translate raylib-OpenGL-style 
+immediate mode functions (i.e. rlVertex3f(), rlBegin(), ...) to different versions of OpenGL (1.1, 3.3+, ES2), selectable by one define.
+
+[rlgl] (https://github.com/raysan5/raylib/blob/master/src/rlgl.h) also comes with a second new module named [raymath] (https://github.com/raysan5/raylib/blob/master/src/raymath.h), which includes
+a bunch of useful functions for 3d-math with vectors, matrices and quaternions.
+
+Some other big changes of this new version have been the support for OGG files loading and stream playing, and the
+support of DDS texture files (compressed and uncompressed) along with mipmaps support.
+
+Lots of code changes and lot of testing have concluded in this amazing new raylib 1.1.
 
 
 Enjoy it.
 Enjoy it.
 
 
 features
 features
 --------
 --------
-
-   * Written in plain C code (C99)
-   * Uses C# PascalCase/camelCase notation
-   * Hardware accelerated using OpenGL 1.1
-   * Transparencies support (RGBA Colors)
-   * Custom color palette for better use on white background
-   * Basic 3D Support (camera, basic models, OBJ models, etc)
-   * Powerful Text module with SpriteFonts support
+ 
+   *  Written in plain C code (C99)
+   *  Uses C# PascalCase/camelCase notation
+   *  Hardware accelerated with OpenGL (1.1, 3.3+ or ES2)
+   *  Unique OpenGL abstraction layer [rlgl]
+   *  Powerful fonts module with SpriteFonts support
+   *  Multiple textures support, including DDS and mipmaps generation
+   *  Basic 3d support for Shapes, Models, Heightmaps and Billboards
+   *  Powerful math module for Vector and Matrix operations [raymath]
+   *  Audio loading and playing with streaming support
+   *  Custom color palette for fancy visuals on raywhite background
 
 
 raylib uses on its core module the outstanding [GLFW3] (http://www.glfw.org/) library. The best option by far I found for 
 raylib uses on its core module the outstanding [GLFW3] (http://www.glfw.org/) library. The best option by far I found for 
 window/context and input management (clean, focused, great license, well documented, modern, ...). 
 window/context and input management (clean, focused, great license, well documented, modern, ...). 
@@ -75,19 +97,30 @@ raylib could be build with the following command lines (Using GCC compiler):
 	gcc -c core.c -std=c99 -Wall
 	gcc -c core.c -std=c99 -Wall
 	gcc -c shapes.c -std=c99 -Wall
 	gcc -c shapes.c -std=c99 -Wall
 	gcc -c textures.c -std=c99 -Wall
 	gcc -c textures.c -std=c99 -Wall
-	gcc -c stb_image.c -std=c99 -Wall
 	gcc -c text.c -std=c99 -Wall
 	gcc -c text.c -std=c99 -Wall
 	gcc -c models.c -std=c99 -Wall
 	gcc -c models.c -std=c99 -Wall
-	gcc -c vector3.c -std=c99 -Wall
+	gcc -c raymath.c -std=c99 -Wall
+    gcc -c rlgl.c -std=c99 -Wall
 	gcc -c audio.c -std=c99 -Wall
 	gcc -c audio.c -std=c99 -Wall
     gcc -c utils.c -std=c99 -Wall
     gcc -c utils.c -std=c99 -Wall
-	ar rcs raylib.a core.o shapes.o textures.o stb_image.o text.o models.o vector3.o utils.o audio.o
+    gcc -c stb_image.c -std=c99 -Wall
+    gcc -c stb_vorbis.c -std=c99 -Wall
+    
+	ar rcs libraylib.a core.o shapes.o textures.o stb_image.o text.o models.o raymath.o rlgl.o utils.o stb_vorbis.o audio.o
+
+To compile examples, make sure raylib.h is placed in the include path and the following libraries are placed in the libraries path:
 
 
-To compile examples, make sure raylib.h is placed in include path and libraries raylib (libraylib.a) and glfw3 (libglfw3.a) 
-are placed in the libraries path. It's also recommended to link with file icon.o for fancy raylib icon usage.
+    libraylib.a   - raylib
+    libglfw3.a    - GLFW3 (static version)
+    libglew32.a   - GLEW, OpenGL extension loading, only required if using OpenGL 3.3+ or ES2
+    libopenal32.a - OpenAL, audio device management
+    
+It's also recommended to link with file icon.o for fancy raylib icon usage. Linking command:
 
 
 	cd raylib/examples
 	cd raylib/examples
-	gcc -o test_code.exe test_code.c icon.o -lraylib -lglfw3 -lopengl32 -lgdi32 -std=c99 -Wl,--subsystem,windows
+	gcc -o test_code.exe test_code.c icon.o -lraylib -lglfw3 -lglew32 -lopenal32 -lopengl32 -lgdi32 -std=c99 -Wl,--subsystem,windows
+    
+If you have any doubt, [let me know][raysan5].
 
 
 contact
 contact
 -------
 -------
@@ -109,4 +142,4 @@ The following people have contributed in some way to make raylib project a reali
  - [Elendow](http://www.elendow.com)
  - [Elendow](http://www.elendow.com)
 
 
 	
 	
-[raysan5]: mailto:raysan@raysanweb.com "Ramon Santamaria - Ray San"
+[raysan5]: mailto:raysan5@gmail.com "Ramon Santamaria - Ray San"

+ 6 - 6
ROADMAP.md

@@ -1,7 +1,7 @@
 roadmap
 roadmap
 -------
 -------
 
 
-First version of raylib is quite complete and functional but there is still a lot of things I would like to improve.
+Current version of raylib is quite complete and functional but there is still a lot of things I would like to improve.
 Here it is a list of features I would like to add and functions to improve.
 Here it is a list of features I would like to add and functions to improve.
 
 
 Around the source code there are some TODO points with pending revisions/bugs and here it is a list of features I would like to add.
 Around the source code there are some TODO points with pending revisions/bugs and here it is a list of features I would like to add.
@@ -10,13 +10,13 @@ raylib v1.x
 
 
    - [DONE] Review Billboard Drawing functions
    - [DONE] Review Billboard Drawing functions
    - [DONE] Review Heightmap Loading and Drawing functions - Load Heightmap directly as a Model
    - [DONE] Review Heightmap Loading and Drawing functions - Load Heightmap directly as a Model
-   - Lighting support (only 3d mode) - CreateLight()
+   - Lighting support (only 3d mode)
    - [DONE] Simple Collision Detection functions
    - [DONE] Simple Collision Detection functions
    - Default scene Camera controls (zoom, pan, rotate)   
    - Default scene Camera controls (zoom, pan, rotate)   
-   - Basic Procedural Texture / Image generation (Gradient, Checked, Spot, Noise, Cellular)
-   - Software mipmapping generation and POT conversion (custom implementation)
-   - Comments / Functions translation (?)
+   - Basic Procedural Image Generation (Gradient, Checked, Spot, Noise, Cellular)
+   - [DONE] Software mipmapping generation and POT conversion (custom implementation)
+   - TTF fonts support
    
    
 Any feature missing? Do you have a request? [Let me know!][raysan5]
 Any feature missing? Do you have a request? [Let me know!][raysan5]
 
 
-[raysan5]: mailto:raysan@raysanweb.com "Ramon Santamaria - Ray San"
+[raysan5]: mailto:raysan5@gmail.com "Ramon Santamaria - Ray San"

+ 346 - 284
src/audio.c

@@ -6,7 +6,7 @@
 *    
 *    
 *   Uses external lib:    
 *   Uses external lib:    
 *       OpenAL - Audio device management lib
 *       OpenAL - Audio device management lib
-*       TODO: stb_vorbis - Ogg audio files loading
+*       stb_vorbis - Ogg audio files loading
 *       
 *       
 *   Copyright (c) 2013 Ramon Santamaria (Ray San - [email protected])
 *   Copyright (c) 2013 Ramon Santamaria (Ray San - [email protected])
 *    
 *    
@@ -32,50 +32,45 @@
 #include <AL/al.h>           // OpenAL basic header
 #include <AL/al.h>           // OpenAL basic header
 #include <AL/alc.h>          // OpenAL context header (like OpenGL, OpenAL requires a context to work)
 #include <AL/alc.h>          // OpenAL context header (like OpenGL, OpenAL requires a context to work)
 
 
-#include <stdlib.h>          // To use exit() function
+#include <stdlib.h>          // Declares malloc() and free() for memory management
+#include <string.h>          // Required for strcmp()
 #include <stdio.h>           // Used for .WAV loading
 #include <stdio.h>           // Used for .WAV loading
 
 
 #include "utils.h"           // rRES data decompression utility function
 #include "utils.h"           // rRES data decompression utility function
 
 
-//#include "stb_vorbis.h"      // OGG loading functions
+#include "stb_vorbis.h"      // OGG loading functions
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Defines and Macros
 // Defines and Macros
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
-// Nop...
+#define MUSIC_STREAM_BUFFERS        2
+#define MUSIC_BUFFER_SIZE      4096*8   //4096*32
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
-// Sound source type (all file loaded in memory)
-/*
-struct Sound {
-    unsigned int source;
-    unsigned int buffer;
-};
-
-// Music type (file streamming from memory)
-// NOTE: Anything longer than ~10 seconds should be Music...
-struct Music {
-    stb_vorbis* stream;
-	stb_vorbis_info info;
-    
-    ALuint id; 
-	ALuint buffers[2];
+
+// Music type (file streaming from memory)
+// NOTE: Anything longer than ~10 seconds should be streamed...
+typedef struct Music {
+    stb_vorbis *stream;
+    
+	ALuint buffers[MUSIC_STREAM_BUFFERS];
 	ALuint source;
 	ALuint source;
 	ALenum format;
 	ALenum format;
  
  
-	int bufferSize;
+    int channels;
+    int sampleRate;
 	int totalSamplesLeft;
 	int totalSamplesLeft;
 	bool loop;
 	bool loop;
-};
-*/
+    
+} Music;
 
 
 // Wave file data
 // Wave file data
 typedef struct Wave {
 typedef struct Wave {
-    unsigned char *data;      // Buffer data pointer
+    void *data;                 // Buffer data pointer
+    unsigned int dataSize;      // Data size in bytes
     unsigned int sampleRate;
     unsigned int sampleRate;
-    unsigned int dataSize;
     short bitsPerSample;
     short bitsPerSample;
     short channels;  
     short channels;  
 } Wave;
 } Wave;
@@ -83,22 +78,23 @@ typedef struct Wave {
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 // Global Variables Definition
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
-static bool musicIsPlaying;
-static Music *currentMusic;
+bool musicEnabled = false;
+static Music currentMusic;      // Current music loaded
+                                // NOTE: Only one music file playing at a time
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
 // Module specific Functions Declaration
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
-static Wave LoadWAV(char *fileName);
-static void UnloadWAV(Wave wave);
-//static Ogg LoadOGG(char *fileName);
-static bool MusicStream(Music music, ALuint buffer);
+static Wave LoadWAV(const char *fileName);
+static Wave LoadOGG(char *fileName);
+static void UnloadWave(Wave wave);
 
 
-extern bool MusicStreamUpdate();
-extern void PlayCurrentMusic();
+static bool BufferMusicStream(ALuint buffer);   // Fill music buffers with data
+static void EmptyMusicStream();                 // Empty music buffers
+extern void UpdateMusicStream();                // Updates buffers (refill) for music streaming
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
-// Module Functions Definition - Window and OpenGL Context Functions
+// Module Functions Definition - Audio Device initialization and Closing
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 
 
 // Initialize audio device and context
 // Initialize audio device and context
@@ -126,13 +122,13 @@ void InitAudioDevice()
     alListener3f(AL_POSITION, 0, 0, 0);
     alListener3f(AL_POSITION, 0, 0, 0);
     alListener3f(AL_VELOCITY, 0, 0, 0);
     alListener3f(AL_VELOCITY, 0, 0, 0);
     alListener3f(AL_ORIENTATION, 0, 0, -1);
     alListener3f(AL_ORIENTATION, 0, 0, -1);
-    
-    musicIsPlaying = false;
 }
 }
 
 
 // Close the audio device for the current context, and destroys the context
 // Close the audio device for the current context, and destroys the context
 void CloseAudioDevice()
 void CloseAudioDevice()
 {
 {
+    StopMusicStream();      // Stop music streaming and close current stream
+
     ALCdevice *device;
     ALCdevice *device;
     ALCcontext *context = alcGetCurrentContext();
     ALCcontext *context = alcGetCurrentContext();
     
     
@@ -145,60 +141,70 @@ void CloseAudioDevice()
     alcCloseDevice(device);
     alcCloseDevice(device);
 }
 }
 
 
+//----------------------------------------------------------------------------------
+// Module Functions Definition - Sounds loading and playing (.WAV)
+//----------------------------------------------------------------------------------
+
 // Load sound to memory
 // Load sound to memory
 Sound LoadSound(char *fileName)
 Sound LoadSound(char *fileName)
 {
 {
     Sound sound;
     Sound sound;
+    Wave wave;
     
     
     // NOTE: The entire file is loaded to memory to play it all at once (no-streaming)
     // NOTE: The entire file is loaded to memory to play it all at once (no-streaming)
     
     
-    // WAV file loading
-    // NOTE: Buffer space is allocated inside LoadWAV, Wave must be freed
-    Wave wave = LoadWAV(fileName);
-    
-    ALenum format = 0;
-    // The OpenAL format is worked out by looking at the number of channels and the bits per sample
-    if (wave.channels == 1) 
-    {
-        if (wave.bitsPerSample == 8 ) format = AL_FORMAT_MONO8;
-        else if (wave.bitsPerSample == 16) format = AL_FORMAT_MONO16;
-    } 
-    else if (wave.channels == 2) 
-    {
-        if (wave.bitsPerSample == 8 ) format = AL_FORMAT_STEREO8;
-        else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16;
-    }
-    
+    // Audio file loading
+    // NOTE: Buffer space is allocated inside function, Wave must be freed
     
     
-    // Create an audio source
-    ALuint source;
-    alGenSources(1, &source);            // Generate pointer to audio source
-
-    alSourcef(source, AL_PITCH, 1);    
-    alSourcef(source, AL_GAIN, 1);
-    alSource3f(source, AL_POSITION, 0, 0, 0);
-    alSource3f(source, AL_VELOCITY, 0, 0, 0);
-    alSourcei(source, AL_LOOPING, AL_FALSE);
+    if (strcmp(GetExtension(fileName),"wav") == 0) wave = LoadWAV(fileName);
+    else if (strcmp(GetExtension(fileName),"ogg") == 0) wave = LoadOGG(fileName);
+    else TraceLog(WARNING, "[%s] Sound extension not recognized, it can't be loaded", fileName);
     
     
-    // Convert loaded data to OpenAL buffer
-    //----------------------------------------
-    ALuint buffer;
-    alGenBuffers(1, &buffer);            // Generate pointer to buffer
+    if (wave.data != NULL)
+    {
+        ALenum format = 0;
+        // The OpenAL format is worked out by looking at the number of channels and the bits per sample
+        if (wave.channels == 1) 
+        {
+            if (wave.bitsPerSample == 8 ) format = AL_FORMAT_MONO8;
+            else if (wave.bitsPerSample == 16) format = AL_FORMAT_MONO16;
+        } 
+        else if (wave.channels == 2) 
+        {
+            if (wave.bitsPerSample == 8 ) format = AL_FORMAT_STEREO8;
+            else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16;
+        }
+        
+        // Create an audio source
+        ALuint source;
+        alGenSources(1, &source);            // Generate pointer to audio source
+
+        alSourcef(source, AL_PITCH, 1);    
+        alSourcef(source, AL_GAIN, 1);
+        alSource3f(source, AL_POSITION, 0, 0, 0);
+        alSource3f(source, AL_VELOCITY, 0, 0, 0);
+        alSourcei(source, AL_LOOPING, AL_FALSE);
+        
+        // Convert loaded data to OpenAL buffer
+        //----------------------------------------
+        ALuint buffer;
+        alGenBuffers(1, &buffer);            // Generate pointer to buffer
 
 
-    // Upload sound data to buffer
-    alBufferData(buffer, format, (void*)wave.data, wave.dataSize, wave.sampleRate);
+        // Upload sound data to buffer
+        alBufferData(buffer, format, wave.data, wave.dataSize, wave.sampleRate);
 
 
-    // Attach sound buffer to source
-    alSourcei(source, AL_BUFFER, buffer);
-    
-    // Unallocate WAV data
-    UnloadWAV(wave);
-    
-    TraceLog(INFO, "[%s] Sound file loaded successfully", fileName);  
-    TraceLog(INFO, "[%s] Sample rate: %i - Channels: %i", fileName, wave.sampleRate, wave.channels);
-    
-    sound.source = source;
-    sound.buffer = buffer;
+        // Attach sound buffer to source
+        alSourcei(source, AL_BUFFER, buffer);
+        
+        // Unallocate WAV data
+        UnloadWave(wave);
+        
+        TraceLog(INFO, "[%s] Sound file loaded successfully", fileName);  
+        TraceLog(INFO, "[%s] Sample rate: %i - Channels: %i", fileName, wave.sampleRate, wave.channels);
+        
+        sound.source = source;
+        sound.buffer = buffer;
+    }
     
     
     return sound;
     return sound;
 }
 }
@@ -314,7 +320,7 @@ Sound LoadSoundFromRES(const char *rresName, int resId)
                         alSourcei(source, AL_BUFFER, buffer);
                         alSourcei(source, AL_BUFFER, buffer);
                         
                         
                         // Unallocate WAV data
                         // Unallocate WAV data
-                        UnloadWAV(wave);
+                        UnloadWave(wave);
 
 
                         TraceLog(INFO, "[%s] Sound loaded successfully from resource, sample rate: %i", rresName, (int)sampleRate);
                         TraceLog(INFO, "[%s] Sound loaded successfully from resource, sample rate: %i", rresName, (int)sampleRate);
                         
                         
@@ -381,22 +387,6 @@ void PlaySound(Sound sound)
     //alGetSourcef(sound.source, AL_SEC_OFFSET, &result);   // AL_SAMPLE_OFFSET
     //alGetSourcef(sound.source, AL_SEC_OFFSET, &result);   // AL_SAMPLE_OFFSET
 }
 }
 
 
-// Play a sound with extended options
-// TODO: This function should be reviewed...
-void PlaySoundEx(Sound sound, float timePosition, bool loop)
-{
-    // TODO: Review
-    
-    // Change the current position (e.g. skip some part of the sound)
-    // NOTE: Only work when the entire file is in a single buffer
-    //alSourcei(sound.source, AL_BYTE_OFFSET, int(position * sampleRate));
-
-    alSourcePlay(sound.source);        // Play the sound
-    
-    if (loop) alSourcei(sound.source, AL_LOOPING, AL_TRUE);
-    else alSourcei(sound.source, AL_LOOPING, AL_FALSE);
-}
-
 // Pause a sound
 // Pause a sound
 void PauseSound(Sound sound)
 void PauseSound(Sound sound)
 {
 {
@@ -421,30 +411,250 @@ bool SoundIsPlaying(Sound sound)
     return playing;
     return playing;
 }
 }
 
 
+// Set volume for a sound
+void SetSoundVolume(Sound sound, float volume)
+{
+    alSourcef(sound.source, AL_GAIN, volume);
+}
+
+// Set pitch for a sound
+void SetSoundPitch(Sound sound, float pitch)
+{
+    alSourcef(sound.source, AL_PITCH, pitch);
+}
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition - Music loading and stream playing (.OGG)
+//----------------------------------------------------------------------------------
+
+// Start music playing (open stream)
+void PlayMusicStream(char *fileName)
+{
+    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);
+        
+        if (currentMusic.stream == NULL) TraceLog(WARNING, "[%s] Could not open ogg audio file", fileName);
+        else
+        {
+            // Get file info
+            stb_vorbis_info info = stb_vorbis_get_info(currentMusic.stream);
+            
+            currentMusic.channels = info.channels;
+            currentMusic.sampleRate = info.sample_rate;
+            
+            TraceLog(INFO, "[%s] Ogg sample rate: %i", fileName, info.sample_rate);
+            TraceLog(INFO, "[%s] Ogg channels: %i", fileName, info.channels);
+            TraceLog(INFO, "[%s] Temp memory required: %i", fileName, info.temp_memory_required);
+            
+            if (info.channels == 2) currentMusic.format = AL_FORMAT_STEREO16;
+            else currentMusic.format = AL_FORMAT_MONO16;
+            
+            currentMusic.loop = true;                  // We loop by default
+            musicEnabled = true;
+            
+            // Create an audio source
+            alGenSources(1, &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: MusicStreamUpdate()
+
+            currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels;
+        }
+    }
+    else TraceLog(WARNING, "[%s] Music extension not recognized, it can't be loaded", fileName);
+}
+
+// Stop music playing (close stream)
+void StopMusicStream()
+{
+    if (musicEnabled)
+    {
+        alSourceStop(currentMusic.source);
+        
+        EmptyMusicStream();     // Empty music buffers
+        
+        alDeleteSources(1, &currentMusic.source);
+        alDeleteBuffers(2, currentMusic.buffers);
+        
+        stb_vorbis_close(currentMusic.stream);
+    }
+    
+    musicEnabled = false;
+}
+
+// Pause music playing
+void PauseMusicStream()
+{
+    // TODO: Record music is paused or check if music available!
+    alSourcePause(currentMusic.source);
+}
+
 // Check if music is playing
 // Check if music is playing
-bool MusicIsPlaying(Music music)
+bool MusicIsPlaying()
 {
 {
     ALenum state;
     ALenum state;
     
     
-    alGetSourcei(music.source, AL_SOURCE_STATE, &state);
+    alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
     
     
     return (state == AL_PLAYING);
     return (state == AL_PLAYING);
 }
 }
 
 
-// Set volume for a sound
-void SetVolume(Sound sound, float volume)
+// Set volume for music
+void SetMusicVolume(float volume)
 {
 {
-    alSourcef(sound.source, AL_GAIN, volume);
+    alSourcef(currentMusic.source, AL_GAIN, volume);
 }
 }
 
 
-// Set pitch for a sound
-void SetPitch(Sound sound, float pitch)
+// Get current music time length (in seconds)
+float GetMusicTimeLength()
 {
 {
-    alSourcef(sound.source, AL_PITCH, pitch);
+    float totalSeconds = stb_vorbis_stream_length_in_seconds(currentMusic.stream);
+    
+    return totalSeconds;
+}
+
+// Get current music time played (in seconds)
+float GetMusicTimePlayed()
+{
+    int totalSamples = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels;
+    
+    int samplesPlayed = totalSamples - currentMusic.totalSamplesLeft;
+    
+    float secondsPlayed = (float)samplesPlayed / (currentMusic.sampleRate * currentMusic.channels);
+    
+    return secondsPlayed;
+}
+
+//----------------------------------------------------------------------------------
+// Module specific Functions Definition
+//----------------------------------------------------------------------------------
+
+// Fill music buffers with new data from music stream
+static bool BufferMusicStream(ALuint buffer)
+{
+	short pcm[MUSIC_BUFFER_SIZE];
+    
+	int  size = 0;              // Total size of data steamed (in bytes)
+	int  streamedBytes = 0;     // Bytes of data obtained in one samples get
+    
+    bool active = true;         // We can get more data from stream (not finished)
+    
+    if (musicEnabled)
+    {
+        while (size < MUSIC_BUFFER_SIZE)
+        {
+            streamedBytes = stb_vorbis_get_samples_short_interleaved(currentMusic.stream, currentMusic.channels, pcm + size, MUSIC_BUFFER_SIZE - size);
+            
+            if (streamedBytes > 0) size += (streamedBytes*currentMusic.channels);
+            else break;
+        }
+        
+        TraceLog(DEBUG, "Streaming music data to buffer. Bytes streamed: %i", size);
+    }
+    
+	if (size > 0)
+    {
+        alBufferData(buffer, currentMusic.format, pcm, size*sizeof(short), currentMusic.sampleRate);
+        
+        currentMusic.totalSamplesLeft -= size;
+    }
+    else
+    {
+        active = false;
+        TraceLog(WARNING, "No more data obtained from stream");
+    }
+
+	return active;
+}
+
+// Empty music buffers
+static void EmptyMusicStream()
+{
+    ALuint buffer = 0; 
+    int queued = 0;
+    
+    alGetSourcei(currentMusic.source, AL_BUFFERS_QUEUED, &queued);
+    
+    while(queued > 0)
+    {
+        alSourceUnqueueBuffers(currentMusic.source, 1, &buffer);
+        
+        queued--;
+    }
+}
+
+// Update (re-fill) music buffers if data already processed
+extern void UpdateMusicStream()
+{
+    ALuint buffer = 0;
+    ALint processed = 0;
+    bool active = true;
+    
+    if (musicEnabled)
+    {
+        // Get the number of already processed buffers (if any)
+        alGetSourcei(currentMusic.source, AL_BUFFERS_PROCESSED, &processed);
+        
+        while (processed > 0)
+        {
+            // Recover processed buffer for refill
+            alSourceUnqueueBuffers(currentMusic.source, 1, &buffer);
+
+            // Refill buffer
+            active = BufferMusicStream(buffer);
+            
+            // If no more data to stream, restart music (if loop)
+            if ((!active) && (currentMusic.loop))   
+            {
+                if (currentMusic.loop)
+                {
+                    stb_vorbis_seek_start(currentMusic.stream);
+                    currentMusic.totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic.stream) * currentMusic.channels;
+                    
+                    active = BufferMusicStream(buffer);
+                }
+            }
+            
+            // Add refilled buffer to queue again... don't let the music stop!
+            alSourceQueueBuffers(currentMusic.source, 1, &buffer);
+            
+            if(alGetError() != AL_NO_ERROR) TraceLog(WARNING, "Ogg playing, error buffering data...");
+            
+            processed--;
+        }
+        
+        ALenum state;
+        alGetSourcei(currentMusic.source, AL_SOURCE_STATE, &state);
+        
+        if ((state != AL_PLAYING) && active) alSourcePlay(currentMusic.source);
+        
+        if (!active) StopMusicStream();
+    }
 }
 }
 
 
 // Load WAV file into Wave structure
 // Load WAV file into Wave structure
-static Wave LoadWAV(char *fileName) 
+static Wave LoadWAV(const char *fileName)
 {
 {
     // Basic WAV headers structs
     // Basic WAV headers structs
     typedef struct {
     typedef struct {
@@ -543,199 +753,51 @@ static Wave LoadWAV(char *fileName)
     return wave;
     return wave;
 }
 }
 
 
-// Unload WAV file data
-static void UnloadWAV(Wave wave)
+// Load OGG file into Wave structure
+static Wave LoadOGG(char *fileName)
 {
 {
-    free(wave.data);
-}
-
-// TODO: Ogg data loading
-Music LoadMusic(char *fileName)
-{
-    Music music;
+    Wave wave;
     
     
-    // Open audio stream
-    music.stream = stb_vorbis_open_filename(fileName, NULL, NULL);
+    stb_vorbis *oggFile = stb_vorbis_open_filename(fileName, NULL, NULL);
+    stb_vorbis_info info = stb_vorbis_get_info(oggFile);
     
     
-	if (music.stream == NULL) TraceLog(WARNING, "Could not open ogg audio file");
-    else
-    {
-        // Get file info
-        music.info = stb_vorbis_get_info(music.stream);
-        
-        printf("Ogg sample rate: %i\n", music.info.sample_rate);
-        printf("Ogg channels: %i\n", music.info.channels);
-        printf("Temp memory required: %i\n", music.info.temp_memory_required);
-        
-        if (music.info.channels == 2) music.format = AL_FORMAT_STEREO16;
-        else music.format = AL_FORMAT_MONO16;
-        
-        music.bufferSize = 4096*8;
-        music.loop = true;          // We loop by default
-        
-        // Create an audio source
-        alGenSources(1, &music.source);             // Generate pointer to audio source
-
-        alSourcef(music.source, AL_PITCH, 1);    
-        alSourcef(music.source, AL_GAIN, 1);
-        alSource3f(music.source, AL_POSITION, 0, 0, 0);
-        alSource3f(music.source, AL_VELOCITY, 0, 0, 0);
-        alSourcei(music.source, AL_LOOPING, AL_TRUE);     // We loop by default
-        
-        // Convert loaded data to OpenAL buffers
-        alGenBuffers(2, music.buffers);
-    /*
-        if (!MusicStream(music, music.buffers[0])) exit(1);
-        if (!MusicStream(music, music.buffers[1])) exit(1);
-        
-        alSourceQueueBuffers(music.source, 2, music.buffers);
-     
-        PlayMusic(music);
-    */ 
-        music.totalSamplesLeft = stb_vorbis_stream_length_in_samples(music.stream) * music.info.channels;
-     
-        currentMusic = &music;
-    }
+    wave.sampleRate = info.sample_rate;
+    wave.bitsPerSample = 16;
+    wave.channels = info.channels;
     
     
-    return music;
-}
+    TraceLog(DEBUG, "[%s] Ogg sample rate: %i", fileName, info.sample_rate);
+    TraceLog(DEBUG, "[%s] Ogg channels: %i", fileName, info.channels);
 
 
-void UnloadMusic(Music music)
-{
-    StopMusic(music);
-
-    alDeleteSources(1, &music.source);
-	alDeleteBuffers(2, music.buffers);
+    int totalSamplesLength = (stb_vorbis_stream_length_in_samples(oggFile) * info.channels);
     
     
-	stb_vorbis_close(music.stream);
-}
-
-void PlayMusic(Music music)
-{
-    //if (MusicIsPlaying(music)) return true;
-
-    if (!MusicStream(music, music.buffers[0])) TraceLog(WARNING, "MusicStream returned 0");
-    if (!MusicStream(music, music.buffers[1])) TraceLog(WARNING, "MusicStream returned 0");
+    wave.dataSize = totalSamplesLength*sizeof(short);   // Size must be in bytes
     
     
-    alSourceQueueBuffers(music.source, 2, music.buffers);
-    alSourcePlay(music.source);
-
-    TraceLog(INFO, "Playing music");
-}
-
-extern void PlayCurrentMusic()
-{
-    if (!MusicStream(*currentMusic, currentMusic->buffers[0])) TraceLog(WARNING, "MusicStream returned 0");
-    if (!MusicStream(*currentMusic, currentMusic->buffers[1])) TraceLog(WARNING, "MusicStream returned 0");
+    TraceLog(DEBUG, "[%s] Samples length: %i", fileName, totalSamplesLength);
     
     
-    alSourceQueueBuffers(currentMusic->source, 2, currentMusic->buffers);
-    alSourcePlay(currentMusic->source);
-}
-
-// Stop reproducing music
-void StopMusic(Music music)
-{
-    alSourceStop(music.source);
+    float totalSeconds = stb_vorbis_stream_length_in_seconds(oggFile);
     
     
-    musicIsPlaying = false;
-}
-
-static bool MusicStream(Music music, ALuint buffer)
-{
-	//Uncomment this to avoid VLAs
-	//#define BUFFER_SIZE 4096*32
-	#ifndef BUFFER_SIZE//VLAs ftw
-	#define BUFFER_SIZE (music.bufferSize)
-	#endif
-	ALshort pcm[BUFFER_SIZE];
-    
-	int  size = 0;
-	int  result = 0;
- 
-	while (size < BUFFER_SIZE)
-    {
-		result = stb_vorbis_get_samples_short_interleaved(music.stream, music.info.channels, pcm+size, BUFFER_SIZE-size);
-        
-		if (result > 0) size += (result*music.info.channels);
-		else break;
-	}
- 
-	if (size == 0) return false;
- 
-	alBufferData(buffer, music.format, pcm, size*sizeof(ALshort), music.info.sample_rate);
+    TraceLog(DEBUG, "[%s] Total seconds: %f", fileName, totalSeconds);
     
     
-	music.totalSamplesLeft -= size;
-	
-    #undef BUFFER_SIZE
- 
-	return true;
-}
-/*
-extern bool MusicStreamUpdate()
-{
-	ALint processed = 0;
- 
-    alGetSourcei(currentMusic->source, AL_BUFFERS_PROCESSED, &processed);
- 
-    while (processed--)
-    {
-        ALuint buffer = 0;
-        
-        alSourceUnqueueBuffers(currentMusic->source, 1, &buffer);
- 
-		if (!MusicStream(*currentMusic, buffer))
-        {
-			bool shouldExit = true;
- 
-			if (currentMusic->loop)
-            {
-				stb_vorbis_seek_start(currentMusic->stream);
-				currentMusic->totalSamplesLeft = stb_vorbis_stream_length_in_samples(currentMusic->stream) * currentMusic->info.channels;
-				
-                shouldExit = !MusicStream(*currentMusic, buffer);
-			}
- 
-			if (shouldExit) return false;
-		}
-        
-		alSourceQueueBuffers(currentMusic->source, 1, &buffer);
-	}
- 
-	return true;
-}
-*/
-extern bool MusicStreamUpdate()
-{
-    int processed;
-    bool active = true;
- 
-    alGetSourcei(currentMusic->source, AL_BUFFERS_PROCESSED, &processed);
+    if (totalSeconds > 10) TraceLog(WARNING, "[%s] Ogg audio lenght is larger than 10 seconds (%f), that's a big file in memory, consider music streaming", fileName, totalSeconds);
     
     
-    printf("Data processed: %i\n", processed);
- 
-    while (processed--)
-    {
-        ALuint buffer = 0;
-        
-        alSourceUnqueueBuffers(currentMusic->source, 1, &buffer);
+    int totalSamples = totalSeconds*info.sample_rate*info.channels;
+   
+    TraceLog(DEBUG, "[%s] Total samples calculated: %i", fileName, totalSamples);
+    
+    //short *data 
+    wave.data = malloc(sizeof(short)*totalSamplesLength);
 
 
-        active = MusicStream(*currentMusic, buffer);
- 
-        alSourceQueueBuffers(currentMusic->source, 1, &buffer);
-    }
- 
-    return active;
+    int samplesObtained = stb_vorbis_get_samples_short_interleaved(oggFile, info.channels, wave.data, totalSamplesLength);
+    
+    TraceLog(DEBUG, "[%s] Samples obtained: %i", fileName, samplesObtained);
+
+    stb_vorbis_close(oggFile);
+    
+    return wave;
 }
 }
 
 
-void MusicStreamEmpty()
+// Unload Wave data
+static void UnloadWave(Wave wave)
 {
 {
-    int queued;
-    
-    alGetSourcei(currentMusic->source, AL_BUFFERS_QUEUED, &queued);
-    
-    while(queued--)
-    {
-        ALuint buffer;  
-        alSourceUnqueueBuffers(currentMusic->source, 1, &buffer);
-    }
+    free(wave.data);
 }
 }

+ 7 - 8
src/core.c

@@ -89,11 +89,10 @@ static Color background = { 0, 0, 0, 0 };   // Screen background color
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Other Modules Functions Declaration (required by core)
 // Other Modules Functions Declaration (required by core)
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
-extern void LoadDefaultFont();               // [Module: text] Loads default font on InitWindow()
-extern void UnloadDefaultFont();             // [Module: text] Unloads default font from GPU memory
+extern void LoadDefaultFont();              // [Module: text] Loads default font on InitWindow()
+extern void UnloadDefaultFont();            // [Module: text] Unloads default font from GPU memory
 
 
-extern bool MusicStreamUpdate();             // [Module: audio] Updates buffers for music streamming
-extern void PlayCurrentMusic();              // [Module: audio] Plays current music stream
+extern void UpdateMusicStream();            // [Module: audio] Updates buffers for music streaming
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
 // Module specific Functions Declaration
@@ -103,7 +102,7 @@ static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, i
 static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);            // GLFW3 Srolling Callback, runs on mouse wheel
 static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);            // GLFW3 Srolling Callback, runs on mouse wheel
 static void CursorEnterCallback(GLFWwindow* window, int enter);                            // GLFW3 Cursor Enter Callback, cursor enters client area
 static void CursorEnterCallback(GLFWwindow* window, int enter);                            // GLFW3 Cursor Enter Callback, cursor enters client area
 static void WindowSizeCallback(GLFWwindow* window, int width, int height);                 // GLFW3 WindowSize Callback, runs when window is resized
 static void WindowSizeCallback(GLFWwindow* window, int width, int height);                 // GLFW3 WindowSize Callback, runs when window is resized
-static void TakeScreenshot();                                                              // Takes a bitmap (BMP) screenshot and saves it in the same folder as executable
+static void TakeScreenshot();                                                              // Takes a screenshot and saves it in the same folder as executable
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Module Functions Definition - Window and OpenGL Context Functions
 // Module Functions Definition - Window and OpenGL Context Functions
@@ -304,9 +303,7 @@ void EndDrawing()
     glfwSwapBuffers(window);            // Swap back and front buffers
     glfwSwapBuffers(window);            // Swap back and front buffers
     glfwPollEvents();                   // Register keyboard/mouse events
     glfwPollEvents();                   // Register keyboard/mouse events
     
     
-    //MusicStreamUpdate();
-    //if (!MusicIsPlaying()) 
-    //PlayCurrentMusic();
+    UpdateMusicStream();        // NOTE: Function checks if music is enabled
     
     
     currentTime = glfwGetTime();
     currentTime = glfwGetTime();
     drawTime = currentTime - previousTime;
     drawTime = currentTime - previousTime;
@@ -748,4 +745,6 @@ static void TakeScreenshot()
     free(imgData);
     free(imgData);
 
 
     shotNum++;
     shotNum++;
+    
+    TraceLog(INFO, "[%s] Screenshot taken!", buffer);
 }
 }

+ 343 - 304
src/models.c

@@ -25,9 +25,9 @@
 
 
 #include "raylib.h"
 #include "raylib.h"
 
 
-#include <GL/gl.h>       // OpenGL functions
 #include <stdio.h>       // Standard input/output functions, used to read model files data
 #include <stdio.h>       // Standard input/output functions, used to read model files data
 #include <stdlib.h>      // Declares malloc() and free() for memory management
 #include <stdlib.h>      // Declares malloc() and free() for memory management
+#include <string.h>      // Required for strcmp()
 #include <math.h>        // Used for sin, cos, tan
 #include <math.h>        // Used for sin, cos, tan
 
 
 #include "raymath.h"     // Required for data type Matrix and Matrix functions
 #include "raymath.h"     // Required for data type Matrix and Matrix functions
@@ -52,6 +52,7 @@
 // Module specific Functions Declaration
 // Module specific Functions Declaration
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 static float GetHeightValue(Color pixel);
 static float GetHeightValue(Color pixel);
+static VertexData LoadOBJ(const char *fileName);
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Module Functions Definition
 // Module Functions Definition
@@ -67,9 +68,9 @@ void DrawCube(Vector3 position, float width, float height, float lenght, Color c
 
 
     rlPushMatrix();
     rlPushMatrix();
 
 
-        // NOTE: Be careful! Function order matters (scale, translate, rotate)
-        //rlScalef(2.0f, 2.0f, 2.0f);
+        // NOTE: Be careful! Function order matters (rotate -> scale -> translate)
         //rlTranslatef(0.0f, 0.0f, 0.0f);
         //rlTranslatef(0.0f, 0.0f, 0.0f);
+        //rlScalef(2.0f, 2.0f, 2.0f);
         //rlRotatef(45, 0, 1, 0);
         //rlRotatef(45, 0, 1, 0);
     
     
         rlBegin(RL_TRIANGLES);
         rlBegin(RL_TRIANGLES);
@@ -215,9 +216,9 @@ void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float hei
     float y = position.y;
     float y = position.y;
     float z = position.z;
     float z = position.z;
 
 
-    rlEnableTexture(texture.glId);
+    rlEnableTexture(texture.id);
     
     
-    rlPushMatrix();      
+    //rlPushMatrix();      
         // NOTE: Be careful! Function order matters (scale, translate, rotate)
         // NOTE: Be careful! Function order matters (scale, translate, rotate)
         //rlScalef(2.0f, 2.0f, 2.0f);
         //rlScalef(2.0f, 2.0f, 2.0f);
         //rlTranslatef(2.0f, 0.0f, 0.0f);
         //rlTranslatef(2.0f, 0.0f, 0.0f);
@@ -262,7 +263,7 @@ void DrawCubeTexture(Texture2D texture, Vector3 position, float width, float hei
             rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z+lenght/2);  // Top Right Of The Texture and Quad
             rlTexCoord2f(1.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z+lenght/2);  // Top Right Of The Texture and Quad
             rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z-lenght/2);  // Top Left Of The Texture and Quad
             rlTexCoord2f(0.0f, 1.0f); rlVertex3f(x-width/2, y+height/2, z-lenght/2);  // Top Left Of The Texture and Quad
         rlEnd();
         rlEnd();
-    rlPopMatrix();
+    //rlPopMatrix();
     
     
     rlDisableTexture();
     rlDisableTexture();
 }
 }
@@ -278,13 +279,13 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
 {
 {
     rlPushMatrix();
     rlPushMatrix();
         rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
         rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
-        //rlRotatef(rotation, 0, 1, 0);
         rlScalef(radius, radius, radius);
         rlScalef(radius, radius, radius);
+        //rlRotatef(rotation, 0, 1, 0);
         
         
         rlBegin(RL_TRIANGLES);
         rlBegin(RL_TRIANGLES);
             rlColor4ub(color.r, color.g, color.b, color.a);
             rlColor4ub(color.r, color.g, color.b, color.a);
             
             
-            for(int i = 0; i < 2 * rings + 1; i ++)
+            for(int i = 0; i < 2 * rings + 1; i++)
             {
             {
                 for(int j = 0; j < slices; j++)
                 for(int j = 0; j < slices; j++)
                 {
                 {
@@ -317,14 +318,14 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color
 void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color)
 void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Color color)
 {
 {
     rlPushMatrix();
     rlPushMatrix();
-        rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
-        //rlRotatef(rotation, 0, 1, 0);
+        //rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
         rlScalef(radius, radius, radius);
         rlScalef(radius, radius, radius);
+        //rlRotatef(rotation, 0, 1, 0);
         
         
         rlBegin(RL_LINES);
         rlBegin(RL_LINES);
             rlColor4ub(color.r, color.g, color.b, color.a);
             rlColor4ub(color.r, color.g, color.b, color.a);
             
             
-            for(int i = 0; i < 2 * rings + 1; i ++)
+            for(int i = 0; i < 2 * rings + 1; i++)
             {
             {
                 for(int j = 0; j < slices; j++)
                 for(int j = 0; j < slices; j++)
                 {
                 {
@@ -447,12 +448,12 @@ void DrawPlane(Vector3 centerPos, Vector2 size, Vector3 rotation, Color color)
     // NOTE: Plane is always created on XZ ground and then rotated
     // NOTE: Plane is always created on XZ ground and then rotated
     rlPushMatrix();
     rlPushMatrix();
         rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
         rlTranslatef(centerPos.x, centerPos.y, centerPos.z);
+        rlScalef(size.x, 1.0f, size.y);
         
         
         // TODO: Review multiples rotations Gimbal-Lock... use matrix or quaternions...
         // TODO: Review multiples rotations Gimbal-Lock... use matrix or quaternions...
         rlRotatef(rotation.x, 1, 0, 0);
         rlRotatef(rotation.x, 1, 0, 0);
         rlRotatef(rotation.y, 0, 1, 0);
         rlRotatef(rotation.y, 0, 1, 0);
         rlRotatef(rotation.z, 0, 0, 1);
         rlRotatef(rotation.z, 0, 0, 1);
-        rlScalef(size.x, 1.0f, size.y);
     
     
         rlBegin(RL_QUADS);
         rlBegin(RL_QUADS);
             rlColor4ub(color.r, color.g, color.b, color.a);
             rlColor4ub(color.r, color.g, color.b, color.a);
@@ -568,14 +569,13 @@ void DrawGizmo(Vector3 position)
     rlPopMatrix();
     rlPopMatrix();
 }
 }
 
 
-void DrawGizmoEx(Vector3 position, Vector3 rot, float scale, bool orbits)
-{
-    static float rotation = 0;
+void DrawGizmoEx(Vector3 position, Vector3 rotation, float scale)
+{   
     // NOTE: RGB = XYZ
     // NOTE: RGB = XYZ
     rlPushMatrix();
     rlPushMatrix();
         rlTranslatef(position.x, position.y, position.z);
         rlTranslatef(position.x, position.y, position.z);
-        rlRotatef(rotation, 0, 1, 0);
         rlScalef(scale, scale, scale);
         rlScalef(scale, scale, scale);
+        rlRotatef(rotation.y, 0, 1, 0);
 
 
         rlBegin(RL_LINES);
         rlBegin(RL_LINES);
             // X Axis
             // X Axis
@@ -612,279 +612,53 @@ void DrawGizmoEx(Vector3 position, Vector3 rot, float scale, bool orbits)
             rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x - .1, position.y, position.z - .9);
             rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x - .1, position.y, position.z - .9);
             
             
             // Extra
             // Extra
-            if(orbits)
+            int n = 3;
+            
+            // X Axis
+            for (int i=0; i < 360; i += 6)
             {
             {
-                int n = 3;
-                
-                // X Axis
-                for (int i=0; i < 360; i += 6)
-                {
-                    rlColor4ub(200, 0, 0, 255); rlVertex3f(0, position.x + sin(DEG2RAD*i) * scale/n, position.y + cos(DEG2RAD*i) * scale/n);
-                    rlColor4ub(200, 0, 0, 255); rlVertex3f(0, position.x + sin(DEG2RAD*(i+6)) * scale/n, position.y + cos(DEG2RAD*(i+6)) * scale/n);
-                }
-                
-                // Y Axis
-                for (int i=0; i < 360; i += 6)
-                {
-                    rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x + sin(DEG2RAD*i) * scale/n, 0, position.y + cos(DEG2RAD*i) * scale/n);
-                    rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x + sin(DEG2RAD*(i+6)) * scale/n, 0, position.y + cos(DEG2RAD*(i+6)) * scale/n);
-                }
-                
-                // Z Axis
-                for (int i=0; i < 360; i += 6)
-                {
-                    rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x + sin(DEG2RAD*i) * scale/n, position.y + cos(DEG2RAD*i) * scale/n, 0);
-                    rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x + sin(DEG2RAD*(i+6)) * scale/n, position.y + cos(DEG2RAD*(i+6)) * scale/n, 0);
-                }
+                rlColor4ub(200, 0, 0, 255); rlVertex3f(0, position.x + sin(DEG2RAD*i) * scale/n, position.y + cos(DEG2RAD*i) * scale/n);
+                rlColor4ub(200, 0, 0, 255); rlVertex3f(0, position.x + sin(DEG2RAD*(i+6)) * scale/n, position.y + cos(DEG2RAD*(i+6)) * scale/n);
+            }
+            
+            // Y Axis
+            for (int i=0; i < 360; i += 6)
+            {
+                rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x + sin(DEG2RAD*i) * scale/n, 0, position.y + cos(DEG2RAD*i) * scale/n);
+                rlColor4ub(0, 200, 0, 255); rlVertex3f(position.x + sin(DEG2RAD*(i+6)) * scale/n, 0, position.y + cos(DEG2RAD*(i+6)) * scale/n);
+            }
+            
+            // Z Axis
+            for (int i=0; i < 360; i += 6)
+            {
+                rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x + sin(DEG2RAD*i) * scale/n, position.y + cos(DEG2RAD*i) * scale/n, 0);
+                rlColor4ub(0, 0, 200, 255); rlVertex3f(position.x + sin(DEG2RAD*(i+6)) * scale/n, position.y + cos(DEG2RAD*(i+6)) * scale/n, 0);
             }
             }
         rlEnd();
         rlEnd();
     rlPopMatrix();
     rlPopMatrix();
-    
-    rotation += 0.1f;
 }
 }
 
 
-// Load a 3d model (.OBJ)
-// TODO: Add comments explaining this function process
+// Load a 3d model
 Model LoadModel(const char *fileName)                                    
 Model LoadModel(const char *fileName)                                    
 {
 {
     VertexData vData;
     VertexData vData;
     
     
-    char dataType;
-    char comments[200];
-    
-    int numVertex = 0;
-    int numNormals = 0;
-    int numTexCoords = 0;
-    int numTriangles = 0;
-
-    FILE* objFile;
-
-    objFile = fopen(fileName, "rt");
-    
-    while(!feof(objFile))
-    {
-        fscanf(objFile, "%c", &dataType);
-        
-        switch(dataType)
-        {
-            case '#':         // It's a comment
-            {
-                fgets(comments, 200, objFile);                
-            } break;
-            case 'v': 
-            {
-                fscanf(objFile, "%c", &dataType);
-                
-                if (dataType == 't')    // Read texCoord
-                {
-                    fgets(comments, 200, objFile);
-                    fscanf(objFile, "%c", &dataType);
-                
-                    while (dataType == 'v')
-                    {
-                        fgets(comments, 200, objFile);
-                        fscanf(objFile, "%c", &dataType);
-                    }
-                    
-                    if (dataType == '#')
-                    {
-                        fscanf(objFile, "%i", &numTexCoords);
-                    }
-                    
-                    fgets(comments, 200, objFile);
-                }
-                else if (dataType == 'n')    // Read normals
-                {
-                    fgets(comments, 200, objFile);
-                    fscanf(objFile, "%c", &dataType);
-                
-                    while (dataType == 'v')
-                    {
-                        fgets(comments, 200, objFile);
-                        fscanf(objFile, "%c", &dataType);
-                    }
-                    
-                    if (dataType == '#')
-                    {
-                        fscanf(objFile, "%i", &numNormals);
-                    }
-                
-                    fgets(comments, 200, objFile);
-                }
-                else    // Read vertex
-                {
-                    fgets(comments, 200, objFile);
-                    fscanf(objFile, "%c", &dataType);
-                
-                    while (dataType == 'v')
-                    {
-                        fgets(comments, 200, objFile);
-                        fscanf(objFile, "%c", &dataType);
-                    }
-                    
-                    if (dataType == '#')
-                    {
-                        fscanf(objFile, "%i", &numVertex);
-                    }
-                    
-                    fgets(comments, 200, objFile);
-                }
-            } break;
-            case 'f':
-            {
-                fgets(comments, 200, objFile);
-                fscanf(objFile, "%c", &dataType);
-            
-                while (dataType == 'f')
-                {
-                    fgets(comments, 200, objFile);
-                    fscanf(objFile, "%c", &dataType);
-                }
-                
-                if (dataType == '#')
-                {
-                    fscanf(objFile, "%i", &numTriangles);
-                }
-                
-                fgets(comments, 200, objFile);
-            
-            } break;
-            default: break;
-        }
-    }
-    
-    Vector3 midVertices[numVertex];
-    Vector3 midNormals[numNormals];
-    Vector2 midTexCoords[numTexCoords];
-    
-    vData.numVertices = numTriangles*3;
-    
-    vData.vertices = (float *)malloc(vData.numVertices * 3 * sizeof(float));
-    vData.texcoords = (float *)malloc(vData.numVertices * 2 * sizeof(float));
-    vData.normals = (float *)malloc(vData.numVertices * 3 * sizeof(float));
-    
-    int countVertex = 0;
-    int countNormals = 0;
-    int countTexCoords = 0;
-    
-    int vCounter = 0;       // Used to count vertices float by float
-    int tcCounter = 0;      // Used to count texcoords float by float
-    int nCounter = 0;       // Used to count normals float by float
-    
-    rewind(objFile);
-    
-    while(!feof(objFile))
-    {
-        fscanf(objFile, "%c", &dataType);
-        
-        switch(dataType)
-        {
-            case '#': 
-            {
-                fgets(comments, 200, objFile);                
-            } break;
-            case 'v': 
-            {
-                fscanf(objFile, "%c", &dataType);
-                
-                if (dataType == 't')    // Read texCoord
-                {
-                    float useless = 0;
-                
-                    fscanf(objFile, "%f %f %f", &midTexCoords[countTexCoords].x, &midTexCoords[countTexCoords].y, &useless);
-                    countTexCoords++;
-                    
-                    fscanf(objFile, "%c", &dataType);
-                }
-                else if (dataType == 'n')    // Read normals
-                {
-                    fscanf(objFile, "%f %f %f", &midNormals[countNormals].x, &midNormals[countNormals].y, &midNormals[countNormals].z );
-                    countNormals++;
-                    
-                    fscanf(objFile, "%c", &dataType);
-                }
-                else    // Read vertex
-                {
-                    fscanf(objFile, "%f %f %f", &midVertices[countVertex].x, &midVertices[countVertex].y, &midVertices[countVertex].z );
-                    countVertex++;
-                    
-                    fscanf(objFile, "%c", &dataType);
-                }
-            } break;
-            case 'f':
-            {
-                // At this point all vertex data (v, vt, vn) have been gathered on midVertices, midTexCoords, midNormals
-                // Now we can organize that data into our VertexData struct
-            
-                int vNum, vtNum, vnNum;
-                fscanf(objFile, "%c", &dataType);
-                fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
-                
-                vData.vertices[vCounter] = midVertices[vNum-1].x;
-                vData.vertices[vCounter + 1] = midVertices[vNum-1].y;
-                vData.vertices[vCounter + 2] = midVertices[vNum-1].z;
-                vCounter += 3;
-                
-                vData.normals[nCounter] = midNormals[vnNum-1].x;
-                vData.normals[nCounter + 1] = midNormals[vnNum-1].y;
-                vData.normals[nCounter + 2] = midNormals[vnNum-1].z;
-                nCounter += 3;
-                
-                vData.texcoords[tcCounter] = midTexCoords[vtNum-1].x;
-                vData.texcoords[tcCounter + 1] = -midTexCoords[vtNum-1].y;
-                tcCounter += 2;
-
-                fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
-                
-                vData.vertices[vCounter] = midVertices[vNum-1].x;
-                vData.vertices[vCounter + 1] = midVertices[vNum-1].y;
-                vData.vertices[vCounter + 2] = midVertices[vNum-1].z;
-                vCounter += 3;
-                
-                vData.normals[nCounter] = midNormals[vnNum-1].x;
-                vData.normals[nCounter + 1] = midNormals[vnNum-1].y;
-                vData.normals[nCounter + 2] = midNormals[vnNum-1].z;
-                nCounter += 3;
-                
-                vData.texcoords[tcCounter] = midTexCoords[vtNum-1].x;
-                vData.texcoords[tcCounter + 1] = -midTexCoords[vtNum-1].y;
-                tcCounter += 2;
-                
-                fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
-                
-                vData.vertices[vCounter] = midVertices[vNum-1].x;
-                vData.vertices[vCounter + 1] = midVertices[vNum-1].y;
-                vData.vertices[vCounter + 2] = midVertices[vNum-1].z;
-                vCounter += 3;
-                
-                vData.normals[nCounter] = midNormals[vnNum-1].x;
-                vData.normals[nCounter + 1] = midNormals[vnNum-1].y;
-                vData.normals[nCounter + 2] = midNormals[vnNum-1].z;
-                nCounter += 3;
-                
-                vData.texcoords[tcCounter] = midTexCoords[vtNum-1].x;
-                vData.texcoords[tcCounter + 1] = -midTexCoords[vtNum-1].y;
-                tcCounter += 2;
-            } break;
-            default: break;
-        }
-    }
-    
-    fclose(objFile);
-    
-    // NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct
+    if (strcmp(GetExtension(fileName),"obj") == 0) vData = LoadOBJ(fileName);
+    else TraceLog(WARNING, "[%s] Model extension not recognized, it can't be loaded", fileName); 
 
 
     Model model;
     Model model;
 
 
-#ifdef USE_OPENGL_11
-    model.data = vData;      // model data is vertex data  
-#else   
-    model.vaoId = rlglLoadModel(vData);     // Use loaded data to generate VAO
+    model.mesh = vData;                     // Model mesh is vertex data
+    model.textureId = 0;
     
     
+#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+    model.vaoId = rlglLoadModel(vData);     // Use loaded data to generate VAO
+    model.textureId = 1;                    // Default whiteTexture
+
     // Now that vertex data is uploaded to GPU, we can free arrays
     // Now that vertex data is uploaded to GPU, we can free arrays
-    free(vData.vertices);
-    free(vData.texcoords);
-    free(vData.normals);
+    //free(vData.vertices);
+    //free(vData.texcoords);
+    //free(vData.normals);
 #endif
 #endif
 
 
     return model;
     return model;
@@ -902,11 +676,11 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
     // TODO: Consider resolution when generating model data?
     // TODO: Consider resolution when generating model data?
     int numTriangles = (mapX-1)*(mapZ-1)*2;    // One quad every four pixels
     int numTriangles = (mapX-1)*(mapZ-1)*2;    // One quad every four pixels
   
   
-    vData.numVertices = numTriangles*3;
+    vData.vertexCount = numTriangles*3;
 
 
-    vData.vertices = (float *)malloc(vData.numVertices * 3 * sizeof(float));
-    vData.normals = (float *)malloc(vData.numVertices * 3 * sizeof(float));
-    vData.texcoords = (float *)malloc(vData.numVertices * 2 * sizeof(float));
+    vData.vertices = (float *)malloc(vData.vertexCount * 3 * sizeof(float));
+    vData.normals = (float *)malloc(vData.vertexCount * 3 * sizeof(float));
+    vData.texcoords = (float *)malloc(vData.vertexCount * 2 * sizeof(float));
     
     
     int vCounter = 0;       // Used to count vertices float by float
     int vCounter = 0;       // Used to count vertices float by float
     int tcCounter = 0;      // Used to count texcoords float by float
     int tcCounter = 0;      // Used to count texcoords float by float
@@ -973,7 +747,7 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
             
             
             // Fill normals array with data
             // Fill normals array with data
             //--------------------------------------------------------------
             //--------------------------------------------------------------
-            // TODO: Review normals calculation
+            // NOTE: Current Model implementation doe not use normals! 
             for (int i = 0; i < 18; i += 3)
             for (int i = 0; i < 18; i += 3)
             {
             {
                 vData.normals[nCounter + i] = 0.0f;
                 vData.normals[nCounter + i] = 0.0f;
@@ -981,6 +755,8 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
                 vData.normals[nCounter + i + 2] = 0.0f;
                 vData.normals[nCounter + i + 2] = 0.0f;
             }
             }
             
             
+            // TODO: Calculate normals in an efficient way
+            
             nCounter += 18;     // 6 vertex, 18 floats
             nCounter += 18;     // 6 vertex, 18 floats
             
             
             trisCounter += 2;
             trisCounter += 2;
@@ -991,15 +767,17 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
 
 
     Model model;
     Model model;
 
 
-#ifdef USE_OPENGL_11
-    model.data = vData;      // model data is vertex data  
-#else   
+    model.mesh = vData;                     // Model mesh is vertex data
+    model.textureId = 0;
+    
+#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
     model.vaoId = rlglLoadModel(vData);     // Use loaded data to generate VAO
     model.vaoId = rlglLoadModel(vData);     // Use loaded data to generate VAO
+    model.textureId = 1;                    // Default whiteTexture
 
 
     // Now that vertex data is uploaded to GPU, we can free arrays
     // Now that vertex data is uploaded to GPU, we can free arrays
-    free(vData.vertices);
-    free(vData.texcoords);
-    free(vData.normals);
+    //free(vData.vertices);
+    //free(vData.texcoords);
+    //free(vData.normals);
 #endif
 #endif
 
 
     return model;
     return model;
@@ -1008,37 +786,43 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
 // Unload 3d model from memory
 // Unload 3d model from memory
 void UnloadModel(Model model)
 void UnloadModel(Model model)
 {
 {
-#ifdef USE_OPENGL_11
-    free(model.data.vertices);
-    free(model.data.texcoords);
-    free(model.data.normals);
-#endif
+    free(model.mesh.vertices);
+    free(model.mesh.texcoords);
+    free(model.mesh.normals);
 
 
 #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
 #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
     rlDeleteVertexArrays(model.vaoId);
     rlDeleteVertexArrays(model.vaoId);
 #endif
 #endif
 }
 }
 
 
-// Draw a model
-void DrawModel(Model model, Vector3 position, float scale, Color color)
+void SetModelTexture(Model *model, Texture2D texture)
 {
 {
-    rlglDrawModel(model, position, scale, false);
+    if (texture.id <= 0) model->textureId = 1;  // Default white texture (use mesh color)
+    else model->textureId = texture.id;
 }
 }
 
 
-// Draw a textured model
-void DrawModelEx(Model model, Texture2D texture, Vector3 position, float scale, Color tint)
+// Draw a model (with texture if set)
+void DrawModel(Model model, Vector3 position, float scale, Color tint)
 {
 {
-    rlEnableTexture(texture.glId);
-    
-    DrawModel(model, position, scale, tint);
-    
-    rlDisableTexture();
+    Vector3 vScale = { scale, scale, scale };
+    Vector3 rotation = { 0, 0, 0 };
+
+    rlglDrawModel(model, position, rotation, vScale, tint, false);
 }
 }
 
 
-// Draw a model wires
+// Draw a model with extended parameters
+void DrawModelEx(Model model, Vector3 position, Vector3 rotation, Vector3 scale, Color tint)
+{
+    rlglDrawModel(model, position, rotation, scale, tint, false);
+}
+
+// Draw a model wires (with texture if set)
 void DrawModelWires(Model model, Vector3 position, float scale, Color color)
 void DrawModelWires(Model model, Vector3 position, float scale, Color color)
 {
 {
-    rlglDrawModel(model, position, scale, true);
+    Vector3 vScale = { scale, scale, scale };
+    Vector3 rotation = { 0, 0, 0 };
+
+    rlglDrawModel(model, position, rotation, vScale, color, true);
 }
 }
 
 
 // Draw a billboard
 // Draw a billboard
@@ -1070,7 +854,7 @@ void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size,
     Vector3 c = VectorAdd(center, p2);
     Vector3 c = VectorAdd(center, p2);
     Vector3 d = VectorSubtract(center, p1);
     Vector3 d = VectorSubtract(center, p1);
     
     
-    rlEnableTexture(texture.glId);
+    rlEnableTexture(texture.id);
       
       
     rlBegin(RL_QUADS);
     rlBegin(RL_QUADS);
         rlColor4ub(tint.r, tint.g, tint.b, tint.a);
         rlColor4ub(tint.r, tint.g, tint.b, tint.a);
@@ -1113,7 +897,7 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vec
     Vector3 c = VectorAdd(center, p2);
     Vector3 c = VectorAdd(center, p2);
     Vector3 d = VectorSubtract(center, p1);
     Vector3 d = VectorSubtract(center, p1);
     
     
-    rlEnableTexture(texture.glId);
+    rlEnableTexture(texture.id);
     
     
     rlBegin(RL_QUADS);
     rlBegin(RL_QUADS);
         rlColor4ub(tint.r, tint.g, tint.b, tint.a);
         rlColor4ub(tint.r, tint.g, tint.b, tint.a);
@@ -1142,4 +926,259 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vec
 static float GetHeightValue(Color pixel)
 static float GetHeightValue(Color pixel)
 {
 {
     return (((float)pixel.r + (float)pixel.g + (float)pixel.b)/3);
     return (((float)pixel.r + (float)pixel.g + (float)pixel.b)/3);
+}
+
+// Load OBJ mesh data
+static VertexData LoadOBJ(const char *fileName)
+{
+    VertexData vData;
+    
+    char dataType;
+    char comments[200];
+    
+    int numVertex = 0;
+    int numNormals = 0;
+    int numTexCoords = 0;
+    int numTriangles = 0;
+
+    FILE* objFile;
+
+    objFile = fopen(fileName, "rt");
+    
+    // First pass over all file to get numVertex, numNormals, numTexCoords, numTriangles
+    // NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition)
+    while(!feof(objFile))
+    {
+        fscanf(objFile, "%c", &dataType);
+        
+        switch(dataType)
+        {
+            case '#':         // It's a comment
+            {
+                fgets(comments, 200, objFile);                
+            } break;
+            case 'o':         // New object
+            {
+                // TODO: Read multiple objects, we need to know numMeshes + verticesPerMesh
+                
+                // NOTE: One OBJ file can contain multible meshes defined, one after every 'o'
+                
+            } break;
+            case 'v':
+            {
+                fscanf(objFile, "%c", &dataType);
+                
+                if (dataType == 't')    // Read texCoord
+                {
+                    fgets(comments, 200, objFile);
+                    fscanf(objFile, "%c", &dataType);
+                
+                    while (dataType == 'v')
+                    {
+                        fgets(comments, 200, objFile);
+                        fscanf(objFile, "%c", &dataType);
+                    }
+                    
+                    if (dataType == '#')
+                    {
+                        fscanf(objFile, "%i", &numTexCoords);
+                    }
+                    
+                    fgets(comments, 200, objFile);
+                }
+                else if (dataType == 'n')    // Read normals
+                {
+                    fgets(comments, 200, objFile);
+                    fscanf(objFile, "%c", &dataType);
+                
+                    while (dataType == 'v')
+                    {
+                        fgets(comments, 200, objFile);
+                        fscanf(objFile, "%c", &dataType);
+                    }
+                    
+                    if (dataType == '#')
+                    {
+                        fscanf(objFile, "%i", &numNormals);
+                    }
+                
+                    fgets(comments, 200, objFile);
+                }
+                else    // Read vertex
+                {
+                    fgets(comments, 200, objFile);
+                    fscanf(objFile, "%c", &dataType);
+                
+                    while (dataType == 'v')
+                    {
+                        fgets(comments, 200, objFile);
+                        fscanf(objFile, "%c", &dataType);
+                    }
+                    
+                    if (dataType == '#')
+                    {
+                        fscanf(objFile, "%i", &numVertex);
+                    }
+                    
+                    fgets(comments, 200, objFile);
+                }
+            } break;
+            case 'f':
+            {
+                fgets(comments, 200, objFile);
+                fscanf(objFile, "%c", &dataType);
+            
+                while (dataType == 'f')
+                {
+                    fgets(comments, 200, objFile);
+                    fscanf(objFile, "%c", &dataType);
+                }
+                
+                if (dataType == '#')
+                {
+                    fscanf(objFile, "%i", &numTriangles);
+                }
+                
+                fgets(comments, 200, objFile);
+            
+            } break;
+            default: break;
+        }
+    }
+    
+    // Once we know the number of vertices to store, we create required arrays
+    Vector3 *midVertices = (Vector3 *)malloc(numVertex*sizeof(Vector3));
+    Vector3 *midNormals = (Vector3 *)malloc(numNormals*sizeof(Vector3));
+    Vector2 *midTexCoords = (Vector2 *)malloc(numTexCoords*sizeof(Vector2));
+    
+    vData.vertexCount = numTriangles*3;
+    
+    // Additional arrays to store vertex data as floats
+    vData.vertices = (float *)malloc(vData.vertexCount * 3 * sizeof(float));
+    vData.texcoords = (float *)malloc(vData.vertexCount * 2 * sizeof(float));
+    vData.normals = (float *)malloc(vData.vertexCount * 3 * sizeof(float));
+    vData.colors = (float *)malloc(vData.vertexCount * 4 * sizeof(float));
+    
+    int countVertex = 0;
+    int countNormals = 0;
+    int countTexCoords = 0;
+    
+    int vCounter = 0;       // Used to count vertices float by float
+    int tcCounter = 0;      // Used to count texcoords float by float
+    int nCounter = 0;       // Used to count normals float by float
+    
+    rewind(objFile);        // Return to the beginning of the file, to read again
+    
+    // Reading again file to get vertex data
+    while(!feof(objFile))
+    {
+        fscanf(objFile, "%c", &dataType);
+        
+        switch(dataType)
+        {
+            case '#': 
+            {
+                fgets(comments, 200, objFile);                
+            } break;
+            case 'v': 
+            {
+                fscanf(objFile, "%c", &dataType);
+                
+                if (dataType == 't')    // Read texCoord
+                {
+                    float useless = 0;
+                
+                    fscanf(objFile, "%f %f %f", &midTexCoords[countTexCoords].x, &midTexCoords[countTexCoords].y, &useless);
+                    countTexCoords++;
+                    
+                    fscanf(objFile, "%c", &dataType);
+                }
+                else if (dataType == 'n')    // Read normals
+                {
+                    fscanf(objFile, "%f %f %f", &midNormals[countNormals].x, &midNormals[countNormals].y, &midNormals[countNormals].z );
+                    countNormals++;
+                    
+                    fscanf(objFile, "%c", &dataType);
+                }
+                else    // Read vertex
+                {
+                    fscanf(objFile, "%f %f %f", &midVertices[countVertex].x, &midVertices[countVertex].y, &midVertices[countVertex].z );
+                    countVertex++;
+                    
+                    fscanf(objFile, "%c", &dataType);
+                }
+            } break;
+            case 'f':
+            {
+                // At this point all vertex data (v, vt, vn) have been gathered on midVertices, midTexCoords, midNormals
+                // Now we can organize that data into our VertexData struct
+            
+                int vNum, vtNum, vnNum;
+                fscanf(objFile, "%c", &dataType);
+                fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
+                
+                vData.vertices[vCounter] = midVertices[vNum-1].x;
+                vData.vertices[vCounter + 1] = midVertices[vNum-1].y;
+                vData.vertices[vCounter + 2] = midVertices[vNum-1].z;
+                vCounter += 3;
+                
+                vData.normals[nCounter] = midNormals[vnNum-1].x;
+                vData.normals[nCounter + 1] = midNormals[vnNum-1].y;
+                vData.normals[nCounter + 2] = midNormals[vnNum-1].z;
+                nCounter += 3;
+                
+                vData.texcoords[tcCounter] = midTexCoords[vtNum-1].x;
+                vData.texcoords[tcCounter + 1] = -midTexCoords[vtNum-1].y;
+                tcCounter += 2;
+
+                fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
+                
+                vData.vertices[vCounter] = midVertices[vNum-1].x;
+                vData.vertices[vCounter + 1] = midVertices[vNum-1].y;
+                vData.vertices[vCounter + 2] = midVertices[vNum-1].z;
+                vCounter += 3;
+                
+                vData.normals[nCounter] = midNormals[vnNum-1].x;
+                vData.normals[nCounter + 1] = midNormals[vnNum-1].y;
+                vData.normals[nCounter + 2] = midNormals[vnNum-1].z;
+                nCounter += 3;
+                
+                vData.texcoords[tcCounter] = midTexCoords[vtNum-1].x;
+                vData.texcoords[tcCounter + 1] = -midTexCoords[vtNum-1].y;
+                tcCounter += 2;
+                
+                fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
+                
+                vData.vertices[vCounter] = midVertices[vNum-1].x;
+                vData.vertices[vCounter + 1] = midVertices[vNum-1].y;
+                vData.vertices[vCounter + 2] = midVertices[vNum-1].z;
+                vCounter += 3;
+                
+                vData.normals[nCounter] = midNormals[vnNum-1].x;
+                vData.normals[nCounter + 1] = midNormals[vnNum-1].y;
+                vData.normals[nCounter + 2] = midNormals[vnNum-1].z;
+                nCounter += 3;
+                
+                vData.texcoords[tcCounter] = midTexCoords[vtNum-1].x;
+                vData.texcoords[tcCounter + 1] = -midTexCoords[vtNum-1].y;
+                tcCounter += 2;
+            } break;
+            default: break;
+        }
+    }
+    
+    fclose(objFile);
+    
+    // NOTE: We set all vertex colors to white
+    for (int i = 0; i < (4*vData.vertexCount); i++) vData.colors[i] = 1.0f;
+    
+    // Now we can free temp mid* arrays
+    free(midVertices);
+    free(midNormals);
+    free(midTexCoords);
+    
+    // NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct
+    TraceLog(INFO, "[%s] Model loaded successfully in RAM (CPU)", fileName);
+    
+    return vData;
 }
 }

+ 56 - 48
src/raylib.h

@@ -10,13 +10,17 @@
 *     Hardware accelerated with OpenGL (1.1, 3.3+ or ES2)
 *     Hardware accelerated with OpenGL (1.1, 3.3+ or ES2)
 *     Unique OpenGL abstraction layer [rlgl]
 *     Unique OpenGL abstraction layer [rlgl]
 *     Powerful fonts module with SpriteFonts support
 *     Powerful fonts module with SpriteFonts support
+*     Multiple textures support, including DDS and mipmaps generation
 *     Basic 3d support for Shapes, Models, Heightmaps and Billboards
 *     Basic 3d support for Shapes, Models, Heightmaps and Billboards
 *     Powerful math module for Vector and Matrix operations [raymath]
 *     Powerful math module for Vector and Matrix operations [raymath]
-*     Audio loading and playing
+*     Audio loading and playing with streaming support
 *    
 *    
 *   Used external libs:
 *   Used external libs:
 *     GLFW3 (www.glfw.org) for window/context management and input
 *     GLFW3 (www.glfw.org) for window/context management and input
+*     GLEW for OpenGL extensions loading (3.3+ and ES2)
 *     stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA, PSD, GIF, HDR, PIC)
 *     stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA, PSD, GIF, HDR, PIC)
+*     stb_image_write (Sean Barret) for image writting (PNG)
+*     stb_vorbis (Sean Barret) for ogg audio loading
 *     OpenAL Soft for audio device/context management
 *     OpenAL Soft for audio device/context management
 *     tinfl for data decompression (DEFLATE algorithm)
 *     tinfl for data decompression (DEFLATE algorithm)
 *
 *
@@ -25,9 +29,9 @@
 *     32bit Textures - All loaded images are converted automatically to RGBA textures
 *     32bit Textures - All loaded images are converted automatically to RGBA textures
 *     SpriteFonts - All loaded sprite-font images are converted to RGBA and POT textures
 *     SpriteFonts - All loaded sprite-font images are converted to RGBA and POT textures
 *     One custom default font is loaded automatically when InitWindow()
 *     One custom default font is loaded automatically when InitWindow()
-*     If using OpenGL 3.3+, one default shader is loaded automatically (internally defined)
+*     If using OpenGL 3.3+ or ES2, one default shader is loaded automatically (internally defined)
 *
 *
-*   -- LICENSE (raylib v1.1, March 2014) --
+*   -- LICENSE (raylib v1.1, April 2014) --
 *
 *
 *   raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, 
 *   raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, 
 *   BSD-like license that allows static linking with closed source software:
 *   BSD-like license that allows static linking with closed source software:
@@ -52,9 +56,7 @@
 **********************************************************************************************/
 **********************************************************************************************/
 
 
 #ifndef RAYLIB_H
 #ifndef RAYLIB_H
-#define RAYLIB_H 
-
-#include "stb_vorbis.h"
+#define RAYLIB_H
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Some basic Defines
 // Some basic Defines
@@ -195,30 +197,46 @@ typedef struct Image {
 // Texture2D type, bpp always RGBA (32bit)
 // Texture2D type, bpp always RGBA (32bit)
 // NOTE: Data stored in GPU memory
 // NOTE: Data stored in GPU memory
 typedef struct Texture2D {
 typedef struct Texture2D {
-    unsigned int glId;
+    unsigned int id;        // OpenGL id
     int width;
     int width;
     int height;
     int height;
 } Texture2D;
 } Texture2D;
 
 
-// Camera type, defines a camera position/orientation in 3d space
-typedef struct Camera {
-    Vector3 position;
-    Vector3 target;
-    Vector3 up;
-} Camera;
-
+// Character type (one font glyph)
+// NOTE: Defined in module: text
 typedef struct Character Character;
 typedef struct Character Character;
 
 
-// SpriteFont type
+// SpriteFont type, includes texture and charSet array data
 typedef struct SpriteFont {
 typedef struct SpriteFont {
     Texture2D texture;
     Texture2D texture;
     int numChars;
     int numChars;
     Character *charSet;
     Character *charSet;
 } SpriteFont;
 } SpriteFont;
 
 
+// Camera type, defines a camera position/orientation in 3d space
+typedef struct Camera {
+    Vector3 position;
+    Vector3 target;
+    Vector3 up;
+} Camera;
+
+// Vertex data definning a mesh
+typedef struct {
+    int vertexCount;
+    float *vertices;            // 3 components per vertex
+    float *texcoords;           // 2 components per vertex
+    float *normals;             // 3 components per vertex
+    float *colors;              // 4 components per vertex
+} VertexData;
+
 // 3d Model type
 // 3d Model type
-// NOTE: If using OpenGL 1.1 loaded in CPU; if OpenGL 3.3+ loaded in GPU
-typedef struct Model Model; // Defined in module: rlgl
+// NOTE: If using OpenGL 1.1 loaded in CPU (mesh); if OpenGL 3.3+ loaded in GPU (vaoId)
+typedef struct Model {
+    VertexData mesh;
+    unsigned int vaoId;
+    unsigned int textureId;
+    //Matrix transform;
+} Model;
 
 
 // Sound source type
 // Sound source type
 typedef struct Sound {
 typedef struct Sound {
@@ -226,23 +244,6 @@ typedef struct Sound {
     unsigned int buffer;
     unsigned int buffer;
 } Sound;
 } Sound;
 
 
-typedef struct OggStream OggStream;
-
-// Music type (streamming)
-typedef struct Music {
-    stb_vorbis *stream;
-	stb_vorbis_info info;
-    
-    unsigned int source;
-	unsigned int buffers[2];
-
-	int format;
- 
-	int bufferSize;
-	int totalSamplesLeft;
-	bool loop;
-} Music;
-
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {            // Prevents name mangling of functions
 extern "C" {            // Prevents name mangling of functions
 #endif
 #endif
@@ -342,7 +343,7 @@ Image LoadImage(const char *fileName);
 Image LoadImageFromRES(const char *rresName, int resId);                                           // Load an image from rRES file (raylib Resource)
 Image LoadImageFromRES(const char *rresName, int resId);                                           // Load an image from rRES file (raylib Resource)
 Texture2D LoadTexture(const char *fileName);                                                       // Load an image as texture into GPU memory
 Texture2D LoadTexture(const char *fileName);                                                       // Load an image as texture into GPU memory
 Texture2D LoadTextureFromRES(const char *rresName, int resId);                                     // Load an image as texture from rRES file (raylib Resource)
 Texture2D LoadTextureFromRES(const char *rresName, int resId);                                     // Load an image as texture from rRES file (raylib Resource)
-Texture2D CreateTexture(Image image);                                                              // Create a Texture2D from Image data
+Texture2D CreateTexture(Image image, bool genMipmaps);                                             // Create a Texture2D from Image data (and generate mipmaps)
 void UnloadImage(Image image);                                                                     // Unload image from CPU memory (RAM)
 void UnloadImage(Image image);                                                                     // Unload image from CPU memory (RAM)
 void UnloadTexture(Texture2D texture);                                                             // Unload texture from GPU memory
 void UnloadTexture(Texture2D texture);                                                             // Unload texture from GPU memory
 
 
@@ -359,6 +360,7 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V
 SpriteFont GetDefaultFont();                                                                       // Get the default SpriteFont
 SpriteFont GetDefaultFont();                                                                       // Get the default SpriteFont
 SpriteFont LoadSpriteFont(const char *fileName);                                                   // Load a SpriteFont image into GPU memory
 SpriteFont LoadSpriteFont(const char *fileName);                                                   // Load a SpriteFont image into GPU memory
 void UnloadSpriteFont(SpriteFont spriteFont);                                                      // Unload SpriteFont from GPU memory
 void UnloadSpriteFont(SpriteFont spriteFont);                                                      // Unload SpriteFont from GPU memory
+
 void DrawText(const char *text, int posX, int posY, int fontSize, Color color);                    // Draw text (using default font)
 void DrawText(const char *text, int posX, int posY, int fontSize, Color color);                    // Draw text (using default font)
 void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position,                         // Draw text using SpriteFont and additional parameters
 void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position,                         // Draw text using SpriteFont and additional parameters
                 int fontSize, int spacing, Color tint);
                 int fontSize, int spacing, Color tint);
@@ -384,7 +386,7 @@ void DrawPlane(Vector3 centerPos, Vector2 size, Vector3 rotation, Color color);
 void DrawPlaneEx(Vector3 centerPos, Vector2 size, Vector3 rotation, int slicesX, int slicesZ, Color color); // Draw a plane with divisions
 void DrawPlaneEx(Vector3 centerPos, Vector2 size, Vector3 rotation, int slicesX, int slicesZ, Color color); // Draw a plane with divisions
 void DrawGrid(int slices, float spacing);                                                          // Draw a grid (centered at (0, 0, 0))
 void DrawGrid(int slices, float spacing);                                                          // Draw a grid (centered at (0, 0, 0))
 void DrawGizmo(Vector3 position);                                                                  // Draw simple gizmo
 void DrawGizmo(Vector3 position);                                                                  // Draw simple gizmo
-void DrawGizmoEx(Vector3 position, Vector3 rot, float scale, bool orbits);                    // Draw gizmo with extended parameters
+void DrawGizmoEx(Vector3 position, Vector3 rotation, float scale);                                 // Draw gizmo with extended parameters
 //DrawTorus(), DrawTeapot() are useless...
 //DrawTorus(), DrawTeapot() are useless...
 
 
 //------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------
@@ -394,9 +396,12 @@ Model LoadModel(const char *fileName);
 //Model LoadModelFromRES(const char *rresName, int resId);                                         // TODO: Load a 3d model from rRES file (raylib Resource)
 //Model LoadModelFromRES(const char *rresName, int resId);                                         // TODO: Load a 3d model from rRES file (raylib Resource)
 Model LoadHeightmap(Image heightmap, float maxHeight);                                             // Load a heightmap image as a 3d model
 Model LoadHeightmap(Image heightmap, float maxHeight);                                             // Load a heightmap image as a 3d model
 void UnloadModel(Model model);                                                                     // Unload 3d model from memory
 void UnloadModel(Model model);                                                                     // Unload 3d model from memory
-void DrawModel(Model model, Vector3 position, float scale, Color color);                           // Draw a model
-void DrawModelEx(Model model, Texture2D texture, Vector3 position, float scale, Color tint);       // Draw a textured model
-void DrawModelWires(Model model, Vector3 position, float scale, Color color);                      // Draw a model wires
+void SetModelTexture(Model *model, Texture2D texture);                                             // Link a texture to a model
+
+void DrawModel(Model model, Vector3 position, float scale, Color tint);                            // Draw a model (with texture if set)
+void DrawModelEx(Model model, Vector3 position, Vector3 rotation, Vector3 scale, Color tint);      // Draw a model with extended parameters
+void DrawModelWires(Model model, Vector3 position, float scale, Color color);                      // Draw a model wires (with texture if set)
+
 void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint);                         // Draw a billboard texture
 void DrawBillboard(Camera camera, Texture2D texture, Vector3 center, float size, Color tint);                         // Draw a billboard texture
 void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec 
 void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 center, float size, Color tint); // Draw a billboard texture defined by sourceRec 
 
 
@@ -404,22 +409,25 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vec
 // Audio Loading and Playing Functions (Module: audio)
 // Audio Loading and Playing Functions (Module: audio)
 //------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------
 void InitAudioDevice();                                         // Initialize audio device and context
 void InitAudioDevice();                                         // Initialize audio device and context
-void CloseAudioDevice();                                        // Close the audio device and context
+void CloseAudioDevice();                                        // Close the audio device and context (and music stream)
+
 Sound LoadSound(char *fileName);                                // Load sound to memory
 Sound LoadSound(char *fileName);                                // Load sound to memory
 Sound LoadSoundFromRES(const char *rresName, int resId);        // Load sound to memory from rRES file (raylib Resource)
 Sound LoadSoundFromRES(const char *rresName, int resId);        // Load sound to memory from rRES file (raylib Resource)
 void UnloadSound(Sound sound);                                  // Unload sound
 void UnloadSound(Sound sound);                                  // Unload sound
-Music LoadMusic(char *fileName);
-void UnloadMusic(Music music);
-
 void PlaySound(Sound sound);                                    // Play a sound
 void PlaySound(Sound sound);                                    // Play a sound
 void PauseSound(Sound sound);                                   // Pause a sound
 void PauseSound(Sound sound);                                   // Pause a sound
 void StopSound(Sound sound);                                    // Stop playing a sound
 void StopSound(Sound sound);                                    // Stop playing a sound
 bool SoundIsPlaying(Sound sound);                               // Check if a sound is currently playing
 bool SoundIsPlaying(Sound sound);                               // Check if a sound is currently playing
-void SetVolume(Sound sound, float volume);                      // Set volume for a sound (1.0 is base level)
-void SetPitch(Sound sound, float pitch);                        // Set pitch for a sound (1.0 is base level)
-void PlayMusic(Music music);
-void StopMusic(Music music);
-bool MusicIsPlaying();
+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)
+void StopMusicStream();                                         // Stop music playing (close stream)
+void PauseMusicStream();                                        // Pause music playing
+bool MusicIsPlaying();                                          // Check if music is playing
+void SetMusicVolume(float volume);                              // Set volume for music (1.0 is max level)
+float GetMusicTimeLength();                                     // Get current music time length (in seconds)
+float GetMusicTimePlayed();                                     // Get current music time played (in seconds)
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 20 - 2
src/raymath.c

@@ -435,7 +435,7 @@ Matrix MatrixSubstract(Matrix left, Matrix right)
 }
 }
 
 
 // Returns translation matrix
 // Returns translation matrix
-// TODO: REVIEW
+// TODO: Review this function
 Matrix MatrixTranslate(float x, float y, float z)
 Matrix MatrixTranslate(float x, float y, float z)
 {
 {
 /*
 /*
@@ -478,6 +478,7 @@ Matrix MatrixTranslate(float x, float y, float z)
 }
 }
 
 
 // Returns rotation matrix
 // Returns rotation matrix
+// TODO: Review this function
 Matrix MatrixRotate(float angleX, float angleY, float angleZ)
 Matrix MatrixRotate(float angleX, float angleY, float angleZ)
 {
 {
     Matrix result;
     Matrix result;
@@ -492,6 +493,7 @@ Matrix MatrixRotate(float angleX, float angleY, float angleZ)
 }
 }
 
 
 // Create rotation matrix from axis and angle
 // Create rotation matrix from axis and angle
+// TODO: Test this function
 Matrix MatrixFromAxisAngle(Vector3 axis, float angle) 
 Matrix MatrixFromAxisAngle(Vector3 axis, float angle) 
 {
 {
     Matrix result;
     Matrix result;
@@ -545,7 +547,8 @@ Matrix MatrixFromAxisAngle(Vector3 axis, float angle)
     return result;
     return result;
 };
 };
 
 
-// Create rotation matrix from axis and angle
+// Create rotation matrix from axis and angle (version 2)
+// TODO: Test this function
 Matrix MatrixFromAxisAngle2(Vector3 axis, float angle)
 Matrix MatrixFromAxisAngle2(Vector3 axis, float angle)
 {
 {
     Matrix result;
     Matrix result;
@@ -661,6 +664,21 @@ Matrix MatrixScale(float x, float y, float z)
     return result;
     return result;
 }
 }
 
 
+// Returns transformation matrix for a given translation, rotation and scale
+// NOTE: Transformation order is rotation -> scale -> translation
+Matrix MatrixTransform(Vector3 translation, Vector3 rotation, Vector3 scale)
+{
+    Matrix result = MatrixIdentity();
+    
+    Matrix mRotation = MatrixRotate(rotation.x, rotation.y, rotation.z);
+    Matrix mScale = MatrixScale(scale.x, scale.y, scale.z);
+    Matrix mTranslate = MatrixTranslate(translation.x, translation.y, translation.z);
+
+    result = MatrixMultiply(MatrixMultiply(mRotation, mScale), mTranslate);
+
+    return result;
+}
+
 // Returns two matrix multiplication
 // Returns two matrix multiplication
 // NOTE: When multiplying matrices... the order matters!
 // NOTE: When multiplying matrices... the order matters!
 Matrix MatrixMultiply(Matrix left, Matrix right)
 Matrix MatrixMultiply(Matrix left, Matrix right)

+ 1 - 0
src/raymath.h

@@ -115,6 +115,7 @@ Matrix MatrixRotateX(float angle);                      // Returns x-rotation ma
 Matrix MatrixRotateY(float angle);                      // Returns y-rotation matrix (angle in radians)
 Matrix MatrixRotateY(float angle);                      // Returns y-rotation matrix (angle in radians)
 Matrix MatrixRotateZ(float angle);                      // Returns z-rotation matrix (angle in radians)
 Matrix MatrixRotateZ(float angle);                      // Returns z-rotation matrix (angle in radians)
 Matrix MatrixScale(float x, float y, float z);          // Returns scaling matrix
 Matrix MatrixScale(float x, float y, float z);          // Returns scaling matrix
+Matrix MatrixTransform(Vector3 translation, Vector3 rotation, Vector3 scale);   // Returns transformation matrix for a given translation, rotation and scale
 Matrix MatrixMultiply(Matrix left, Matrix right);       // Returns two matrix multiplication
 Matrix MatrixMultiply(Matrix left, Matrix right);       // Returns two matrix multiplication
 Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far);  // Returns perspective projection matrix
 Matrix MatrixFrustum(double left, double right, double bottom, double top, double near, double far);  // Returns perspective projection matrix
 Matrix MatrixPerspective(double fovy, double aspect, double near, double far);                        // Returns perspective projection matrix
 Matrix MatrixPerspective(double fovy, double aspect, double near, double far);                        // Returns perspective projection matrix

+ 359 - 114
src/rlgl.c

@@ -31,10 +31,24 @@
 #include <stdio.h>          // Standard input / output lib
 #include <stdio.h>          // Standard input / output lib
 #include <stdlib.h>         // Declares malloc() and free() for memory management, rand()
 #include <stdlib.h>         // Declares malloc() and free() for memory management, rand()
 
 
-// TODO: Security check in case multiple USE_OPENGL_* defined
+// Security check in case no USE_OPENGL_* defined
+#if !defined(USE_OPENGL_11) && !defined(USE_OPENGL_33) && !defined(USE_OPENGL_ES2)
+    #define USE_OPENGL_11
+#endif
+
+// Security check in case multiple USE_OPENGL_* defined
+#ifdef USE_OPENGL_11
+    #ifdef USE_OPENGL_33
+        #undef USE_OPENGL_33
+    #endif
+    
+    #ifdef USE_OPENGL_ES2
+        #undef USE_OPENGL_ES2
+    #endif   
+#endif
 
 
 #ifdef USE_OPENGL_11
 #ifdef USE_OPENGL_11
-    #include <GL/gl.h>      // Extensions loading lib
+    #include <GL/gl.h>      // Basic OpenGL include
 #endif
 #endif
 
 
 #ifdef USE_OPENGL_33
 #ifdef USE_OPENGL_33
@@ -42,7 +56,7 @@
     #include <GL/glew.h>    // Extensions loading lib
     #include <GL/glew.h>    // Extensions loading lib
 #endif
 #endif
 
 
-//#include "glad.h"         // Extensions loading lib? --> REVIEW
+//#include "glad.h"         // Other extensions loading lib? --> REVIEW
 
 
 #define USE_VBO_DOUBLE_BUFFERS    // Enable VBO double buffers usage --> REVIEW!
 #define USE_VBO_DOUBLE_BUFFERS    // Enable VBO double buffers usage --> REVIEW!
 
 
@@ -56,18 +70,18 @@
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
-typedef struct {
-    int numQuads;
-    int texId;
-} QuadsByTexture;
 
 
+// Vertex buffer (position + color arrays)
+// NOTE: Used for lines and triangles VAOs
 typedef struct {
 typedef struct {
     int vCounter;
     int vCounter;
     int cCounter;
     int cCounter;
     float *vertices;            // 3 components per vertex
     float *vertices;            // 3 components per vertex
     float *colors;              // 4 components per vertex
     float *colors;              // 4 components per vertex
 } VertexPositionColorBuffer;
 } VertexPositionColorBuffer;
-/*
+
+// Vertex buffer (position + texcoords + color arrays)
+// NOTE: Not used
 typedef struct {
 typedef struct {
     int vCounter;
     int vCounter;
     int tcCounter;
     int tcCounter;
@@ -76,8 +90,9 @@ typedef struct {
     float *texcoords;           // 2 components per vertex
     float *texcoords;           // 2 components per vertex
     float *colors;              // 4 components per vertex
     float *colors;              // 4 components per vertex
 } VertexPositionColorTextureBuffer;
 } VertexPositionColorTextureBuffer;
-*/
-/*
+
+// Vertex buffer (position + texcoords + normals arrays)
+// NOTE: Not used
 typedef struct {
 typedef struct {
     int vCounter;
     int vCounter;
     int tcCounter;
     int tcCounter;
@@ -86,7 +101,9 @@ typedef struct {
     float *texcoords;           // 2 components per vertex
     float *texcoords;           // 2 components per vertex
     float *normals;             // 3 components per vertex
     float *normals;             // 3 components per vertex
 } VertexPositionTextureNormalBuffer;
 } VertexPositionTextureNormalBuffer;
-*/
+
+// Vertex buffer (position + texcoords + colors + indices arrays)
+// NOTE: Used for quads VAO
 typedef struct {
 typedef struct {
     int vCounter;
     int vCounter;
     int tcCounter;
     int tcCounter;
@@ -97,12 +114,22 @@ typedef struct {
     unsigned int *indices;      // 6 indices per quad
     unsigned int *indices;      // 6 indices per quad
 } VertexPositionColorTextureIndexBuffer;
 } VertexPositionColorTextureIndexBuffer;
 
 
+// Draw call type
+// NOTE: Used to track required draw-calls, organized by texture
 typedef struct {
 typedef struct {
-    GLuint texId;
-    int firstVertex;    // Actually, when using glDrawElements, this parameter is useless..
-    int vCount;
+    GLuint textureId;
+    int vertexCount;
 } DrawCall;
 } DrawCall;
 
 
+// pixel type (same as Color type)
+// NOTE: Used exclusively in mipmap generation functions
+typedef struct {
+    unsigned char r;
+    unsigned char g;
+    unsigned char b;
+    unsigned char a;
+} pixel;
+
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 // Global Variables Definition
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
@@ -140,7 +167,6 @@ static GLuint quadsBuffer[4];
 
 
 #ifdef USE_VBO_DOUBLE_BUFFERS
 #ifdef USE_VBO_DOUBLE_BUFFERS
 // Double buffering
 // Double buffering
-// TODO: REVIEW -> Not getting any performance improvement... why?
 static GLuint vaoQuadsB;
 static GLuint vaoQuadsB;
 static GLuint quadsBufferB[4];
 static GLuint quadsBufferB[4];
 static bool useBufferB = false;
 static bool useBufferB = false;
@@ -172,6 +198,11 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName);
 static char *TextFileRead(char *fn);
 static char *TextFileRead(char *fn);
 #endif
 #endif
 
 
+#ifdef USE_OPENGL_11
+static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight);
+static pixel *GenNextMipmap(pixel *srcData, int srcWidth, int srcHeight);
+#endif
+
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Module Functions Definition - Matrix operations
 // Module Functions Definition - Matrix operations
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
@@ -216,7 +247,7 @@ void rlMatrixMode(int mode)
 {
 {
     if (mode == RL_PROJECTION) currentMatrix = &projection;
     if (mode == RL_PROJECTION) currentMatrix = &projection;
     else if (mode == RL_MODELVIEW) currentMatrix = &modelview;
     else if (mode == RL_MODELVIEW) currentMatrix = &modelview;
-    //else if (mode == GL_TEXTURE) TODO: NEVER USED!
+    //else if (mode == RL_TEXTURE) // Not supported
     
     
     currentMatrixMode = mode;
     currentMatrixMode = mode;
 }
 }
@@ -257,6 +288,7 @@ void rlLoadIdentity()
 void rlTranslatef(float x, float y, float z)
 void rlTranslatef(float x, float y, float z)
 {
 {
     Matrix mat = MatrixTranslate(x, y, z);
     Matrix mat = MatrixTranslate(x, y, z);
+    MatrixTranspose(&mat);
     
     
     *currentMatrix = MatrixMultiply(*currentMatrix, mat);
     *currentMatrix = MatrixMultiply(*currentMatrix, mat);
 }
 }
@@ -264,13 +296,15 @@ void rlTranslatef(float x, float y, float z)
 // Multiply the current matrix by a rotation matrix
 // Multiply the current matrix by a rotation matrix
 void rlRotatef(float angleDeg, float x, float y, float z)
 void rlRotatef(float angleDeg, float x, float y, float z)
 {
 {
-    // TODO: Rotation matrix --> REVIEW!
+    // TODO: Support rotation in multiple axes
     Matrix rot = MatrixIdentity();
     Matrix rot = MatrixIdentity();
     
     
     if (x == 1) rot = MatrixRotateX(angleDeg*DEG2RAD);
     if (x == 1) rot = MatrixRotateX(angleDeg*DEG2RAD);
     else if (y == 1) rot = MatrixRotateY(angleDeg*DEG2RAD);
     else if (y == 1) rot = MatrixRotateY(angleDeg*DEG2RAD);
     else if (z == 1) rot = MatrixRotateZ(angleDeg*DEG2RAD);
     else if (z == 1) rot = MatrixRotateZ(angleDeg*DEG2RAD);
     
     
+    MatrixTranspose(&rot);
+    
     *currentMatrix = MatrixMultiply(*currentMatrix, rot);
     *currentMatrix = MatrixMultiply(*currentMatrix, rot);
 }
 }
 
 
@@ -278,6 +312,7 @@ void rlRotatef(float angleDeg, float x, float y, float z)
 void rlScalef(float x, float y, float z)
 void rlScalef(float x, float y, float z)
 {
 {
     Matrix mat = MatrixScale(x, y, z);
     Matrix mat = MatrixScale(x, y, z);
+    MatrixTranspose(&mat);
     
     
     *currentMatrix = MatrixMultiply(*currentMatrix, mat);
     *currentMatrix = MatrixMultiply(*currentMatrix, mat);
 }
 }
@@ -356,12 +391,12 @@ void rlEnd()
 {
 {
     if (useTempBuffer)
     if (useTempBuffer)
     {
     {
-        // IT WORKS!!! --> Refactor...
-        Matrix mat = *currentMatrix;
-        MatrixTranspose(&mat);
+        // NOTE: In this case, *currentMatrix is already transposed because transposing has been applied
+        // independently to translation-scale-rotation matrices -> t(M1 x M2) = t(M2) x t(M1)
+        // This way, rlTranslatef(), rlRotatef()... behaviour is the same than OpenGL 1.1
 
 
         // Apply transformation matrix to all temp vertices
         // Apply transformation matrix to all temp vertices
-        for (int i = 0; i < tempBufferCount; i++) VectorTransform(&tempBuffer[i], mat);
+        for (int i = 0; i < tempBufferCount; i++) VectorTransform(&tempBuffer[i], *currentMatrix);
         
         
         // Deactivate tempBuffer usage to allow rlVertex3f do its job
         // Deactivate tempBuffer usage to allow rlVertex3f do its job
         useTempBuffer = false;
         useTempBuffer = false;
@@ -373,7 +408,7 @@ void rlEnd()
         tempBufferCount = 0;
         tempBufferCount = 0;
     }
     }
 
 
-    // Make sure vertexCounter is the same for vertices-texcoords-normals-colors
+    // Make sure vertexCount is the same for vertices-texcoords-normals-colors
     // NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls.
     // NOTE: In OpenGL 1.1, one glColor call can be made for all the subsequent glVertex calls.
     switch (currentDrawMode)
     switch (currentDrawMode)
     {
     {
@@ -490,7 +525,7 @@ void rlVertex3f(float x, float y, float z)
                 
                 
                 quads.vCounter++;
                 quads.vCounter++;
                 
                 
-                draws[drawsCounter - 1].vCount++;
+                draws[drawsCounter - 1].vertexCount++;
                 
                 
             } break;
             } break;
             default: break;
             default: break;
@@ -596,13 +631,12 @@ void rlEnableTexture(unsigned int id)
 #endif
 #endif
 
 
 #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
 #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
-    if (draws[drawsCounter - 1].texId != id)
+    if (draws[drawsCounter - 1].textureId != id)
     {
     {
-        if (draws[drawsCounter - 1].vCount > 0) drawsCounter++;
+        if (draws[drawsCounter - 1].vertexCount > 0) drawsCounter++;
         
         
-        draws[drawsCounter - 1].texId = id;
-        draws[drawsCounter - 1].firstVertex = draws[drawsCounter - 2].vCount;
-        draws[drawsCounter - 1].vCount = 0;
+        draws[drawsCounter - 1].textureId = id;
+        draws[drawsCounter - 1].vertexCount = 0;
     }
     }
 #endif
 #endif
 }
 }
@@ -708,9 +742,7 @@ void rlglInit()
     projectionMatrixLoc = glGetUniformLocation(shaderProgram, "projectionMatrix");
     projectionMatrixLoc = glGetUniformLocation(shaderProgram, "projectionMatrix");
     
     
     // Get handles to GLSL uniform vars locations (fragment-shader)
     // Get handles to GLSL uniform vars locations (fragment-shader)
-    textureLoc  = glGetUniformLocation(shaderProgram, "texture0");
-    
-    TraceLog(INFO, "Default shader loaded");
+    textureLoc = glGetUniformLocation(shaderProgram, "texture0");
     
     
     InitializeBuffers();    // Init vertex arrays
     InitializeBuffers();    // Init vertex arrays
     InitializeVAOs();       // Init VBO and VAO
     InitializeVAOs();       // Init VBO and VAO
@@ -723,9 +755,9 @@ void rlglInit()
     // Create default white texture for plain colors (required by shader)
     // Create default white texture for plain colors (required by shader)
     unsigned char pixels[4] = { 255, 255, 255, 255 };   // 1 pixel RGBA (4 bytes)
     unsigned char pixels[4] = { 255, 255, 255, 255 };   // 1 pixel RGBA (4 bytes)
     
     
-    whiteTexture = rlglLoadTexture(1, 1, pixels);
+    whiteTexture = rlglLoadTexture(pixels, 1, 1, false);
     
     
-    if (whiteTexture != 0) TraceLog(INFO, "Base white texture successfully created, id: %i", whiteTexture);
+    if (whiteTexture != 0) TraceLog(INFO, "[ID %i] Base white texture created successfully", whiteTexture);
     else TraceLog(WARNING, "Base white texture could not be created");
     else TraceLog(WARNING, "Base white texture could not be created");
     
     
     // Init draw calls tracking system
     // Init draw calls tracking system
@@ -733,13 +765,12 @@ void rlglInit()
     
     
     for (int i = 0; i < MAX_DRAWS_BY_TEXTURE; i++)
     for (int i = 0; i < MAX_DRAWS_BY_TEXTURE; i++)
     {
     {
-        draws[i].texId = 0;
-        draws[i].firstVertex = 0;
-        draws[i].vCount = 0;
+        draws[i].textureId = 0;
+        draws[i].vertexCount = 0;
     }
     }
     
     
     drawsCounter = 1;
     drawsCounter = 1;
-    draws[drawsCounter - 1].texId = whiteTexture;
+    draws[drawsCounter - 1].textureId = whiteTexture;
 }
 }
 
 
 // Vertex Buffer Object deinitialization (memory free)
 // Vertex Buffer Object deinitialization (memory free)
@@ -789,6 +820,8 @@ void rlglClose()
     
     
     // Free GPU texture
     // Free GPU texture
     glDeleteTextures(1, &whiteTexture);
     glDeleteTextures(1, &whiteTexture);
+    
+    free(draws);
 }
 }
 
 
 void rlglDraw()
 void rlglDraw()
@@ -823,7 +856,7 @@ void rlglDraw()
     
     
     if (quads.vCounter > 0)
     if (quads.vCounter > 0)
     {
     {
-        int numQuads = 0;
+        int quadsCount = 0;
         int numIndicesToProcess = 0;
         int numIndicesToProcess = 0;
         int indicesOffset = 0;
         int indicesOffset = 0;
 
 
@@ -836,21 +869,21 @@ void rlglDraw()
             glBindVertexArray(vaoQuads);
             glBindVertexArray(vaoQuads);
         }
         }
         
         
-        //TraceLog(INFO, "Draws required per frame: %i", drawsCounter);
+        //TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter);
      
      
         for (int i = 0; i < drawsCounter; i++)
         for (int i = 0; i < drawsCounter; i++)
         {
         {
-            numQuads = draws[i].vCount/4;
-            numIndicesToProcess = numQuads*6;  // Get number of Quads * 6 index by Quad
+            quadsCount = draws[i].vertexCount/4;
+            numIndicesToProcess = quadsCount*6;  // Get number of Quads * 6 index by Quad
             
             
-            //TraceLog(INFO, "Quads to render: %i - Vertex Count: %i", numQuads, draws[i].vCount);
+            //TraceLog(DEBUG, "Quads to render: %i - Vertex Count: %i", quadsCount, draws[i].vertexCount);
 
 
-            glBindTexture(GL_TEXTURE_2D, draws[i].texId);
+            glBindTexture(GL_TEXTURE_2D, draws[i].textureId);
             
             
             // NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process
             // NOTE: The final parameter tells the GPU the offset in bytes from the start of the index buffer to the location of the first index to process
             glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid*) (sizeof(GLuint) * indicesOffset));
             glDrawElements(GL_TRIANGLES, numIndicesToProcess, GL_UNSIGNED_INT, (GLvoid*) (sizeof(GLuint) * indicesOffset));
 
 
-            indicesOffset += draws[i].vCount/4*6;
+            indicesOffset += draws[i].vertexCount/4*6;
         }
         }
     }
     }
     
     
@@ -859,9 +892,8 @@ void rlglDraw()
     
     
     // Reset draws counter
     // Reset draws counter
     drawsCounter = 1;
     drawsCounter = 1;
-    draws[0].texId = whiteTexture;
-    draws[0].firstVertex = 0;
-    draws[0].vCount = 0;
+    draws[0].textureId = whiteTexture;
+    draws[0].vertexCount = 0;
     
     
     // Reset vertex counters for next frame
     // Reset vertex counters for next frame
     lines.vCounter = 0;
     lines.vCounter = 0;
@@ -883,52 +915,71 @@ void rlglDraw()
 #endif      // End for OpenGL 3.3+ and ES2 only functions
 #endif      // End for OpenGL 3.3+ and ES2 only functions
 
 
 // Draw a 3d model
 // Draw a 3d model
-void rlglDrawModel(Model model, Vector3 position, float scale, bool wires)
+void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scale, Color color, bool wires)
 {
 {
     if (wires) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
     if (wires) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
     
     
 #ifdef USE_OPENGL_11
 #ifdef USE_OPENGL_11
-    // NOTE: For models we use Vertex Arrays (OpenGL 1.1)
+    glEnable(GL_TEXTURE_2D);
+    glBindTexture(GL_TEXTURE_2D, model.textureId);
+
+    // NOTE: On OpenGL 1.1 we use Vertex Arrays to draw model
     glEnableClientState(GL_VERTEX_ARRAY);                     // Enable vertex array
     glEnableClientState(GL_VERTEX_ARRAY);                     // Enable vertex array
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);              // Enable texture coords array
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);              // Enable texture coords array
     glEnableClientState(GL_NORMAL_ARRAY);                     // Enable normals array
     glEnableClientState(GL_NORMAL_ARRAY);                     // Enable normals array
         
         
-    glVertexPointer(3, GL_FLOAT, 0, model.data.vertices);     // Pointer to vertex coords array
-    glTexCoordPointer(2, GL_FLOAT, 0, model.data.texcoords);  // Pointer to texture coords array
-    glNormalPointer(GL_FLOAT, 0, model.data.normals);         // Pointer to normals array
+    glVertexPointer(3, GL_FLOAT, 0, model.mesh.vertices);     // Pointer to vertex coords array
+    glTexCoordPointer(2, GL_FLOAT, 0, model.mesh.texcoords);  // Pointer to texture coords array
+    glNormalPointer(GL_FLOAT, 0, model.mesh.normals);         // Pointer to normals array
     //glColorPointer(4, GL_UNSIGNED_BYTE, 0, model.colors);   // Pointer to colors array (NOT USED)
     //glColorPointer(4, GL_UNSIGNED_BYTE, 0, model.colors);   // Pointer to colors array (NOT USED)
-        
+    
+    //TraceLog(DEBUG, "Drawing model.mesh, VertexCount: %i", model.mesh.vertexCount);
+    
     rlPushMatrix();
     rlPushMatrix();
         rlTranslatef(position.x, position.y, position.z);
         rlTranslatef(position.x, position.y, position.z);
-        //rlRotatef(rotation * GetFrameTime(), 0, 1, 0);
-        rlScalef(scale, scale, scale);
+        rlScalef(scale.x, scale.y, scale.z);
+        //rlRotatef(rotation, 0, 1, 0);
         
         
-        rlColor4ub(1.0f, 1.0f, 1.0f, 1.0f);
+        // TODO: If rotate in multiple axis, get rotation matrix and use rlMultMatrix()
+
+        rlColor4ub(color.r, color.g, color.b, color.a);
 
 
-        glDrawArrays(GL_TRIANGLES, 0, model.data.numVertices);
+        glDrawArrays(GL_TRIANGLES, 0, model.mesh.vertexCount);
     rlPopMatrix();
     rlPopMatrix();
     
     
     glDisableClientState(GL_VERTEX_ARRAY);                     // Disable vertex array
     glDisableClientState(GL_VERTEX_ARRAY);                     // Disable vertex array
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);              // Disable texture coords array
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);              // Disable texture coords array
     glDisableClientState(GL_NORMAL_ARRAY);                     // Disable normals array
     glDisableClientState(GL_NORMAL_ARRAY);                     // Disable normals array
+    
+    glDisable(GL_TEXTURE_2D);
+    glBindTexture(GL_TEXTURE_2D, 0);
 #endif
 #endif
 
 
 #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
 #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
     glUseProgram(shaderProgram);        // Use our shader
     glUseProgram(shaderProgram);        // Use our shader
     
     
-    Matrix modelview2 = MatrixMultiply(model.transform, modelview);
+    // Get transform matrix (rotation -> scale -> translation)
+    Matrix transform = MatrixTransform(position, rotation, scale);
+    Matrix modelviewworld = MatrixMultiply(transform, modelview);
     
     
     // NOTE: Drawing in OpenGL 3.3+, transform is passed to shader
     // NOTE: Drawing in OpenGL 3.3+, transform is passed to shader
     glUniformMatrix4fv(projectionMatrixLoc, 1, false, GetMatrixVector(projection));
     glUniformMatrix4fv(projectionMatrixLoc, 1, false, GetMatrixVector(projection));
-    glUniformMatrix4fv(modelviewMatrixLoc, 1, false, GetMatrixVector(modelview2));
+    glUniformMatrix4fv(modelviewMatrixLoc, 1, false, GetMatrixVector(modelviewworld));
     glUniform1i(textureLoc, 0);
     glUniform1i(textureLoc, 0);
+    
+    //TraceLog(DEBUG, "ShaderProgram: %i, VAO ID: %i, VertexCount: %i", shaderProgram, model.vaoId, model.mesh.vertexCount);
    
    
     glBindVertexArray(model.vaoId);
     glBindVertexArray(model.vaoId);
-    //glBindTexture(GL_TEXTURE_2D, model.textureId);
+    
+    // TODO: Update vertex color
+    glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]);
+    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*4*model.mesh.vertexCount, model.mesh.colors);
+    
+    glBindTexture(GL_TEXTURE_2D, model.textureId);
 
 
-    glDrawArrays(GL_TRIANGLES, 0, model.numVertices);
+    glDrawArrays(GL_TRIANGLES, 0, model.mesh.vertexCount);
 
 
-    //glBindTexture(GL_TEXTURE_2D, 0);    // Unbind textures
+    glBindTexture(GL_TEXTURE_2D, 0);    // Unbind textures
     glBindVertexArray(0);               // Unbind VAO
     glBindVertexArray(0);               // Unbind VAO
 #endif
 #endif
 
 
@@ -982,8 +1033,7 @@ void rlglInitGraphicsDevice(int fbWidth, int fbHeight)
 }
 }
 
 
 // Convert image data to OpenGL texture (returns OpenGL valid Id)
 // Convert image data to OpenGL texture (returns OpenGL valid Id)
-// NOTE: Image is not unloaded, it should be done manually...
-unsigned int rlglLoadTexture(int width, int height, unsigned char *data)
+unsigned int rlglLoadTexture(unsigned char *data, int width, int height, bool genMipmaps)
 {
 {
     glBindTexture(GL_TEXTURE_2D,0); // Free any old binding
     glBindTexture(GL_TEXTURE_2D,0); // Free any old binding
 
 
@@ -996,27 +1046,82 @@ unsigned int rlglLoadTexture(int width, int height, unsigned char *data)
     // NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used!
     // NOTE: glTexParameteri does NOT affect texture uploading, just the way it's used!
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);       // Set texture to repead on x-axis
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);       // Set texture to repead on x-axis
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);       // Set texture to repead on y-axis
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);       // Set texture to repead on y-axis
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  // Filter for pixel-perfect drawing, alternative: GL_LINEAR 
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  // Filter for pixel-perfect drawing, alternative: GL_LINEAR
- 
-#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
-    // Trilinear filtering
-    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);   // Activate use of mipmaps (must be available)
-    //glGenerateMipmap(GL_TEXTURE_2D);    // OpenGL 3.3!
-#endif  
 
 
-    // NOTE: Not using mipmappings (texture for 2D drawing)
-    // At this point we have the image converted to texture and uploaded to GPU
+    bool texIsPOT = false;
     
     
+    // Check if width and height are power-of-two (POT)
+    if (((width > 0) && ((width & (width - 1)) == 0)) && ((height > 0) && ((height & (height - 1)) == 0))) texIsPOT = true;
+    
+    if (!texIsPOT)
+    {
+        TraceLog(WARNING, "[ID %i] Texture is not power-of-two, mipmaps can not be generated", id);
+        
+        genMipmaps = false;
+    }
+    
+    // If mipmaps are being used, we configure mag-min filters accordingly
+    if (genMipmaps)
+    {
+        // Trilinear filtering with mipmaps
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);   // Activate use of mipmaps (must be available)
+    }
+    else
+    {
+        // Not using mipmappings
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  // Filter for pixel-perfect drawing, alternative: GL_LINEAR 
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  // Filter for pixel-perfect drawing, alternative: GL_LINEAR
+    }
+
+#ifdef USE_OPENGL_11
+    if (genMipmaps)
+    {
+        TraceLog(WARNING, "[ID %i] Mipmaps generated manually on CPU side", id);
+
+        // Compute required mipmaps
+        // NOTE: data size is reallocated to fit mipmaps data
+        int mipmapCount = GenerateMipmaps(data, width, height);
+
+        int offset = 0;
+        int size = 0;
+        
+        int mipWidth = width;
+        int mipHeight = height;
+        
+        // Load the mipmaps       
+        for (int level = 0; level < mipmapCount; level++)
+        {
+            glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA8, mipWidth, mipHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, data + offset);
+            
+            size = mipWidth*mipHeight*4;
+            offset += size;
+            
+            mipWidth /= 2;
+            mipHeight /= 2;
+        }
+    }
+    else glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+#endif
+
+
+#if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
     
     
+    if (genMipmaps)
+    {
+        glGenerateMipmap(GL_TEXTURE_2D);  // Generate mipmaps automatically
+        TraceLog(INFO, "[ID %i] Mipmaps generated automatically for new texture", id);
+    }
+    
+#endif
+
     // At this point we have the image converted to texture and uploaded to GPU
     // At this point we have the image converted to texture and uploaded to GPU
     
     
     // Unbind current texture
     // Unbind current texture
     glBindTexture(GL_TEXTURE_2D, 0);
     glBindTexture(GL_TEXTURE_2D, 0);
     
     
-    TraceLog(INFO, "New texture created, id: %i (%i x %i)", id, width, height);
+    TraceLog(INFO, "[ID %i] New texture created (%i x %i)", id, width, height);
     
     
     return id;
     return id;
 }
 }
@@ -1024,51 +1129,42 @@ unsigned int rlglLoadTexture(int width, int height, unsigned char *data)
 
 
 #ifdef USE_OPENGL_33
 #ifdef USE_OPENGL_33
 
 
-#define FOURCC_DXT1 0x31545844 // Equivalent to "DXT1" in ASCII
-#define FOURCC_DXT3 0x33545844 // Equivalent to "DXT3" in ASCII
-#define FOURCC_DXT5 0x35545844 // Equivalent to "DXT5" in ASCII
-
 // Convert image data to OpenGL texture (returns OpenGL valid Id)
 // Convert image data to OpenGL texture (returns OpenGL valid Id)
-// NOTE: Expected compressed data from DDS file
-unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int format)
+// NOTE: Expected compressed image data and POT image
+unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int compFormat)
 {
 {
     // Create one OpenGL texture
     // Create one OpenGL texture
     GLuint id;
     GLuint id;
-    int compFormat = 0;
+    
+    glGenTextures(1, &id);
     
     
     TraceLog(DEBUG, "Compressed texture width: %i", width);
     TraceLog(DEBUG, "Compressed texture width: %i", width);
     TraceLog(DEBUG, "Compressed texture height: %i", height);
     TraceLog(DEBUG, "Compressed texture height: %i", height);
     TraceLog(DEBUG, "Compressed texture mipmap levels: %i", mipmapCount);
     TraceLog(DEBUG, "Compressed texture mipmap levels: %i", mipmapCount);
-    TraceLog(DEBUG, "Compressed texture format: 0x%x", format);
-    
-    switch(format) 
-    { 
-        case FOURCC_DXT1: compFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; 
-        case FOURCC_DXT3: compFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; 
-        case FOURCC_DXT5: compFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; 
-        default: compFormat = -1; break;
-    }
-    
-    if (compFormat == -1)
+    TraceLog(DEBUG, "Compressed texture format: 0x%x", compFormat);
+        
+    if (compFormat == 0)
     {
     {
-        TraceLog(WARNING, "Texture compressed format not recognized");
+        TraceLog(WARNING, "[ID %i] Texture compressed format not recognized", id);
         id = 0;
         id = 0;
     }
     }
     else
     else
     {
     {
-        glGenTextures(1, &id);
-
         // Bind the texture
         // Bind the texture
         glBindTexture(GL_TEXTURE_2D, id);
         glBindTexture(GL_TEXTURE_2D, id);
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
     
     
-        unsigned int blockSize = (compFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16; 
-        unsigned int offset = 0;
+        int blockSize = 0;
+        int offset = 0;
+        
+        if (compFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) blockSize = 8;
+        else blockSize = 16;
         
         
         // Load the mipmaps 
         // Load the mipmaps 
         for (int level = 0; level < mipmapCount && (width || height); level++) 
         for (int level = 0; level < mipmapCount && (width || height); level++) 
         { 
         { 
-            unsigned int size = ((width+3)/4)*((height+3)/4)*blockSize;
+            // NOTE: size specifies the number of bytes of image data (S3TC/DXTC)
+            unsigned int size = ((width + 3)/4)*((height + 3)/4)*blockSize;
             
             
             glCompressedTexImage2D(GL_TEXTURE_2D, level, compFormat, width, height, 0, size, data + offset); 
             glCompressedTexImage2D(GL_TEXTURE_2D, level, compFormat, width, height, 0, size, data + offset); 
          
          
@@ -1100,20 +1196,28 @@ unsigned int rlglLoadModel(VertexData mesh)
  
  
     // Enable vertex attributes
     // Enable vertex attributes
     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]);
     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.numVertices, mesh.vertices, GL_STATIC_DRAW);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.vertices, GL_STATIC_DRAW);
     glEnableVertexAttribArray(vertexLoc);
     glEnableVertexAttribArray(vertexLoc);
     glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
     glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
     
     
     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]);
     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh.numVertices, mesh.texcoords, GL_STATIC_DRAW);      
+    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh.vertexCount, mesh.texcoords, GL_STATIC_DRAW);      
     glEnableVertexAttribArray(texcoordLoc);
     glEnableVertexAttribArray(texcoordLoc);
     glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
     glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
     
     
-    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.numVertices, mesh.normals, GL_STATIC_DRAW);   
+    //glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]);
+    //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.normals, GL_STATIC_DRAW);   
     //glEnableVertexAttribArray(normalLoc);
     //glEnableVertexAttribArray(normalLoc);
     //glVertexAttribPointer(normalLoc, 3, GL_FLOAT, 0, 0, 0);
     //glVertexAttribPointer(normalLoc, 3, GL_FLOAT, 0, 0, 0);
     
     
+    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*mesh.vertexCount, mesh.colors, GL_STATIC_DRAW);   
+    glEnableVertexAttribArray(colorLoc);
+    glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
+    
+    if (vaoModel > 0) TraceLog(INFO, "[ID %i] Model uploaded successfully to VRAM (GPU)", vaoModel);
+    else TraceLog(WARNING, "Model could not be uploaded to VRAM (GPU)");
+    
     return vaoModel;
     return vaoModel;
 }
 }
 #endif
 #endif
@@ -1208,6 +1312,9 @@ static GLuint LoadDefaultShaders()
 
 
     glCompileShader(vertexShader);
     glCompileShader(vertexShader);
     glCompileShader(fragmentShader);
     glCompileShader(fragmentShader);
+    
+    TraceLog(INFO, "[ID %i] Default vertex shader compiled succesfully", vertexShader);
+    TraceLog(INFO, "[ID %i] Default fragment shader compiled succesfully", fragmentShader);
  
  
     program = glCreateProgram();
     program = glCreateProgram();
     
     
@@ -1218,6 +1325,8 @@ static GLuint LoadDefaultShaders()
  
  
     glDeleteShader(vertexShader);
     glDeleteShader(vertexShader);
     glDeleteShader(fragmentShader);
     glDeleteShader(fragmentShader);
+    
+    TraceLog(INFO, "[ID %i] Default shader program loaded succesfully", program);
  
  
     return program;
     return program;
 }
 }
@@ -1245,6 +1354,9 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName)
 
 
     glCompileShader(vertexShader);
     glCompileShader(vertexShader);
     glCompileShader(fragmentShader);
     glCompileShader(fragmentShader);
+    
+    TraceLog(INFO, "[ID %i] Vertex shader compiled succesfully", vertexShader);
+    TraceLog(INFO, "[ID %i] Fragment shader compiled succesfully", fragmentShader);
  
  
     program = glCreateProgram();
     program = glCreateProgram();
     
     
@@ -1255,6 +1367,8 @@ static GLuint LoadShaders(char *vertexFileName, char *fragmentFileName)
  
  
     glDeleteShader(vertexShader);
     glDeleteShader(vertexShader);
     glDeleteShader(fragmentShader);
     glDeleteShader(fragmentShader);
+    
+    TraceLog(INFO, "[ID %i] Shader program loaded succesfully", program);
  
  
     return program;
     return program;
 }
 }
@@ -1364,7 +1478,8 @@ static void InitializeVAOs()
     glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW);
     glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW);
     glEnableVertexAttribArray(colorLoc);
     glEnableVertexAttribArray(colorLoc);
     glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
     glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
-
+    
+    TraceLog(INFO, "[ID %i] Lines VAO successfully initialized", vaoLines);
     //-------------------------------------------------------------- 
     //-------------------------------------------------------------- 
     
     
     // Initialize Triangles VAO
     // Initialize Triangles VAO
@@ -1384,7 +1499,8 @@ static void InitializeVAOs()
     glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW);
     glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW);
     glEnableVertexAttribArray(colorLoc);
     glEnableVertexAttribArray(colorLoc);
     glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
     glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
-
+    
+    TraceLog(INFO, "[ID %i] Triangles VAO successfully initialized", vaoTriangles);
     //-------------------------------------------------------------- 
     //-------------------------------------------------------------- 
     
     
     // Initialize Quads VAO (Buffer A)
     // Initialize Quads VAO (Buffer A)
@@ -1414,6 +1530,8 @@ static void InitializeVAOs()
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]);
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]);
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW);
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW);
     
     
+    TraceLog(INFO, "[ID %i] Quads VAO successfully initialized", vaoQuads);
+    
 #ifdef USE_VBO_DOUBLE_BUFFERS
 #ifdef USE_VBO_DOUBLE_BUFFERS
     // Initialize Quads VAO (Buffer B)
     // Initialize Quads VAO (Buffer B)
     glGenVertexArrays(1, &vaoQuadsB);
     glGenVertexArrays(1, &vaoQuadsB);
@@ -1442,11 +1560,9 @@ static void InitializeVAOs()
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBufferB[3]);
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBufferB[3]);
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW);
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW);
     
     
-    TraceLog(INFO, "Using VBO double buffering");
+    TraceLog(INFO, "[ID %i] Second Quads VAO successfully initilized (double buffering)", vaoQuadsB);
 #endif
 #endif
  
  
-    TraceLog(INFO, "Vertex buffers successfully initialized (lines, triangles, quads)\n");
- 
     // Unbind the current VAO
     // Unbind the current VAO
     glBindVertexArray(0);
     glBindVertexArray(0);
 }
 }
@@ -1540,6 +1656,135 @@ static void UpdateBuffers()
     glBindVertexArray(0);
     glBindVertexArray(0);
 }
 }
 
 
+#endif //defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
+
+#ifdef USE_OPENGL_11
+
+// Mipmaps data is generated after image data
+static int GenerateMipmaps(unsigned char *data, int baseWidth, int baseHeight)
+{
+    int mipmapCount = 1;                // Required mipmap levels count (including base level)
+    int width = baseWidth;
+    int height = baseHeight;
+    int size = baseWidth*baseHeight*4;  // Size in bytes (will include mipmaps...)
+
+    // Count mipmap levels required
+    while ((width != 1) && (height != 1))
+    {
+        if (width != 1) width /= 2;
+        if (height != 1) height /= 2;
+        
+        TraceLog(DEBUG, "Next mipmap size: %i x %i", width, height);
+        
+        mipmapCount++;
+        
+        size += (width*height*4);       // Add mipmap size (in bytes)
+    }
+    
+    TraceLog(DEBUG, "Total mipmaps required: %i", mipmapCount);
+    TraceLog(DEBUG, "Total size of data required: %i", size);
+    
+    unsigned char *temp = realloc(data, size);
+    
+    if (temp != NULL) data = temp;
+    else TraceLog(WARNING, "Mipmaps required memory could not be allocated");
+    
+    width = baseWidth;
+    height = baseHeight;
+    size = (width*height*4);
+    
+    // Generate mipmaps
+    // NOTE: Every mipmap data is stored after data
+    pixel *image = (pixel *)malloc(width*height*sizeof(pixel));
+    pixel *mipmap = NULL;
+    int offset = 0;
+    int j = 0;
+
+    for (int i = 0; i < size; i += 4)
+    {
+        image[j].r = data[i];
+        image[j].g = data[i + 1];
+        image[j].b = data[i + 2];
+        image[j].a = data[i + 3];
+        j++;
+    }
+    
+    TraceLog(DEBUG, "Mipmap base (%i, %i)", width, height);
+    
+    for (int mip = 1; mip < mipmapCount; mip++)
+    {
+        mipmap = GenNextMipmap(image, width, height);
+        
+        offset += (width*height*4); // Size of last mipmap
+        j = 0;
+        
+        width /= 2;
+        height /= 2;
+        size = (width*height*4);    // Mipmap size to store after offset
+
+        // Add mipmap to data
+        for (int i = 0; i < size; i += 4)
+        {
+            data[offset + i] = mipmap[j].r;
+            data[offset + i + 1] = mipmap[j].g;
+            data[offset + i + 2] = mipmap[j].b;
+            data[offset + i + 3] = mipmap[j].a; 
+            j++;
+        }
+
+        free(image);
+        
+        image = mipmap;
+        mipmap = NULL;
+    }
+    
+    free(mipmap);       // free mipmap data
+    
+    return mipmapCount;
+}
+
+// Manual mipmap generation (basic scaling algorithm)
+static pixel *GenNextMipmap(pixel *srcData, int srcWidth, int srcHeight)
+{
+    int x2, y2;
+    pixel prow, pcol;
+
+    int width = srcWidth / 2;
+    int height = srcHeight / 2;
+
+    pixel *mipmap = (pixel *)malloc(width*height*sizeof(pixel));
+
+    // Scaling algorithm works perfectly (box-filter)
+    for (int y = 0; y < height; y++) 
+    {
+        y2 = 2 * y;
+
+        for (int x = 0; x < width; x++) 
+        {
+            x2 = 2 * x;
+
+            prow.r = (srcData[y2*srcWidth + x2].r + srcData[y2*srcWidth + x2 + 1].r)/2;
+            prow.g = (srcData[y2*srcWidth + x2].g + srcData[y2*srcWidth + x2 + 1].g)/2;
+            prow.b = (srcData[y2*srcWidth + x2].b + srcData[y2*srcWidth + x2 + 1].b)/2;
+            prow.a = (srcData[y2*srcWidth + x2].a + srcData[y2*srcWidth + x2 + 1].a)/2;
+
+            pcol.r = (srcData[(y2+1)*srcWidth + x2].r + srcData[(y2+1)*srcWidth + x2 + 1].r)/2;
+            pcol.g = (srcData[(y2+1)*srcWidth + x2].g + srcData[(y2+1)*srcWidth + x2 + 1].g)/2;
+            pcol.b = (srcData[(y2+1)*srcWidth + x2].b + srcData[(y2+1)*srcWidth + x2 + 1].b)/2;
+            pcol.a = (srcData[(y2+1)*srcWidth + x2].a + srcData[(y2+1)*srcWidth + x2 + 1].a)/2;
+
+            mipmap[y*width + x].r = (prow.r + pcol.r)/2;
+            mipmap[y*width + x].g = (prow.g + pcol.g)/2;
+            mipmap[y*width + x].b = (prow.b + pcol.b)/2;
+            mipmap[y*width + x].a = (prow.a + pcol.a)/2;
+        }
+    }
+    
+    TraceLog(DEBUG, "Mipmap generated successfully (%i, %i)", width, height);
+
+    return mipmap;
+}
+
 #endif
 #endif
 
 
 #ifdef RLGL_STANDALONE
 #ifdef RLGL_STANDALONE
@@ -1555,10 +1800,10 @@ void TraceLog(int msgType, const char *text, ...)
     
     
     switch(msgType)
     switch(msgType)
     {
     {
-        case 0: fprintf(stdout, "INFO: "); break;
-        case 1: fprintf(stdout, "ERROR: "); break;
-        case 2: fprintf(stdout, "WARNING: "); break;
-        case 3: fprintf(logstream, "DEBUG: "); break;
+        case INFO: fprintf(stdout, "INFO: "); break;
+        case ERROR: fprintf(stdout, "ERROR: "); break;
+        case WARNING: fprintf(stdout, "WARNING: "); break;
+        case DEBUG: fprintf(stdout, "DEBUG: "); break;
         default: break;
         default: break;
     }
     }
     
     
@@ -1567,6 +1812,6 @@ void TraceLog(int msgType, const char *text, ...)
     
     
     va_end(args);
     va_end(args);
     
     
-    if (msgType == 1) exit(1);
+    if (msgType == ERROR) exit(1);
 }
 }
 #endif
 #endif

+ 26 - 31
src/rlgl.h

@@ -36,19 +36,19 @@
     #include "utils.h"          // Required for function TraceLog()
     #include "utils.h"          // Required for function TraceLog()
 #endif
 #endif
 
 
-#include "raymath.h"        // Required for data type Matrix and Matrix functions
+#include "raymath.h"            // Required for data type Matrix and Matrix functions
 
 
 // Select desired OpenGL version
 // Select desired OpenGL version
-//#define USE_OPENGL_11
-#define USE_OPENGL_33
+#define USE_OPENGL_11
+//#define USE_OPENGL_33
 //#define USE_OPENGL_ES2
 //#define USE_OPENGL_ES2
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Defines and Macros
 // Defines and Macros
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
-#define MAX_LINES_BATCH         8192    // 1024
-#define MAX_TRIANGLES_BATCH     2048
-#define MAX_QUADS_BATCH         8192
+#define MAX_LINES_BATCH         8192    // NOTE: Be careful with limits!
+#define MAX_TRIANGLES_BATCH     4096    // NOTE: Be careful with limits!
+#define MAX_QUADS_BATCH         8192    // NOTE: Be careful with limits!
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 // Types and Structures Definition
@@ -60,26 +60,20 @@ typedef enum { RL_PROJECTION, RL_MODELVIEW, RL_TEXTURE } MatrixMode;
 typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode;
 typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode;
 
 
 #ifdef RLGL_STANDALONE
 #ifdef RLGL_STANDALONE
-typedef struct Model Model;
-#endif
-
-typedef struct {
-    int numVertices;
-    float *vertices;            // 3 components per vertex
-    float *texcoords;           // 2 components per vertex
-    float *normals;             // 3 components per vertex
-} VertexData;
-
-#ifdef USE_OPENGL_11
-struct Model {
-    VertexData data;
-};
-#else
-struct Model {
-    unsigned int vaoId;
-    Matrix transform;
-    int numVertices;
-};
+    typedef struct {
+        int vertexCount;
+        float *vertices;            // 3 components per vertex
+        float *texcoords;           // 2 components per vertex
+        float *normals;             // 3 components per vertex
+        float *colors;
+    } VertexData;
+
+    typedef struct Model {
+        VertexData mesh;
+        unsigned int vaoId;
+        unsigned int textureId;
+        //Matrix transform;
+    } Model;
 #endif
 #endif
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -90,8 +84,8 @@ extern "C" {            // Prevents name mangling of functions
 // Functions Declaration - Matrix operations
 // Functions Declaration - Matrix operations
 //------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------
 void rlMatrixMode(int mode);                    // Choose the current matrix to be transformed
 void rlMatrixMode(int mode);                    // Choose the current matrix to be transformed
-void rlPushMatrix();                            // TODO: REVIEW: Required? - Push the current matrix to stack
-void rlPopMatrix();                             // TODO: REVIEW: Required? - Pop lattest inserted matrix from stack
+void rlPushMatrix();                            // Push the current matrix to stack
+void rlPopMatrix();                             // Pop lattest inserted matrix from stack
 void rlLoadIdentity();                          // Reset current matrix to identity matrix
 void rlLoadIdentity();                          // Reset current matrix to identity matrix
 void rlTranslatef(float x, float y, float z);   // Multiply the current matrix by a translation matrix
 void rlTranslatef(float x, float y, float z);   // Multiply the current matrix by a translation matrix
 void rlRotatef(float angleDeg, float x, float y, float z);  // Multiply the current matrix by a rotation matrix
 void rlRotatef(float angleDeg, float x, float y, float z);  // Multiply the current matrix by a rotation matrix
@@ -132,13 +126,14 @@ void rlClearScreenBuffers();                // Clear used screen buffers (color
 void rlglInit();                                // Initialize rlgl (shaders, VAO, VBO...)
 void rlglInit();                                // Initialize rlgl (shaders, VAO, VBO...)
 void rlglClose();                               // De-init rlgl
 void rlglClose();                               // De-init rlgl
 void rlglDraw();                                // Draw VAOs
 void rlglDraw();                                // Draw VAOs
-unsigned int rlglLoadModel(VertexData data);
+unsigned int rlglLoadModel(VertexData mesh);
 unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int format);
 unsigned int rlglLoadCompressedTexture(unsigned char *data, int width, int height, int mipmapCount, int format);
 #endif
 #endif
 
 
-void rlglDrawModel(Model model, Vector3 position, float scale, bool wires);   // Draw model
+void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scale, Color color, bool wires);
+
 void rlglInitGraphicsDevice(int fbWidth, int fbHeight);  // Initialize Graphics Device (OpenGL stuff)
 void rlglInitGraphicsDevice(int fbWidth, int fbHeight);  // Initialize Graphics Device (OpenGL stuff)
-unsigned int rlglLoadTexture(int width, int height, unsigned char *pixels); // Load in GPU OpenGL texture
+unsigned int rlglLoadTexture(unsigned char *data, int width, int height, bool genMipmaps); // Load in GPU OpenGL texture
 byte *rlglReadScreenPixels(int width, int height);    // Read screen pixel data (color buffer)
 byte *rlglReadScreenPixels(int width, int height);    // Read screen pixel data (color buffer)
 
 
 #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)
 #if defined(USE_OPENGL_33) || defined(USE_OPENGL_ES2)

+ 18 - 21
src/shapes.c

@@ -112,6 +112,7 @@ void DrawCircleGradient(int centerX, int centerY, float radius, Color color1, Co
             rlVertex2i(centerX, centerY);
             rlVertex2i(centerX, centerY);
             rlColor4ub(color2.r, color2.g, color2.b, color2.a);
             rlColor4ub(color2.r, color2.g, color2.b, color2.a);
             rlVertex2f(centerX + sin(DEG2RAD*i) * radius, centerY + cos(DEG2RAD*i) * radius);
             rlVertex2f(centerX + sin(DEG2RAD*i) * radius, centerY + cos(DEG2RAD*i) * radius);
+            rlColor4ub(color2.r, color2.g, color2.b, color2.a);
             rlVertex2f(centerX + sin(DEG2RAD*(i+2)) * radius, centerY + cos(DEG2RAD*(i+2)) * radius);
             rlVertex2f(centerX + sin(DEG2RAD*(i+2)) * radius, centerY + cos(DEG2RAD*(i+2)) * radius);
         }
         }
     rlEnd();
     rlEnd();
@@ -149,17 +150,10 @@ void DrawCircleLines(int centerX, int centerY, float radius, Color color)
 // Draw a color-filled rectangle
 // Draw a color-filled rectangle
 void DrawRectangle(int posX, int posY, int width, int height, Color color)
 void DrawRectangle(int posX, int posY, int width, int height, Color color)
 {
 {
-    rlBegin(RL_QUADS);
-        rlColor4ub(color.r, color.g, color.b, color.a);
-        rlTexCoord2f(0.0f, 0.0f);
-        rlVertex2i(posX, posY);
-        rlTexCoord2f(0.0f, 1.0f); 
-        rlVertex2i(posX, posY + height);
-        rlTexCoord2f(1.0f, 1.0f); 
-        rlVertex2i(posX + width, posY + height);
-        rlTexCoord2f(1.0f, 0.0f);
-        rlVertex2i(posX + width, posY);
-    rlEnd();
+    Vector2 position = { (float)posX, (float)posY };
+    Vector2 size = { (float)width, (float)height };
+
+    DrawRectangleV(position, size, color);
 }
 }
 
 
 // Draw a color-filled rectangle
 // Draw a color-filled rectangle
@@ -172,26 +166,29 @@ void DrawRectangleRec(Rectangle rec, Color color)
 // NOTE: Gradient goes from bottom (color1) to top (color2)
 // NOTE: Gradient goes from bottom (color1) to top (color2)
 void DrawRectangleGradient(int posX, int posY, int width, int height, Color color1, Color color2)
 void DrawRectangleGradient(int posX, int posY, int width, int height, Color color1, Color color2)
 {
 {
-    rlBegin(RL_QUADS);
-        rlColor4ub(color1.r, color1.g, color1.b, color1.a);
-        rlVertex2i(posX, posY);
-        rlColor4ub(color1.r, color1.g, color1.b, color1.a);
-        rlVertex2i(posX, posY + height);
-        rlColor4ub(color2.r, color2.g, color2.b, color2.a);
-        rlVertex2i(posX + width, posY + height);
-        rlColor4ub(color2.r, color2.g, color2.b, color2.a);
-        rlVertex2i(posX + width, posY);
+    rlBegin(RL_TRIANGLES);
+        rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX, posY);
+        rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX, posY + height);
+        rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX + width, posY + height);
+        
+        rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX, posY);
+        rlColor4ub(color2.r, color2.g, color2.b, color2.a); rlVertex2i(posX + width, posY + height);        
+        rlColor4ub(color1.r, color1.g, color1.b, color1.a); rlVertex2i(posX + width, posY);
     rlEnd();
     rlEnd();
 }
 }
 
 
 // Draw a color-filled rectangle (Vector version)
 // Draw a color-filled rectangle (Vector version)
 void DrawRectangleV(Vector2 position, Vector2 size, Color color)
 void DrawRectangleV(Vector2 position, Vector2 size, Color color)
 {
 {
-    rlBegin(RL_QUADS);
+    rlBegin(RL_TRIANGLES);
         rlColor4ub(color.r, color.g, color.b, color.a);
         rlColor4ub(color.r, color.g, color.b, color.a);
+        
         rlVertex2i(position.x, position.y);
         rlVertex2i(position.x, position.y);
         rlVertex2i(position.x, position.y + size.y);
         rlVertex2i(position.x, position.y + size.y);
         rlVertex2i(position.x + size.x, position.y + size.y);
         rlVertex2i(position.x + size.x, position.y + size.y);
+        
+        rlVertex2i(position.x, position.y);
+        rlVertex2i(position.x + size.x, position.y + size.y);        
         rlVertex2i(position.x + size.x, position.y);
         rlVertex2i(position.x + size.x, position.y);
     rlEnd();
     rlEnd();
 }
 }

+ 17 - 26
src/text.c

@@ -35,6 +35,8 @@
 
 
 #include "rlgl.h"         // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
 #include "rlgl.h"         // raylib OpenGL abstraction layer to OpenGL 1.1, 3.3+ or ES2
 
 
+#include "utils.h"        // Required for function GetExtendion()
+
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Defines and Macros
 // Defines and Macros
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
@@ -58,15 +60,6 @@ typedef struct Character {
     int h;
     int h;
 } Character;
 } Character;
 
 
-// SpriteFont type, includes texture and charSet array data
-/*
-struct SpriteFont {
-    Texture2D texture;
-    int numChars;
-    Character *charSet;
-};
-*/
-
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Global variables
 // Global variables
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
@@ -85,7 +78,6 @@ static bool PixelIsMagenta(Color p);                // Check if a pixel is magen
 static int ParseImageData(Color *imgDataPixel, int imgWidth, int imgHeight, Character **charSet);    // Parse image pixel data to obtain character set measures
 static int ParseImageData(Color *imgDataPixel, int imgWidth, int imgHeight, Character **charSet);    // Parse image pixel data to obtain character set measures
 static int GetNextPOT(int num);                     // Calculate next power-of-two value for a given value
 static int GetNextPOT(int num);                     // Calculate next power-of-two value for a given value
 static SpriteFont LoadRBMF(const char *fileName);   // Load a rBMF font file (raylib BitMap Font)
 static SpriteFont LoadRBMF(const char *fileName);   // Load a rBMF font file (raylib BitMap Font)
-static const char *GetExtension(const char *fileName);
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Module Functions Definition
 // Module Functions Definition
@@ -153,8 +145,7 @@ extern void LoadDefaultFont()
         if (counter > 256) counter = 0;         // Security check...
         if (counter > 256) counter = 0;         // Security check...
     }
     }
     
     
-    defaultFont.texture = CreateTexture(image); // Convert loaded image to OpenGL texture
-
+    defaultFont.texture = CreateTexture(image, false); // Convert loaded image to OpenGL texture
     UnloadImage(image);
     UnloadImage(image);
     
     
     // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, numChars
     // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, numChars
@@ -192,7 +183,7 @@ extern void LoadDefaultFont()
 
 
 extern void UnloadDefaultFont()
 extern void UnloadDefaultFont()
 {
 {
-    rlDeleteTextures(defaultFont.texture.glId);
+    rlDeleteTextures(defaultFont.texture.id);
     free(defaultFont.charSet);
     free(defaultFont.charSet);
 }
 }
 
 
@@ -277,8 +268,7 @@ SpriteFont LoadSpriteFont(const char* fileName)
         image.width = potWidth;
         image.width = potWidth;
         image.height = potHeight;
         image.height = potHeight;
         
         
-        spriteFont.texture = CreateTexture(image); // Convert loaded image to OpenGL texture
-
+        spriteFont.texture = CreateTexture(image, false); // Convert loaded image to OpenGL texture
         UnloadImage(image);
         UnloadImage(image);
     }
     }
     
     
@@ -288,7 +278,7 @@ SpriteFont LoadSpriteFont(const char* fileName)
 // Unload SpriteFont from GPU memory
 // Unload SpriteFont from GPU memory
 void UnloadSpriteFont(SpriteFont spriteFont)
 void UnloadSpriteFont(SpriteFont spriteFont)
 {
 {
-    rlDeleteTextures(spriteFont.texture.glId);
+    rlDeleteTextures(spriteFont.texture.id);
     free(spriteFont.charSet);
     free(spriteFont.charSet);
 }
 }
 
 
@@ -322,7 +312,7 @@ void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, int f
     if (fontSize <= spriteFont.charSet[0].h) scaleFactor = 1.0f;
     if (fontSize <= spriteFont.charSet[0].h) scaleFactor = 1.0f;
     else scaleFactor = (float)fontSize / spriteFont.charSet[0].h;
     else scaleFactor = (float)fontSize / spriteFont.charSet[0].h;
 
 
-    rlEnableTexture(spriteFont.texture.glId);
+    rlEnableTexture(spriteFont.texture.id);
 
 
     rlBegin(RL_QUADS);
     rlBegin(RL_QUADS);
         for(int i = 0; i < length; i++)
         for(int i = 0; i < length; i++)
@@ -513,11 +503,11 @@ static int GetNextPOT(int num)
     if (num != 0)
     if (num != 0)
     {
     {
         num--;
         num--;
-        num |= (num >> 1);    // Or first 2 bits
+        num |= (num >> 1);     // Or first 2 bits
         num |= (num >> 2);     // Or next 2 bits
         num |= (num >> 2);     // Or next 2 bits
         num |= (num >> 4);     // Or next 4 bits
         num |= (num >> 4);     // Or next 4 bits
         num |= (num >> 8);     // Or next 8 bits
         num |= (num >> 8);     // Or next 8 bits
-        num |= (num >> 16); // Or next 16 bits
+        num |= (num >> 16);    // Or next 16 bits
         num++;
         num++;
     }
     }
 
 
@@ -596,8 +586,7 @@ static SpriteFont LoadRBMF(const char *fileName)
     
     
     TraceLog(INFO, "[%s] Image reconstructed correctly, now converting it to texture", fileName);
     TraceLog(INFO, "[%s] Image reconstructed correctly, now converting it to texture", fileName);
     
     
-    spriteFont.texture = CreateTexture(image);
-    
+    spriteFont.texture = CreateTexture(image, false);
     UnloadImage(image);     // Unload image data
     UnloadImage(image);     // Unload image data
     
     
     TraceLog(INFO, "[%s] Starting charSet reconstruction", fileName);
     TraceLog(INFO, "[%s] Starting charSet reconstruction", fileName);
@@ -641,10 +630,12 @@ static SpriteFont LoadRBMF(const char *fileName)
     return spriteFont;
     return spriteFont;
 }
 }
 
 
-// Get the extension for a filename
-static const char *GetExtension(const char *fileName) 
+// Generate a sprite font from TTF data (font size required)
+static SpriteFont GenerateFromTTF(const char *fileName, int fontSize)
 {
 {
-    const char *dot = strrchr(fileName, '.');
-    if(!dot || dot == fileName) return "";
-    return dot + 1;
+    SpriteFont font;
+    
+    // TODO: Load TTF and generate bitmap font and chars data
+    
+    return font;
 }
 }

+ 204 - 137
src/textures.c

@@ -46,12 +46,14 @@
 typedef unsigned char byte;
 typedef unsigned char byte;
 
 
 typedef struct {
 typedef struct {
-    unsigned char *data;
-    int width;
-    int height;
-    int mipmaps;
-    int format;
-} ImageDDS;
+    unsigned char *data;    // Image raw data
+    int width;              // Image base width
+    int height;             // Image base height
+    //int bpp;              // bytes per pixel
+    //int components;       // num color components
+    int mipmaps;            // Mipmap levels, 1 by default
+    int compFormat;         // Compressed data format, 0 if no compression
+} ImageEx;
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Global Variables Definition
 // Global Variables Definition
@@ -66,8 +68,7 @@ typedef struct {
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Module specific Functions Declaration
 // Module specific Functions Declaration
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
-static const char *GetExtension(const char *fileName);
-static ImageDDS LoadDDS(const char *fileName);
+static ImageEx LoadDDS(const char *fileName);
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Module Functions Definition
 // Module Functions Definition
@@ -78,6 +79,11 @@ Image LoadImage(const char *fileName)
 {
 {
     Image image;
     Image image;
     
     
+    // Initial values
+    image.pixels = NULL;
+    image.width = 0;
+    image.height = 0;
+    
     if ((strcmp(GetExtension(fileName),"png") == 0) ||
     if ((strcmp(GetExtension(fileName),"png") == 0) ||
         (strcmp(GetExtension(fileName),"bmp") == 0) ||
         (strcmp(GetExtension(fileName),"bmp") == 0) ||
         (strcmp(GetExtension(fileName),"tga") == 0) ||
         (strcmp(GetExtension(fileName),"tga") == 0) ||
@@ -115,6 +121,35 @@ Image LoadImage(const char *fileName)
         
         
         TraceLog(INFO, "[%s] Image loaded successfully", fileName);
         TraceLog(INFO, "[%s] Image loaded successfully", fileName);
     }
     }
+    else if (strcmp(GetExtension(fileName),"dds") == 0)
+    {
+        // NOTE: DDS uncompressed images can also be loaded (discarding mipmaps...)
+        
+        ImageEx imageDDS = LoadDDS(fileName);
+        
+        if (imageDDS.compFormat == 0)
+        {
+            image.pixels = (Color *)malloc(imageDDS.width * imageDDS.height * sizeof(Color));
+            image.width = imageDDS.width;
+            image.height = imageDDS.height;
+            
+            int pix = 0;
+        
+            for (int i = 0; i < (image.width * image.height * 4); i += 4)
+            {
+                image.pixels[pix].r = imageDDS.data[i];
+                image.pixels[pix].g = imageDDS.data[i+1];
+                image.pixels[pix].b = imageDDS.data[i+2];
+                image.pixels[pix].a = imageDDS.data[i+3];
+                pix++;
+            }
+            
+            free(imageDDS.data);
+            
+            TraceLog(INFO, "[%s] Image loaded successfully", fileName);
+        }
+        else TraceLog(WARNING, "[%s] Compressed image data could not be loaded", fileName);    
+    }
     else TraceLog(WARNING, "[%s] Image extension not recognized, it can't be loaded", fileName);
     else TraceLog(WARNING, "[%s] Image extension not recognized, it can't be loaded", fileName);
     
     
     // ALTERNATIVE: We can load pixel data directly into Color struct pixels array, 
     // ALTERNATIVE: We can load pixel data directly into Color struct pixels array, 
@@ -127,7 +162,8 @@ Image LoadImage(const char *fileName)
 // Load an image from rRES file (raylib Resource)
 // Load an image from rRES file (raylib Resource)
 Image LoadImageFromRES(const char *rresName, int resId)
 Image LoadImageFromRES(const char *rresName, int resId)
 {
 {
-    // NOTE: rresName could be directly a char array with all the data!!! ---> TODO!
+    // TODO: rresName could be directly a char array with all the data! --> support it! :P
+    
     Image image;
     Image image;
     bool found = false;
     bool found = false;
 
 
@@ -172,8 +208,8 @@ Image LoadImageFromRES(const char *rresName, int resId)
                     if (infoHeader.type == 0)   // IMAGE data type
                     if (infoHeader.type == 0)   // IMAGE data type
                     {
                     {
                         // TODO: Check data compression type
                         // TODO: Check data compression type
-                        
                         // NOTE: We suppose compression type 2 (DEFLATE - default)
                         // NOTE: We suppose compression type 2 (DEFLATE - default)
+
                         short imgWidth, imgHeight;
                         short imgWidth, imgHeight;
                         char colorFormat, mipmaps;
                         char colorFormat, mipmaps;
                     
                     
@@ -220,11 +256,11 @@ Image LoadImageFromRES(const char *rresName, int resId)
                     // Depending on type, skip the right amount of parameters
                     // Depending on type, skip the right amount of parameters
                     switch (infoHeader.type)
                     switch (infoHeader.type)
                     {
                     {
-                        case 0: fseek(rresFile, 6, SEEK_CUR); break;   // IMAGE: Jump 6 bytes of parameters
-                        case 1: fseek(rresFile, 6, SEEK_CUR); break;   // SOUND: Jump 6 bytes of parameters
-                        case 2: fseek(rresFile, 5, SEEK_CUR); break;   // MODEL: Jump 5 bytes of parameters (TODO: Review)
-                        case 3: break;   // TEXT: No parameters
-                        case 4: break;   // RAW: No parameters
+                        case 0: fseek(rresFile, 6, SEEK_CUR); break;    // IMAGE: Jump 6 bytes of parameters
+                        case 1: fseek(rresFile, 6, SEEK_CUR); break;    // SOUND: Jump 6 bytes of parameters
+                        case 2: fseek(rresFile, 5, SEEK_CUR); break;    // MODEL: Jump 5 bytes of parameters (TODO: Review)
+                        case 3: break;                                  // TEXT: No parameters
+                        case 4: break;                                  // RAW: No parameters
                         default: break;
                         default: break;
                     }
                     }
                     
                     
@@ -249,19 +285,26 @@ Texture2D LoadTexture(const char *fileName)
 
 
     if (strcmp(GetExtension(fileName),"dds") == 0)
     if (strcmp(GetExtension(fileName),"dds") == 0)
     {
     {
-#ifdef USE_OPENGL_11 
-        TraceLog(WARNING, "[%s] DDS file loading requires OpenGL 3.2+ or ES 2.0", fileName);
-#else
-        ImageDDS image = LoadDDS(fileName);
+        ImageEx image = LoadDDS(fileName);
+        
+        if (image.compFormat == 0)
+        {
+            texture.id = rlglLoadTexture(image.data, image.width, image.height, false);
+        }
+        else
+        {
+#ifdef USE_OPENGL_33
+            texture.id = rlglLoadCompressedTexture(image.data, image.width, image.height, image.mipmaps, image.compFormat);
+#endif
+        }
         
         
-        texture.glId = rlglLoadCompressedTexture(image.data, image.width, image.height, image.mipmaps, image.format);
-
         texture.width = image.width;
         texture.width = image.width;
         texture.height = image.height;
         texture.height = image.height;
         
         
-        if (texture.glId == 0) TraceLog(WARNING, "Compressed texture could not be loaded");
-        else TraceLog(INFO, "Compressed texture loaded succesfully");
-#endif
+        if (texture.id == 0) TraceLog(WARNING, "[%s] DDS texture could not be loaded", fileName);
+        else TraceLog(INFO, "[%s] DDS texture loaded succesfully", fileName);
+        
+        free(image.data);
     }
     }
     else
     else
     {
     {
@@ -269,7 +312,7 @@ Texture2D LoadTexture(const char *fileName)
         
         
         if (image.pixels != NULL)
         if (image.pixels != NULL)
         {
         {
-            texture = CreateTexture(image);
+            texture = CreateTexture(image, false);
             UnloadImage(image);
             UnloadImage(image);
         }
         }
     }
     }
@@ -283,7 +326,8 @@ Texture2D LoadTextureFromRES(const char *rresName, int resId)
     Texture2D texture;
     Texture2D texture;
 
 
     Image image = LoadImageFromRES(rresName, resId);
     Image image = LoadImageFromRES(rresName, resId);
-    texture = CreateTexture(image);
+    texture = CreateTexture(image, false);
+    UnloadImage(image);
     
     
     return texture;
     return texture;
 }
 }
@@ -297,7 +341,7 @@ void UnloadImage(Image image)
 // Unload texture from GPU memory
 // Unload texture from GPU memory
 void UnloadTexture(Texture2D texture)
 void UnloadTexture(Texture2D texture)
 {
 {
-    rlDeleteTextures(texture.glId);
+    rlDeleteTextures(texture.id);
 }
 }
 
 
 // Draw a Texture2D
 // Draw a Texture2D
@@ -315,76 +359,32 @@ void DrawTextureV(Texture2D texture, Vector2 position, Color tint)
 // Draw a Texture2D with extended parameters
 // Draw a Texture2D with extended parameters
 void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint)
 void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint)
 {
 {
-    rlEnableTexture(texture.glId);
+    Rectangle sourceRec = { 0, 0, texture.width, texture.height };
+    Rectangle destRec = { (int)position.x, (int)position.y, texture.width*scale, texture.height*scale };
+    Vector2 origin = { 0, 0 };
     
     
-    // NOTE: Rotation is applied before translation and scaling, even being called in inverse order...
-    // NOTE: Rotation point is upper-left corner    
-    rlPushMatrix();
-        //rlTranslatef(position.x, position.y, 0.0);
-        rlRotatef(rotation, 0, 0, 1);
-        rlScalef(scale, scale, 1.0f);
-    
-        rlBegin(RL_QUADS);
-            rlColor4ub(tint.r, tint.g, tint.b, tint.a);
-            rlNormal3f(0.0f, 0.0f, 1.0f);                               // Normal vector pointing towards viewer
-            
-            rlTexCoord2f(0.0f, 0.0f);
-            rlVertex2f(position.x, position.y);                         // Bottom-left corner for texture and quad
-            
-            rlTexCoord2f(0.0f, 1.0f); 
-            rlVertex2f(position.x, position.y + texture.height);        // Bottom-right corner for texture and quad
-            
-            rlTexCoord2f(1.0f, 1.0f); 
-            rlVertex2f(position.x + texture.width, position.y + texture.height);  // Top-right corner for texture and quad
-            
-            rlTexCoord2f(1.0f, 0.0f); 
-            rlVertex2f(position.x + texture.width, position.y);         // Top-left corner for texture and quad
-        rlEnd();
-    rlPopMatrix();
-    
-    rlDisableTexture();
+    DrawTexturePro(texture, sourceRec, destRec, origin, rotation, tint);
 }
 }
 
 
 // Draw a part of a texture (defined by a rectangle)
 // Draw a part of a texture (defined by a rectangle)
 void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint)
 void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint)
 {
 {
-    rlEnableTexture(texture.glId);
-    
-    rlBegin(RL_QUADS);
-        rlColor4ub(tint.r, tint.g, tint.b, tint.a);
-        rlNormal3f(0.0f, 0.0f, 1.0f);                          // Normal vector pointing towards viewer
-        
-        // Bottom-left corner for texture and quad
-        rlTexCoord2f((float)sourceRec.x / texture.width, (float)sourceRec.y / texture.height); 
-        rlVertex2f(position.x, position.y);
-        
-        // Bottom-right corner for texture and quad
-        rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
-        rlVertex2f(position.x, position.y + sourceRec.height);
-        
-        // Top-right corner for texture and quad
-        rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); 
-        rlVertex2f(position.x + sourceRec.width, position.y + sourceRec.height);
-        
-        // Top-left corner for texture and quad 
-        rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height);
-        rlVertex2f(position.x + sourceRec.width, position.y);
-    rlEnd();
+    Rectangle destRec = { (int)position.x, (int)position.y, sourceRec.width, sourceRec.height };
+    Vector2 origin = { 0, 0 };
     
     
-    rlDisableTexture();
+    DrawTexturePro(texture, sourceRec, destRec, origin, 0, tint);
 }
 }
 
 
 // Draw a part of a texture (defined by a rectangle) with 'pro' parameters
 // Draw a part of a texture (defined by a rectangle) with 'pro' parameters
-// TODO: Test this function...
+// NOTE: origin is relative to destination rectangle size
 void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint)
 void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint)
 {
 {
-    rlEnableTexture(texture.glId);
+    rlEnableTexture(texture.id);
     
     
-    // NOTE: First we translate texture to origin to apply rotation and translation from there
     rlPushMatrix();
     rlPushMatrix();
-        rlTranslatef(-origin.x, -origin.y, 0);  
+        rlTranslatef(destRec.x, destRec.y, 0);
         rlRotatef(rotation, 0, 0, 1);
         rlRotatef(rotation, 0, 0, 1);
-        rlTranslatef(destRec.x + origin.x, destRec.y + origin.y, 0);
+        rlTranslatef(-origin.x, -origin.y, 0);
             
             
         rlBegin(RL_QUADS);
         rlBegin(RL_QUADS);
             rlColor4ub(tint.r, tint.g, tint.b, tint.a);
             rlColor4ub(tint.r, tint.g, tint.b, tint.a);
@@ -395,65 +395,84 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V
             rlVertex2f(0.0f, 0.0f);
             rlVertex2f(0.0f, 0.0f);
             
             
             // Bottom-right corner for texture and quad
             // Bottom-right corner for texture and quad
-            rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height);
-            rlVertex2f(destRec.width, 0.0f);
+            rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
+            rlVertex2f(0.0f, destRec.height);
             
             
             // Top-right corner for texture and quad
             // Top-right corner for texture and quad
             rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); 
             rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height); 
             rlVertex2f(destRec.width, destRec.height);
             rlVertex2f(destRec.width, destRec.height);
             
             
             // Top-left corner for texture and quad
             // Top-left corner for texture and quad
-            rlTexCoord2f((float)sourceRec.x / texture.width, (float)(sourceRec.y + sourceRec.height) / texture.height);
-            rlVertex2f(0.0f, destRec.height);
+            rlTexCoord2f((float)(sourceRec.x + sourceRec.width) / texture.width, (float)sourceRec.y / texture.height);
+            rlVertex2f(destRec.width, 0.0f);
         rlEnd();
         rlEnd();
     rlPopMatrix();
     rlPopMatrix();
     
     
     rlDisableTexture();
     rlDisableTexture();
 }
 }
 
 
-Texture2D CreateTexture(Image image)
+// Create a texture from an image
+// NOTE: image is not unloaded, iot must be done manually
+Texture2D CreateTexture(Image image, bool genMipmaps)
 {
 {
     Texture2D texture;
     Texture2D texture;
     
     
-    unsigned char *img = malloc(image.width * image.height * 4);
-    
-    int j = 0;
+    // Init texture to default values
+    texture.id = 0;
+    texture.width = 0;
+    texture.height = 0;
     
     
-    for (int i = 0; i < image.width * image.height * 4; i += 4)
+    if (image.pixels != NULL)
     {
     {
-        img[i] = image.pixels[j].r;
-        img[i+1] = image.pixels[j].g;
-        img[i+2] = image.pixels[j].b;
-        img[i+3] = image.pixels[j].a;
+        unsigned char *imgData = malloc(image.width * image.height * 4);
         
         
-        j++;
-    }
+        int j = 0;
+        
+        for (int i = 0; i < image.width * image.height * 4; i += 4)
+        {
+            imgData[i] = image.pixels[j].r;
+            imgData[i+1] = image.pixels[j].g;
+            imgData[i+2] = image.pixels[j].b;
+            imgData[i+3] = image.pixels[j].a;
+            
+            j++;
+        }
 
 
-    texture.glId = rlglLoadTexture(image.width, image.height, img);
+        // NOTE: rlglLoadTexture() can generate mipmaps (POT image required)
+        texture.id = rlglLoadTexture(imgData, image.width, image.height, genMipmaps);
 
 
-    texture.width = image.width;
-    texture.height = image.height;
-    
-    TraceLog(INFO, "Texture created succesfully");
-    
-    free(img);
+        texture.width = image.width;
+        texture.height = image.height;
+        
+        TraceLog(INFO, "[ID %i] Texture created succesfully", texture.id);
+        
+        free(imgData);
+    }
+    else TraceLog(WARNING, "Texture could not be created, image data is not valid");
     
     
     return texture;
     return texture;
 }
 }
 
 
-// Get the extension for a filename
-static const char *GetExtension(const char *fileName) 
-{
-    const char *dot = strrchr(fileName, '.');
-    if(!dot || dot == fileName) return "";
-    return (dot + 1);
-}
-
-// Loading DDS image compressed data 
-ImageDDS LoadDDS(const char *fileName)
+// Loading DDS image data (compressed or uncompressed)
+// NOTE: Compressed data loading not supported on OpenGL 1.1
+ImageEx LoadDDS(const char *fileName)
 {   
 {   
-    // TODO: Review and expand DDS file loading to support uncompressed formats and new formats
+    #define FOURCC_DXT1 0x31545844  // Equivalent to "DXT1" in ASCII
+    #define FOURCC_DXT3 0x33545844  // Equivalent to "DXT3" in ASCII
+    #define FOURCC_DXT5 0x35545844  // Equivalent to "DXT5" in ASCII
+    
+    #ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
+    #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+    #endif
 
 
+    #ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
+    #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
+    #endif
+
+    #ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
+    #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
+    #endif
+    
     // DDS Pixel Format
     // DDS Pixel Format
     typedef struct {
     typedef struct {
         unsigned int size;
         unsigned int size;
@@ -484,7 +503,7 @@ ImageDDS LoadDDS(const char *fileName)
         unsigned int reserved2;
         unsigned int reserved2;
     } ddsHeader;
     } ddsHeader;
     
     
-    ImageDDS image;
+    ImageEx image;
     ddsHeader header;
     ddsHeader header;
 
 
     FILE *ddsFile = fopen(fileName, "rb");
     FILE *ddsFile = fopen(fileName, "rb");
@@ -510,36 +529,84 @@ ImageDDS LoadDDS(const char *fileName)
             // Get the surface descriptor
             // Get the surface descriptor
             fread(&header, sizeof(ddsHeader), 1, ddsFile);
             fread(&header, sizeof(ddsHeader), 1, ddsFile);
 
 
-            int height = header.height;
-            int width = header.width;
-            int linearSize = header.pitchOrLinearSize;
-            int mipMapCount = header.mipMapCount;
-            int fourCC = header.ddspf.fourCC;
-            
             TraceLog(DEBUG, "[%s] DDS file header size: %i", fileName, sizeof(ddsHeader));
             TraceLog(DEBUG, "[%s] DDS file header size: %i", fileName, sizeof(ddsHeader));
-            
             TraceLog(DEBUG, "[%s] DDS file pixel format size: %i", fileName, header.ddspf.size);
             TraceLog(DEBUG, "[%s] DDS file pixel format size: %i", fileName, header.ddspf.size);
             TraceLog(DEBUG, "[%s] DDS file pixel format flags: 0x%x", fileName, header.ddspf.flags);
             TraceLog(DEBUG, "[%s] DDS file pixel format flags: 0x%x", fileName, header.ddspf.flags);
-            TraceLog(DEBUG, "[%s] DDS file format: 0x%x", fileName, fourCC);
+            TraceLog(DEBUG, "[%s] DDS file format: 0x%x", fileName, header.ddspf.fourCC);
             
             
-            int bufsize;
+            image.width = header.width;
+            image.height = header.height;
+            image.mipmaps = 1;
+            image.compFormat = 0;
             
             
-            // Calculate data size, including all mipmaps 
-            bufsize = mipMapCount > 1 ? linearSize * 2 : linearSize; 
+            if (header.ddspf.flags == 0x40 && header.ddspf.rgbBitCount == 24)   // DDS_RGB, no compressed
+            {
+                image.data = (unsigned char *)malloc(header.width * header.height * 4);
+                unsigned char *buffer = (unsigned char *)malloc(header.width * header.height * 3);
             
             
-            image.data = (unsigned char*)malloc(bufsize * sizeof(unsigned char)); 
+                fread(buffer, image.width*image.height*3, 1, ddsFile);
+                
+                unsigned char *src = buffer;
+                unsigned char *dest = image.data;
+                
+                for(int y = 0; y < image.height; y++) 
+                {
+                    for(int x = 0; x < image.width; x++) 
+                    {
+                        *dest++ = *src++;
+                        *dest++ = *src++;
+                        *dest++ = *src++;
+                        *dest++ = 255;
+                    }
+                }
+                
+                free(buffer);
+            }
+            else if (header.ddspf.flags == 0x41 && header.ddspf.rgbBitCount == 32) // DDS_RGBA, no compressed
+            {
+                image.data = (unsigned char *)malloc(header.width * header.height * 4);
             
             
-            fread(image.data, 1, bufsize, ddsFile); 
+                fread(image.data, image.width*image.height*4, 1, ddsFile);
             
             
-            // Close file pointer
-            fclose(ddsFile);
-
-            //int components = (fourCC == FOURCC_DXT1) ? 3 : 4; // Not required
+                image.mipmaps = 1;
+                image.compFormat = 0;
+            }
+            else if ((header.ddspf.flags == 0x04) && (header.ddspf.fourCC > 0))
+            {
+#ifdef USE_OPENGL_11 
+                TraceLog(WARNING, "[%s] DDS image uses compression, not supported by current OpenGL version", fileName);
+                TraceLog(WARNING, "[%s] DDS compressed files require OpenGL 3.2+ or ES 2.0", fileName);
+                fclose(ddsFile);
+#else
+                int bufsize;
+                
+                // Calculate data size, including all mipmaps
+                if (header.mipMapCount > 1) bufsize = header.pitchOrLinearSize * 2;
+                else bufsize = header.pitchOrLinearSize; 
+                
+                image.data = (unsigned char*)malloc(bufsize * sizeof(unsigned char)); 
+                
+                fread(image.data, 1, bufsize, ddsFile); 
+                
+                // Close file pointer
+                fclose(ddsFile);
+                
+                image.mipmaps = header.mipMapCount;
+                image.compFormat = 0;
+           
+                switch(header.ddspf.fourCC)
+                { 
+                    case FOURCC_DXT1: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; 
+                    case FOURCC_DXT3: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; 
+                    case FOURCC_DXT5: image.compFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; 
+                    default: break;
+                }
             
             
-            image.width = width;
-            image.height = height;
-            image.mipmaps = mipMapCount;
-            image.format = fourCC;
+                // NOTE: Image num color components not required... for now...
+                //if (fourCC == FOURCC_DXT1) image.components = 3;
+                //else image.components = 4;
+#endif
+            }
         }
         }
     }
     }
     
     

+ 44 - 72
src/utils.c

@@ -4,8 +4,9 @@
 *
 *
 *   Utils Functions Definitions
 *   Utils Functions Definitions
 *    
 *    
-*   Uses external lib:    
+*   Uses external libs:    
 *       tinfl - zlib DEFLATE algorithm decompression lib
 *       tinfl - zlib DEFLATE algorithm decompression lib
+*       stb_image_write - PNG writting functions
 *       
 *       
 *   Copyright (c) 2013 Ramon Santamaria (Ray San - [email protected])
 *   Copyright (c) 2013 Ramon Santamaria (Ray San - [email protected])
 *    
 *    
@@ -28,14 +29,14 @@
 
 
 #include "utils.h"
 #include "utils.h"
 
 
-#include <stdlib.h>         // malloc(), free()
-#include <stdio.h>          // printf(), fprintf()
-#include <stdarg.h>         // Used for functions with variable number of parameters (TraceLog())
-//#include <string.h>       // String management functions: strlen(), strrchr(), strcmp()
+#include <stdlib.h>             // malloc(), free()
+#include <stdio.h>              // printf(), fprintf()
+#include <stdarg.h>             // Used for functions with variable number of parameters (TraceLog())
+//#include <string.h>           // String management functions: strlen(), strrchr(), strcmp()
 
 
 #define STB_IMAGE_WRITE_IMPLEMENTATION
 #define STB_IMAGE_WRITE_IMPLEMENTATION
-
 #include "stb_image_write.h"    // Create PNG file
 #include "stb_image_write.h"    // Create PNG file
+
 #include "tinfl.c"
 #include "tinfl.c"
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
@@ -140,84 +141,39 @@ void WritePNG(const char *fileName, unsigned char *imgData, int width, int heigh
 // NOTE: If a file has been init, output log is written there
 // NOTE: If a file has been init, output log is written there
 void TraceLog(int msgType, const char *text, ...)
 void TraceLog(int msgType, const char *text, ...)
 {
 {
-    // TODO: This function requires some refactoring...
-
-    // NOTE: If trace log file has been set, stdout is being redirected to a file
     va_list args;
     va_list args;
     int traceDebugMsgs = 1;
     int traceDebugMsgs = 1;
     
     
 #ifdef DO_NOT_TRACE_DEBUG_MSGS
 #ifdef DO_NOT_TRACE_DEBUG_MSGS
     traceDebugMsgs = 0;
     traceDebugMsgs = 0;
 #endif
 #endif
+
+    // NOTE: If trace log file not set, output redirected to stdout 
+    if (logstream == NULL) logstream = stdout;
     
     
-    if (logstream != NULL)
+    switch(msgType)
     {
     {
-        switch(msgType)
-        {
-            case 0: fprintf(logstream, "INFO: "); break;
-            case 1: fprintf(logstream, "ERROR: "); break;
-            case 2: fprintf(logstream, "WARNING: "); break;
-            case 3: if (traceDebugMsgs) fprintf(logstream, "DEBUG: "); break;
-            default: break;
-        }
-        
-        if (msgType == 3)
-        {
-            if (traceDebugMsgs)
-            {
-                va_start(args, text);
-                vfprintf(logstream, text, args);
-                va_end(args);
-                
-                fprintf(logstream, "\n");
-            }
-        }
-        else
-        {
-            va_start(args, text);
-            vfprintf(logstream, text, args);
-            va_end(args);
-            
-            fprintf(logstream, "\n");
-        }
+        case INFO: fprintf(logstream, "INFO: "); break;
+        case ERROR: fprintf(logstream, "ERROR: "); break;
+        case WARNING: fprintf(logstream, "WARNING: "); break;
+        case DEBUG: if (traceDebugMsgs) fprintf(logstream, "DEBUG: "); break;
+        default: break;
     }
     }
-    else
-    {   
-        switch(msgType)
-        {
-            case 0: fprintf(stdout, "INFO: "); break;
-            case 1: fprintf(stdout, "ERROR: "); break;
-            case 2: fprintf(stdout, "WARNING: "); break;
-            case 3: if (traceDebugMsgs) fprintf(stdout, "DEBUG: "); break;
-            default: break;
-        }
+    
+    if ((msgType != DEBUG) || ((msgType == DEBUG) && (traceDebugMsgs)))
+    {
+        va_start(args, text);
+        vfprintf(logstream, text, args);
+        va_end(args);
         
         
-        if (msgType == 3)
-        {
-            if (traceDebugMsgs)
-            {
-                va_start(args, text);
-                vfprintf(stdout, text, args);
-                va_end(args);
-                
-                fprintf(stdout, "\n");
-            }
-        }
-        else
-        {
-            va_start(args, text);
-            vfprintf(stdout, text, args);
-            va_end(args);
-            
-            fprintf(stdout, "\n");
-        }
+        fprintf(logstream, "\n");
     }
     }
     
     
-    if (msgType == 1) exit(1);      // If ERROR message, exit program
+    if (msgType == ERROR) exit(1);      // If ERROR message, exit program
 }
 }
 
 
-// Inits a trace log file
-void InitTraceLogFile(const char *logFileName)
+// Open a trace log file (if desired)
+void TraceLogOpen(const char *logFileName)
 {
 {
     // stdout redirected to stream file
     // stdout redirected to stream file
     FILE *logstream = fopen(logFileName, "w");
     FILE *logstream = fopen(logFileName, "w");
@@ -225,9 +181,25 @@ void InitTraceLogFile(const char *logFileName)
     if (logstream == NULL) TraceLog(WARNING, "Unable to open log file");
     if (logstream == NULL) TraceLog(WARNING, "Unable to open log file");
 }
 }
 
 
-// Closes the trace log file
-void CloseTraceLogFile()
+// Close the trace log file
+void TraceLogClose()
 {
 {
     if (logstream != NULL) fclose(logstream);
     if (logstream != NULL) fclose(logstream);
 }
 }
 
 
+// Keep track of memory allocated
+// NOTE: mallocType defines the type of data allocated
+void RecordMalloc(int mallocType, int mallocSize, const char *msg)
+{
+    // TODO: Investigate how to record memory allocation data...
+    // Maybe creating my own malloc function...
+}
+
+// Get the extension for a filename
+const char *GetExtension(const char *fileName) 
+{
+    const char *dot = strrchr(fileName, '.');
+    if(!dot || dot == fileName) return "";
+    return (dot + 1);
+}
+

+ 6 - 7
src/utils.h

@@ -3,9 +3,6 @@
 *   raylib.utils
 *   raylib.utils
 *
 *
 *   Some utility functions: rRES files data decompression
 *   Some utility functions: rRES files data decompression
-*    
-*   Uses external lib:    
-*       tinfl - zlib DEFLATE algorithm decompression lib
 *       
 *       
 *   Copyright (c) 2013 Ramon Santamaria (Ray San - [email protected])
 *   Copyright (c) 2013 Ramon Santamaria (Ray San - [email protected])
 *    
 *    
@@ -32,12 +29,12 @@
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Some basic Defines
 // Some basic Defines
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
-//#define DO_NOT_TRACE_DEBUG_MSGS   // Use this define to avoid DEBUG tracing
+#define DO_NOT_TRACE_DEBUG_MSGS   // Use this define to avoid DEBUG tracing
 
 
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
 // Types and Structures Definition
 //----------------------------------------------------------------------------------
 //----------------------------------------------------------------------------------
-typedef enum { IMAGE, SOUND, MODEL, TEXT, RAW } DataType;
+typedef enum { IMAGE = 0, SOUND, MODEL, TEXT, RAW } DataType;
 
 
 typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
 typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType;
 
 
@@ -68,8 +65,10 @@ void WriteBitmap(const char *fileName, unsigned char *imgData, int width, int he
 void WritePNG(const char *fileName, unsigned char *imgData, int width, int height);
 void WritePNG(const char *fileName, unsigned char *imgData, int width, int height);
 
 
 void TraceLog(int msgType, const char *text, ...);  // Outputs a trace log message
 void TraceLog(int msgType, const char *text, ...);  // Outputs a trace log message
-void InitTraceLogFile(const char *logFileName);     // Inits a trace log file
-void CloseTraceLogFile();                           // Closes the trace log file
+void TraceLogOpen(const char *logFileName);         // Open a trace log file (if desired)
+void TraceLogClose();                               // Close the trace log file
+
+const char *GetExtension(const char *fileName);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }