فهرست منبع

Update to version 1.1.1

Check CHANGELOG for a detailed list of changes
raysan5 11 سال پیش
والد
کامیت
0b03431c95
17فایلهای تغییر یافته به همراه850 افزوده شده و 330 حذف شده
  1. 18 1
      CHANGELOG
  2. 1 1
      HELPME.md
  3. 3 1
      README.md
  4. 1 1
      ROADMAP.md
  5. 1 1
      examples/ex07b_3d_shapes.c
  6. 6 3
      release/win32-mingw/include/raylib.h
  7. BIN
      release/win32-mingw/lib/libraylib.a
  8. 144 3
      src/core.c
  9. 453 136
      src/models.c
  10. 5 2
      src/raylib.h
  11. 105 157
      src/rlgl.c
  12. 1 1
      src/rlgl.h
  13. 3 1
      src/text.c
  14. 22 18
      src/textures.c
  15. BIN
      tests/resources/cubesmap.png
  16. 83 0
      tests/test_cubesmap.c
  17. 4 4
      tests/test_heightmap.c

+ 18 - 1
CHANGELOG

@@ -1,11 +1,28 @@
 changelog
 ---------
 
-Current Release:    raylib 1.1.0 (April 2014)
+Current Release:    raylib 1.1.1 (22 July 2014)
 
 NOTE: Only versions marked as 'Release' are available on release folder, updates are only available as source.
 NOTE: Current Release includes all previous updates.
 
+-----------------------------------------------
+Release:     raylib 1.1.1 (22 July 2014)
+-----------------------------------------------
+[core] ShowLogo() - To enable raylib logo animation at startup
+[core] Corrected bug with window resizing
+[rlgl] Redefined colors arrays to use byte instead of float
+[rlgl] Removed double buffer system (no performance improvement)
+[rlgl] rlglDraw() - Reorganized buffers drawing order
+[rlgl] Corrected bug on screen resizing
+[models] DrawSphereWires() - Corrected some issues
+[models] LoadOBJ() - Redesigned to support multiple meshes
+[models] LoadCubesMap() - Loading a map as cubes (by pixel color)
+[textures] Added security check if file doesn't exist
+[text] Corrected bug on SpriteFont loading
+[examples] Corrected some 3d examples
+[test] Added cubesmap loading test
+
 -----------------------------------------------
 Release:     raylib 1.1.0 (19 April 2014)
 -----------------------------------------------

+ 1 - 1
HELPME.md

@@ -34,4 +34,4 @@ contact
    * Facebook: [http://www.facebook.com/raylibgames](http://www.facebook.com/raylibgames)
 
    
-[raysan5]: mailto:raysan5@gmail.com "Ramon Santamaria - Ray San"
+[raysan5]: mailto:raysan@raysanweb.com "Ramon Santamaria - Ray San"

+ 3 - 1
README.md

@@ -88,6 +88,8 @@ I believe those are the best tools to train spartan-programmers.
 Someone could argue about debugging. raylib is a library intended for learning and I think C it's a clear enough language
 to allow writing small-mid size programs with a printf-based debugging. All raylib examples have also been written this way.
 
+Since raylib v1.1, you can download a windows Installer package for easy installation and configuration. Check [raylib Webpage](http://www.raylib.com/)
+
 building
 --------
 
@@ -143,4 +145,4 @@ The following people have contributed in some way to make raylib project a reali
  - Victor Dual
  - Marc Palau
 	
-[raysan5]: mailto:raysan5@gmail.com "Ramon Santamaria - Ray San"
+[raysan5]: mailto:raysan@raysanweb.com "Ramon Santamaria - Ray San"

+ 1 - 1
ROADMAP.md

@@ -19,4 +19,4 @@ raylib v1.x
    
 Any feature missing? Do you have a request? [Let me know!][raysan5]
 
-[raysan5]: mailto:raysan5@gmail.com "Ramon Santamaria - Ray San"
+[raysan5]: mailto:raysan@raysanweb.com "Ramon Santamaria - Ray San"

+ 1 - 1
examples/ex07b_3d_shapes.c

@@ -47,7 +47,7 @@ int main()
                 DrawCubeWires((Vector3){-4, 0, -2}, 3, 6, 2, MAROON);
                 
                 DrawSphere((Vector3){-1, 0, -2}, 1, GREEN);     
-                DrawSphereWires((Vector3){1, 0, 2}, 2, LIME);
+                DrawSphereWires((Vector3){1, 0, 2}, 2, 16, 16, LIME);
                 
                 DrawCylinder((Vector3){4, 0, -2}, 1, 2, 3, 4, SKYBLUE);
                 DrawCylinderWires((Vector3){4, 0, -2}, 1, 2, 3, 4, DARKBLUE);

+ 6 - 3
release/win32-mingw/include/raylib.h

@@ -221,16 +221,16 @@ typedef struct Camera {
 } Camera;
 
 // Vertex data definning a mesh
-typedef struct {
+typedef struct VertexData {
     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
+    unsigned char *colors;      // 4 components per vertex
 } VertexData;
 
 // 3d Model type
-// NOTE: If using OpenGL 1.1 loaded in CPU (mesh); if OpenGL 3.3+ loaded in GPU (vaoId)
+// 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;
@@ -282,6 +282,8 @@ int GetHexValue(Color color);                               // Returns hexadecim
 int GetRandomValue(int min, int max);                       // Returns a random value between min and max (both included)
 Color Fade(Color color, float alpha);                       // Color fade-in or fade-out, alpha goes from 0.0 to 1.0
 
+void ShowLogo();                                            // Activates raylib logo at startup
+
 //------------------------------------------------------------------------------------
 // Input Handling Functions (Module: core)
 //------------------------------------------------------------------------------------
@@ -395,6 +397,7 @@ void DrawGizmoEx(Vector3 position, Vector3 rotation, float scale);
 Model LoadModel(const char *fileName);                                                             // Load a 3d model (.OBJ)
 //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 LoadCubesmap(Image cubesmap);                                                                // Load a map image as a 3d model (cubes based)
 void UnloadModel(Model model);                                                                     // Unload 3d model from memory
 void SetModelTexture(Model *model, Texture2D texture);                                             // Link a texture to a model
 

BIN
release/win32-mingw/lib/libraylib.a


+ 144 - 3
src/core.c

@@ -86,6 +86,8 @@ static int currentMouseWheelY = 0;          // Required to track mouse wheel var
 
 static Color background = { 0, 0, 0, 0 };   // Screen background color
 
+static bool showLogo = false;
+
 //----------------------------------------------------------------------------------
 // Other Modules Functions Declaration (required by core)
 //----------------------------------------------------------------------------------
@@ -103,6 +105,7 @@ static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
 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 TakeScreenshot();                                                              // Takes a screenshot and saves it in the same folder as executable
+static void LogoAnimation();                                                               // Plays raylib logo appearing animation
 
 //----------------------------------------------------------------------------------
 // Module Functions Definition - Window and OpenGL Context Functions
@@ -177,6 +180,13 @@ void InitWindowEx(int width, int height, const char* title, bool resizable, cons
     srand(time(NULL));              // Initialize random seed
     
     ClearBackground(RAYWHITE);      // Default background color for raylib games :P
+    
+    // raylib logo appearing animation
+    if (showLogo)
+    {
+        SetTargetFPS(60);
+        LogoAnimation();
+    }
 }
 
 // Close Window and Terminate Context
@@ -436,6 +446,12 @@ Color Fade(Color color, float alpha)
     return (Color){color.r, color.g, color.b, color.a*alpha};
 }
 
+// Activates raylib logo at startup
+void ShowLogo()
+{
+    showLogo = true;
+}
+
 //----------------------------------------------------------------------------------
 // Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions
 //----------------------------------------------------------------------------------
@@ -681,7 +697,7 @@ bool IsGamepadButtonUp(int gamepad, int button)
 // GLFW3 Error Callback, runs on GLFW3 error
 static void ErrorCallback(int error, const char *description)
 {
-    TraceLog(WARNING, "GLFW3 Error: %s", description);
+    TraceLog(WARNING, "[GLFW3 Error] Code: %i Decription: %s", error, description);
 }
 
 // GLFW3 Srolling Callback, runs on mouse wheel
@@ -721,9 +737,15 @@ static void WindowSizeCallback(GLFWwindow* window, int width, int height)
     int fbWidth, fbHeight;
     glfwGetFramebufferSize(window, &fbWidth, &fbHeight);    // Get framebuffer size of current window
 
-    // If window is resized, graphics device is re-initialized
-    // NOTE: Aspect ratio does not change, so, image can be deformed
+    // If window is resized, graphics device is re-initialized (but only ortho mode)
     rlglInitGraphicsDevice(fbWidth, fbHeight);
+    
+    // Window size must be updated to be used on 3D mode to get new aspect ratio (Begin3dMode())
+    windowWidth = fbWidth;
+    windowHeight = fbHeight;
+    
+    // Background must be also re-cleared
+    rlClearColor(background.r, background.g, background.b, background.a);
 }
 
 // Takes a bitmap (BMP) screenshot and saves it in the same folder as executable
@@ -747,4 +769,123 @@ static void TakeScreenshot()
     shotNum++;
     
     TraceLog(INFO, "[%s] Screenshot taken!", buffer);
+}
+
+static void LogoAnimation()
+{
+    int logoPositionX = windowWidth/2 - 128;
+    int logoPositionY = windowHeight/2 - 128;
+    
+    int framesCounter = 0;
+    int lettersCount = 0;
+    
+    int topSideRecWidth = 16;
+    int leftSideRecHeight = 16;
+    
+    int bottomSideRecWidth = 16;
+    int rightSideRecHeight = 16;
+    
+    char raylib[8] = "       ";     // raylib text array, max 8 letters
+    int state = 0;                  // Tracking animation states (State Machine)
+    float alpha = 1.0;              // Useful for fading
+    
+    while (!WindowShouldClose() && (state != 4))    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        if (state == 0)                 // State 0: Small box blinking
+        {
+            framesCounter++;
+        
+            if (framesCounter == 84)
+            {                
+                state = 1;
+                framesCounter = 0;      // Reset counter... will be used later...
+            }
+        }
+        else if (state == 1)            // State 1: Top and left bars growing
+        {
+            topSideRecWidth += 4;
+            leftSideRecHeight += 4;
+            
+            if (topSideRecWidth == 256) state = 2;
+        }
+        else if (state == 2)            // State 2: Bottom and right bars growing
+        {
+            bottomSideRecWidth += 4;
+            rightSideRecHeight += 4;
+            
+            if (bottomSideRecWidth == 256) state = 3;
+        }
+        else if (state == 3)            // State 3: Letters appearing (one by one)
+        {
+            framesCounter++;
+            
+            if (framesCounter/12)       // Every 12 frames, one more letter!
+            {    
+                lettersCount++;
+                framesCounter = 0;
+            }
+            
+            switch (lettersCount)
+            {
+                case 1: raylib[0] = 'r'; break;
+                case 2: raylib[1] = 'a'; break;
+                case 3: raylib[2] = 'y'; break;
+                case 4: raylib[3] = 'l'; break;
+                case 5: raylib[4] = 'i'; break;
+                case 6: raylib[5] = 'b'; break;
+                default: break;
+            }
+            
+            if (lettersCount >= 10)     // When all letters have appeared, just fade out everything
+            {
+                alpha -= 0.02;
+                
+                if (alpha <= 0)
+                {
+                    alpha = 0;
+                    state = 4;
+                }
+            }
+        }
+        //----------------------------------------------------------------------------------
+        
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+        
+            if (state == 0)
+            {
+                if ((framesCounter/12)%2) DrawRectangle(logoPositionX, logoPositionY, 16, 16, BLACK);
+            }
+            else if (state == 1)
+            {
+                DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK);
+                DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK);
+            }
+            else if (state == 2)
+            {
+                DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, BLACK);
+                DrawRectangle(logoPositionX, logoPositionY, 16, leftSideRecHeight, BLACK);
+                
+                DrawRectangle(logoPositionX + 240, logoPositionY, 16, rightSideRecHeight, BLACK);
+                DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, BLACK);
+            }
+            else if (state == 3)
+            {
+                DrawRectangle(logoPositionX, logoPositionY, topSideRecWidth, 16, Fade(BLACK, alpha));
+                DrawRectangle(logoPositionX, logoPositionY + 16, 16, leftSideRecHeight - 32, Fade(BLACK, alpha));
+                
+                DrawRectangle(logoPositionX + 240, logoPositionY + 16, 16, rightSideRecHeight - 32, Fade(BLACK, alpha));
+                DrawRectangle(logoPositionX, logoPositionY + 240, bottomSideRecWidth, 16, Fade(BLACK, alpha));
+                
+                DrawRectangle(windowWidth/2 - 112, windowHeight/2 - 112, 224, 224, Fade(RAYWHITE, alpha));
+                
+                DrawText(raylib, 356, 273, 50, Fade(BLACK, alpha));
+            }
+        
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
 }

+ 453 - 136
src/models.c

@@ -681,6 +681,7 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
     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));
+    vData.colors = (unsigned char *)malloc(vData.vertexCount * 4 * sizeof(unsigned char));
     
     int vCounter = 0;       // Used to count vertices float by float
     int tcCounter = 0;      // Used to count texcoords float by float
@@ -765,6 +766,9 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
     
     // NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct
 
+    // Fill color data
+    for (int i = 0; i < (4*vData.vertexCount); i++) vData.colors[i] = 255;
+    
     Model model;
 
     model.mesh = vData;                     // Model mesh is vertex data
@@ -783,6 +787,329 @@ Model LoadHeightmap(Image heightmap, float maxHeight)
     return model;
 }
 
+// Load a map image as a 3d model (cubes based)
+Model LoadCubesmap(Image cubesmap)
+{
+    VertexData vData;
+
+    // Map cube size will be 1.0
+    float mapCubeSide = 1.0f;
+    int mapWidth = cubesmap.width * (int)mapCubeSide;
+    int mapHeight = cubesmap.height * (int)mapCubeSide;
+    
+    // NOTE: Max possible number of triangles numCubes * (12 triangles by cube) 
+    int maxTriangles = cubesmap.width*cubesmap.height*12;
+
+    int vCounter = 0;       // Used to count vertices
+    int tcCounter = 0;      // Used to count texcoords
+    int nCounter = 0;       // Used to count normals
+    
+    float w = mapCubeSide;
+    float h = mapCubeSide;
+    float h2 = mapCubeSide;
+    
+    Vector3 *mapVertices = (Vector3 *)malloc(maxTriangles * 3 * sizeof(Vector3));
+    Vector2 *mapTexcoords = (Vector2 *)malloc(maxTriangles * 3 * sizeof(Vector2));
+	Vector3 *mapNormals = (Vector3 *)malloc(maxTriangles * 3 * sizeof(Vector3));
+    
+    for (int z = 0; z < mapHeight; z += mapCubeSide)
+    {
+        for (int x = 0; x < mapWidth; x += mapCubeSide)
+        {            
+            // Define the 8 vertex of the cube, we will combine them accordingly later...
+            Vector3 v1 = { x - w/2, h2, z - h/2 };
+            Vector3 v2 = { x - w/2, h2, z + h/2 };
+            Vector3 v3 = { x + w/2, h2, z + h/2 };
+            Vector3 v4 = { x + w/2, h2, z - h/2 };
+            Vector3 v5 = { x + w/2, 0, z - h/2 };
+            Vector3 v6 = { x - w/2, 0, z - h/2 };
+            Vector3 v7 = { x - w/2, 0, z + h/2 };
+            Vector3 v8 = { x + w/2, 0, z + h/2 };
+            
+            // Define the 6 normals of the cube, we will combine them accordingly later...
+            Vector3 n1 = { 1.0f, 0.0f, 0.0f };
+            Vector3 n2 = { -1.0f, 0.0f, 0.0f };
+            Vector3 n3 = { 0.0f, 1.0f, 0.0f };
+            Vector3 n4 = { 0.0f, -1.0f, 0.0f };
+            Vector3 n5 = { 0.0f, 0.0f, 1.0f };
+            Vector3 n6 = { 0.0f, 0.0f, -1.0f };
+            
+            // Define the 4 texture coordinates of the cube, we will combine them accordingly later...
+            // TODO: Use texture rectangles to define different textures for top-bottom-front-back-right-left (6)
+            Vector2 vt2 = { 0.0f, 0.0f }; 
+            Vector2 vt1 = { 0.0f, 1.0f };
+            Vector2 vt4 = { 1.0f, 0.0f };
+            Vector2 vt3 = { 1.0f, 1.0f };
+            
+            // We check pixel color to be WHITE, we will full cubes
+            if ((cubesmap.pixels[z*cubesmap.width + x].r == 255) &&
+                (cubesmap.pixels[z*cubesmap.width + x].g == 255) &&
+                (cubesmap.pixels[z*cubesmap.width + x].b == 255))
+            {
+                // Define triangles (Checking Collateral Cubes!)
+                //----------------------------------------------
+                
+                // Define top triangles (2 tris, 6 vertex --> v1-v2-v3, v1-v3-v4)
+                mapVertices[vCounter] = v1;
+                mapVertices[vCounter + 1] = v2; 
+                mapVertices[vCounter + 2] = v3; 
+                mapVertices[vCounter + 3] = v1; 
+                mapVertices[vCounter + 4] = v3; 
+                mapVertices[vCounter + 5] = v4;
+                vCounter += 6;
+                
+                mapNormals[nCounter] = n3;
+                mapNormals[nCounter + 1] = n3; 
+                mapNormals[nCounter + 2] = n3; 
+                mapNormals[nCounter + 3] = n3; 
+                mapNormals[nCounter + 4] = n3; 
+                mapNormals[nCounter + 5] = n3;
+                nCounter += 6;
+                
+                mapTexcoords[tcCounter] = vt2;
+                mapTexcoords[tcCounter + 1] = vt1; 
+                mapTexcoords[tcCounter + 2] = vt3; 
+                mapTexcoords[tcCounter + 3] = vt2; 
+                mapTexcoords[tcCounter + 4] = vt3; 
+                mapTexcoords[tcCounter + 5] = vt4;
+                tcCounter += 6;
+                
+                // Define bottom triangles (2 tris, 6 vertex --> v6-v8-v7, v6-v5-v8)
+                mapVertices[vCounter] = v6;
+                mapVertices[vCounter + 1] = v8; 
+                mapVertices[vCounter + 2] = v7; 
+                mapVertices[vCounter + 3] = v6; 
+                mapVertices[vCounter + 4] = v5; 
+                mapVertices[vCounter + 5] = v8;
+                vCounter += 6;
+                
+                mapNormals[nCounter] = n4;
+                mapNormals[nCounter + 1] = n4; 
+                mapNormals[nCounter + 2] = n4; 
+                mapNormals[nCounter + 3] = n4; 
+                mapNormals[nCounter + 4] = n4; 
+                mapNormals[nCounter + 5] = n4;
+                nCounter += 6;
+                
+                mapTexcoords[tcCounter] = vt4;
+                mapTexcoords[tcCounter + 1] = vt1; 
+                mapTexcoords[tcCounter + 2] = vt3; 
+                mapTexcoords[tcCounter + 3] = vt4; 
+                mapTexcoords[tcCounter + 4] = vt2; 
+                mapTexcoords[tcCounter + 5] = vt1;
+                tcCounter += 6;
+                
+                if (((z < cubesmap.height - 1) && 
+                (cubesmap.pixels[(z + 1)*cubesmap.width + x].r == 0) &&
+                (cubesmap.pixels[(z + 1)*cubesmap.width + x].g == 0) &&
+                (cubesmap.pixels[(z + 1)*cubesmap.width + x].b == 0)) || (z == cubesmap.height - 1))
+                {
+                    // Define front triangles (2 tris, 6 vertex) --> v2 v7 v3, v3 v7 v8
+                    // NOTE: Collateral occluded faces are not generated
+                    mapVertices[vCounter] = v2;
+                    mapVertices[vCounter + 1] = v7; 
+                    mapVertices[vCounter + 2] = v3; 
+                    mapVertices[vCounter + 3] = v3; 
+                    mapVertices[vCounter + 4] = v7; 
+                    mapVertices[vCounter + 5] = v8;
+                    vCounter += 6;
+                    
+                    mapNormals[nCounter] = n6;
+                    mapNormals[nCounter + 1] = n6; 
+                    mapNormals[nCounter + 2] = n6; 
+                    mapNormals[nCounter + 3] = n6; 
+                    mapNormals[nCounter + 4] = n6; 
+                    mapNormals[nCounter + 5] = n6;
+                    nCounter += 6;
+                    
+                    mapTexcoords[tcCounter] = vt2;
+                    mapTexcoords[tcCounter + 1] = vt1; 
+                    mapTexcoords[tcCounter + 2] = vt4; 
+                    mapTexcoords[tcCounter + 3] = vt4; 
+                    mapTexcoords[tcCounter + 4] = vt1; 
+                    mapTexcoords[tcCounter + 5] = vt3;
+                    tcCounter += 6;
+                }
+                
+                if (((z > 0) &&
+                (cubesmap.pixels[(z - 1)*cubesmap.width + x].r == 0) &&
+                (cubesmap.pixels[(z - 1)*cubesmap.width + x].g == 0) &&
+                (cubesmap.pixels[(z - 1)*cubesmap.width + x].b == 0)) || (z == 0))
+                {
+                    // Define back triangles (2 tris, 6 vertex) --> v1 v5 v6, v1 v4 v5
+                    // NOTE: Collateral occluded faces are not generated
+                    mapVertices[vCounter] = v1;
+                    mapVertices[vCounter + 1] = v5; 
+                    mapVertices[vCounter + 2] = v6; 
+                    mapVertices[vCounter + 3] = v1; 
+                    mapVertices[vCounter + 4] = v4; 
+                    mapVertices[vCounter + 5] = v5;
+                    vCounter += 6;
+                    
+                    mapNormals[nCounter] = n5;
+                    mapNormals[nCounter + 1] = n5; 
+                    mapNormals[nCounter + 2] = n5; 
+                    mapNormals[nCounter + 3] = n5; 
+                    mapNormals[nCounter + 4] = n5; 
+                    mapNormals[nCounter + 5] = n5;
+                    nCounter += 6;
+                    
+                    mapTexcoords[tcCounter] = vt4;
+                    mapTexcoords[tcCounter + 1] = vt1; 
+                    mapTexcoords[tcCounter + 2] = vt3; 
+                    mapTexcoords[tcCounter + 3] = vt4; 
+                    mapTexcoords[tcCounter + 4] = vt2; 
+                    mapTexcoords[tcCounter + 5] = vt1;
+                    tcCounter += 6;
+                }
+                
+                if (((x < cubesmap.width - 1) &&
+                (cubesmap.pixels[z*cubesmap.width + (x + 1)].r == 0) &&
+                (cubesmap.pixels[z*cubesmap.width + (x + 1)].g == 0) &&
+                (cubesmap.pixels[z*cubesmap.width + (x + 1)].b == 0)) || (x == cubesmap.width - 1))
+                {
+                    // Define right triangles (2 tris, 6 vertex) --> v3 v8 v4, v4 v8 v5
+                    // NOTE: Collateral occluded faces are not generated
+                    mapVertices[vCounter] = v3;
+                    mapVertices[vCounter + 1] = v8; 
+                    mapVertices[vCounter + 2] = v4; 
+                    mapVertices[vCounter + 3] = v4; 
+                    mapVertices[vCounter + 4] = v8; 
+                    mapVertices[vCounter + 5] = v5;
+                    vCounter += 6;
+                    
+                    mapNormals[nCounter] = n1;
+                    mapNormals[nCounter + 1] = n1; 
+                    mapNormals[nCounter + 2] = n1; 
+                    mapNormals[nCounter + 3] = n1; 
+                    mapNormals[nCounter + 4] = n1; 
+                    mapNormals[nCounter + 5] = n1;
+                    nCounter += 6;
+                    
+                    mapTexcoords[tcCounter] = vt2;
+                    mapTexcoords[tcCounter + 1] = vt1; 
+                    mapTexcoords[tcCounter + 2] = vt4; 
+                    mapTexcoords[tcCounter + 3] = vt4; 
+                    mapTexcoords[tcCounter + 4] = vt1; 
+                    mapTexcoords[tcCounter + 5] = vt3;
+                    tcCounter += 6;
+                }
+                
+                if (((x > 0) &&
+                (cubesmap.pixels[z*cubesmap.width + (x - 1)].r == 0) &&
+                (cubesmap.pixels[z*cubesmap.width + (x - 1)].g == 0) &&
+                (cubesmap.pixels[z*cubesmap.width + (x - 1)].b == 0)) || (x == 0))
+                {
+                    // Define left triangles (2 tris, 6 vertex) --> v1 v7 v2, v1 v6 v7
+                    // NOTE: Collateral occluded faces are not generated
+                    mapVertices[vCounter] = v1;
+                    mapVertices[vCounter + 1] = v7; 
+                    mapVertices[vCounter + 2] = v2; 
+                    mapVertices[vCounter + 3] = v1; 
+                    mapVertices[vCounter + 4] = v6; 
+                    mapVertices[vCounter + 5] = v7;
+                    vCounter += 6;
+                    
+                    mapNormals[nCounter] = n2;
+                    mapNormals[nCounter + 1] = n2; 
+                    mapNormals[nCounter + 2] = n2; 
+                    mapNormals[nCounter + 3] = n2; 
+                    mapNormals[nCounter + 4] = n2; 
+                    mapNormals[nCounter + 5] = n2;
+                    nCounter += 6;
+                    
+                    mapTexcoords[tcCounter] = vt2;
+                    mapTexcoords[tcCounter + 1] = vt3; 
+                    mapTexcoords[tcCounter + 2] = vt4; 
+                    mapTexcoords[tcCounter + 3] = vt2; 
+                    mapTexcoords[tcCounter + 4] = vt1; 
+                    mapTexcoords[tcCounter + 5] = vt3;
+                    tcCounter += 6;
+                }
+            }
+            // We check pixel color to be BLACK, we will only draw floor and roof
+            else if  ((cubesmap.pixels[z*cubesmap.width + x].r == 0) &&
+                      (cubesmap.pixels[z*cubesmap.width + x].g == 0) &&
+                      (cubesmap.pixels[z*cubesmap.width + x].b == 0))
+            {
+                // Define top triangles (2 tris, 6 vertex --> v1-v3-v2, v1-v4-v3)
+                // TODO: ...
+                
+                // Define bottom triangles (2 tris, 6 vertex --> v6-v7-v8, v6-v8-v5) 
+                // TODO: ...
+            }
+        }	
+    }
+
+    // Move data from mapVertices temp arays to vertices float array
+    vData.vertexCount = vCounter;
+    
+    printf("Vertex count: %i\n", vCounter);
+
+    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));
+    vData.colors = (unsigned char *)malloc(vData.vertexCount * 4 * sizeof(unsigned char));
+    
+    // Fill color data
+    for (int i = 0; i < (4*vData.vertexCount); i++) vData.colors[i] = 255;
+    
+    int fCounter = 0;
+    
+    // Move vertices data
+    for (int i = 0; i < vCounter; i++)
+    {
+        vData.vertices[fCounter] = mapVertices[i].x;
+        vData.vertices[fCounter + 1] = mapVertices[i].y;
+        vData.vertices[fCounter + 2] = mapVertices[i].z;
+        fCounter += 3;
+    }
+    
+    fCounter = 0;
+    
+    // Move normals data
+    for (int i = 0; i < nCounter; i++)
+    {
+        vData.normals[fCounter] = mapNormals[i].x;
+        vData.normals[fCounter + 1] = mapNormals[i].y;
+        vData.normals[fCounter + 2] = mapNormals[i].z;
+        fCounter += 3;
+    }
+        
+    fCounter = 0;
+    
+    // Move texcoords data
+    for (int i = 0; i < tcCounter; i++)
+    {
+        vData.texcoords[fCounter] = mapTexcoords[i].x;
+        vData.texcoords[fCounter + 1] = mapTexcoords[i].y;
+        fCounter += 2;
+    }
+    
+    free(mapVertices);
+    free(mapNormals);
+    free(mapTexcoords);
+    
+    // NOTE: At this point we have all vertex, texcoord, normal data for the model in vData struct
+    
+    Model model;
+
+    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
+    //free(vData.vertices);
+    //free(vData.texcoords);
+    //free(vData.normals);
+#endif
+    
+    return model;
+}
+
 // Unload 3d model from memory
 void UnloadModel(Model model)
 {
@@ -945,141 +1272,81 @@ static VertexData LoadOBJ(const char *fileName)
 
     objFile = fopen(fileName, "rt");
     
-    // First pass over all file to get numVertex, numNormals, numTexCoords, numTriangles
+    // First reading pass: Get numVertex, numNormals, numTexCoords, numTriangles
     // NOTE: vertex, texcoords and normals could be optimized (to be used indexed on faces definition)
+    // NOTE: faces MUST be defined as TRIANGLES, not QUADS
     while(!feof(objFile))
     {
         fscanf(objFile, "%c", &dataType);
         
         switch(dataType)
         {
-            case '#':         // It's a comment
+            case '#':   // Comments
+            case 'o':   // Object name (One OBJ file can contain multible named meshes)
+            case 'g':   // Group name
+            case 's':   // Smoothing level
+            case 'm':   // mtllib [external .mtl file name]
+            case 'u':   // usemtl [material name]
             {
-                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;
+                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);
-                    }
-                    
+                    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);
-                    }
-                
+                    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);
-                    }
-                    
+                    numVertex++;
                     fgets(comments, 200, objFile);
                 }
             } break;
             case 'f':
             {
+                numTriangles++;
                 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;
         }
     }
     
+    TraceLog(DEBUG, "[%s] Model num vertices: %i", fileName, numVertex);
+    TraceLog(DEBUG, "[%s] Model num texcoords: %i", fileName, numTexCoords);
+    TraceLog(DEBUG, "[%s] Model num normals: %i", fileName, numNormals);
+    TraceLog(DEBUG, "[%s] Model num triangles: %i", fileName, numTriangles);
+    
     // 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));
-    
+    Vector3 *midNormals;
+    if (numNormals > 0) midNormals = (Vector3 *)malloc(numNormals*sizeof(Vector3));
+    Vector2 *midTexCoords;
+    if (numTexCoords > 0) midTexCoords = (Vector2 *)malloc(numTexCoords*sizeof(Vector2));
+
     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
+    // Second reading pass: Get vertex data to fill intermediate arrays
+    // NOTE: This second pass is required in case of multiple meshes defined in same OBJ
+    // TODO: Consider that diferent meshes can have different vertex data available (position, texcoords, normals)
     while(!feof(objFile))
     {
         fscanf(objFile, "%c", &dataType);
         
         switch(dataType)
         {
-            case '#': 
-            {
-                fgets(comments, 200, objFile);                
-            } break;
+            case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'f': fgets(comments, 200, objFile); break; 
             case 'v': 
             {
                 fscanf(objFile, "%c", &dataType);
@@ -1108,60 +1375,107 @@ static VertexData LoadOBJ(const char *fileName)
                     fscanf(objFile, "%c", &dataType);
                 }
             } break;
+            default: break;
+        }
+    }
+    
+    // At this point all vertex data (v, vt, vn) has been gathered on midVertices, midTexCoords, midNormals
+    // Now we can organize that data into our VertexData struct
+    
+    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 = (unsigned char *)malloc(vData.vertexCount * 4 * sizeof(unsigned char));
+    
+    int vCounter = 0;       // Used to count vertices float by float
+    int tcCounter = 0;      // Used to count texcoords float by float
+    int nCounter = 0;       // Used to count normals float by float
+    
+    int vNum[3], vtNum[3], vnNum[3];
+    
+    rewind(objFile);        // Return to the beginning of the file, to read again
+    
+    if (numNormals == 0) TraceLog(INFO, "[%s] No normals data on OBJ, normals will be generated from faces data", fileName);
+    
+    // Third reading pass: Get faces (triangles) data and fill VertexArray
+    while(!feof(objFile))
+    {
+        fscanf(objFile, "%c", &dataType);
+        
+        switch(dataType)
+        {
+            case '#': case 'o': case 'g': case 's': case 'm': case 'u': case 'v': fgets(comments, 200, objFile); 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);
+                // NOTE: It could be that OBJ does not have normals or texcoords defined!
                 
-                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;
+                if ((numNormals == 0) && (numTexCoords == 0)) fscanf(objFile, "%i %i %i", &vNum[0], &vNum[1], &vNum[2]);
+                else if (numNormals == 0) fscanf(objFile, "%i/%i %i/%i %i/%i", &vNum[0], &vtNum[0], &vNum[1], &vtNum[1], &vNum[2], &vtNum[2]);
+                else fscanf(objFile, "%i/%i/%i %i/%i/%i %i/%i/%i", &vNum[0], &vtNum[0], &vnNum[0], &vNum[1], &vtNum[1], &vnNum[1], &vNum[2], &vtNum[2], &vnNum[2]);
                 
-                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;
+                vData.vertices[vCounter] = midVertices[vNum[0]-1].x;
+                vData.vertices[vCounter + 1] = midVertices[vNum[0]-1].y;
+                vData.vertices[vCounter + 2] = midVertices[vNum[0]-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;
+                vData.vertices[vCounter] = midVertices[vNum[1]-1].x;
+                vData.vertices[vCounter + 1] = midVertices[vNum[1]-1].y;
+                vData.vertices[vCounter + 2] = midVertices[vNum[1]-1].z;
+                vCounter += 3;
+                vData.vertices[vCounter] = midVertices[vNum[2]-1].x;
+                vData.vertices[vCounter + 1] = midVertices[vNum[2]-1].y;
+                vData.vertices[vCounter + 2] = midVertices[vNum[2]-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;
+                if (numNormals > 0)
+                {
+                    vData.normals[nCounter] = midNormals[vnNum[0]-1].x;
+                    vData.normals[nCounter + 1] = midNormals[vnNum[0]-1].y;
+                    vData.normals[nCounter + 2] = midNormals[vnNum[0]-1].z;
+                    nCounter += 3;
+                    vData.normals[nCounter] = midNormals[vnNum[1]-1].x;
+                    vData.normals[nCounter + 1] = midNormals[vnNum[1]-1].y;
+                    vData.normals[nCounter + 2] = midNormals[vnNum[1]-1].z;
+                    nCounter += 3;
+                    vData.normals[nCounter] = midNormals[vnNum[2]-1].x;
+                    vData.normals[nCounter + 1] = midNormals[vnNum[2]-1].y;
+                    vData.normals[nCounter + 2] = midNormals[vnNum[2]-1].z;
+                    nCounter += 3;
+                }
+                else
+                {
+                    // If normals not defined, they are calculated from the 3 vertices [N = (V2 - V1) x (V3 - V1)]
+                    Vector3 norm = VectorCrossProduct(VectorSubtract(midVertices[vNum[1]-1], midVertices[vNum[0]-1]), VectorSubtract(midVertices[vNum[2]-1], midVertices[vNum[0]-1]));
+                    VectorNormalize(&norm);
+                    
+                    vData.normals[nCounter] = norm.x;
+                    vData.normals[nCounter + 1] = norm.y;
+                    vData.normals[nCounter + 2] = norm.z;
+                    nCounter += 3;
+                    vData.normals[nCounter] = norm.x;
+                    vData.normals[nCounter + 1] = norm.y;
+                    vData.normals[nCounter + 2] = norm.z;
+                    nCounter += 3;
+                    vData.normals[nCounter] = norm.x;
+                    vData.normals[nCounter + 1] = norm.y;
+                    vData.normals[nCounter + 2] = norm.z;
+                    nCounter += 3;
+                }
                 
-                vData.texcoords[tcCounter] = midTexCoords[vtNum-1].x;
-                vData.texcoords[tcCounter + 1] = -midTexCoords[vtNum-1].y;
-                tcCounter += 2;
+                if (numTexCoords > 0)
+                {
+                    vData.texcoords[tcCounter] = midTexCoords[vtNum[0]-1].x;
+                    vData.texcoords[tcCounter + 1] = -midTexCoords[vtNum[0]-1].y;
+                    tcCounter += 2;
+                    vData.texcoords[tcCounter] = midTexCoords[vtNum[1]-1].x;
+                    vData.texcoords[tcCounter + 1] = -midTexCoords[vtNum[1]-1].y;
+                    tcCounter += 2;
+                    vData.texcoords[tcCounter] = midTexCoords[vtNum[2]-1].x;
+                    vData.texcoords[tcCounter + 1] = -midTexCoords[vtNum[2]-1].y;
+                    tcCounter += 2;
+                }
             } break;
             default: break;
         }
@@ -1169,8 +1483,11 @@ static VertexData LoadOBJ(const char *fileName)
     
     fclose(objFile);
     
+    // Security check, just in case no normals or no texcoords defined in OBJ
+    if (numTexCoords == 0) for (int i = 0; i < (2*vData.vertexCount); i++) vData.texcoords[i] = 0.0f;
+    
     // NOTE: We set all vertex colors to white
-    for (int i = 0; i < (4*vData.vertexCount); i++) vData.colors[i] = 1.0f;
+    for (int i = 0; i < (4*vData.vertexCount); i++) vData.colors[i] = 255;
     
     // Now we can free temp mid* arrays
     free(midVertices);

+ 5 - 2
src/raylib.h

@@ -226,11 +226,11 @@ typedef struct VertexData {
     float *vertices;            // 3 components per vertex
     float *texcoords;           // 2 components per vertex
     float *normals;             // 3 components per vertex
-    float *colors;              // 4 components per vertex
+    unsigned char *colors;      // 4 components per vertex
 } VertexData;
 
 // 3d Model type
-// NOTE: If using OpenGL 1.1 loaded in CPU (mesh); if OpenGL 3.3+ loaded in GPU (vaoId)
+// 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;
@@ -282,6 +282,8 @@ int GetHexValue(Color color);                               // Returns hexadecim
 int GetRandomValue(int min, int max);                       // Returns a random value between min and max (both included)
 Color Fade(Color color, float alpha);                       // Color fade-in or fade-out, alpha goes from 0.0 to 1.0
 
+void ShowLogo();                                            // Activates raylib logo at startup
+
 //------------------------------------------------------------------------------------
 // Input Handling Functions (Module: core)
 //------------------------------------------------------------------------------------
@@ -395,6 +397,7 @@ void DrawGizmoEx(Vector3 position, Vector3 rotation, float scale);
 Model LoadModel(const char *fileName);                                                             // Load a 3d model (.OBJ)
 //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 LoadCubesmap(Image cubesmap);                                                                // Load a map image as a 3d model (cubes based)
 void UnloadModel(Model model);                                                                     // Unload 3d model from memory
 void SetModelTexture(Model *model, Texture2D texture);                                             // Link a texture to a model
 

+ 105 - 157
src/rlgl.c

@@ -58,8 +58,6 @@
 
 //#include "glad.h"         // Other extensions loading lib? --> REVIEW
 
-#define USE_VBO_DOUBLE_BUFFERS    // Enable VBO double buffers usage --> REVIEW!
-
 //----------------------------------------------------------------------------------
 // Defines and Macros
 //----------------------------------------------------------------------------------
@@ -77,7 +75,7 @@ typedef struct {
     int vCounter;
     int cCounter;
     float *vertices;            // 3 components per vertex
-    float *colors;              // 4 components per vertex
+    unsigned char *colors;      // 4 components per vertex
 } VertexPositionColorBuffer;
 
 // Vertex buffer (position + texcoords + color arrays)
@@ -88,7 +86,7 @@ typedef struct {
     int cCounter;
     float *vertices;            // 3 components per vertex
     float *texcoords;           // 2 components per vertex
-    float *colors;              // 4 components per vertex
+    unsigned char *colors;      // 4 components per vertex
 } VertexPositionColorTextureBuffer;
 
 // Vertex buffer (position + texcoords + normals arrays)
@@ -110,7 +108,7 @@ typedef struct {
     int cCounter;
     float *vertices;            // 3 components per vertex
     float *texcoords;           // 2 components per vertex
-    float *colors;              // 4 components per vertex
+    unsigned char *colors;      // 4 components per vertex
     unsigned int *indices;      // 6 indices per quad
 } VertexPositionColorTextureIndexBuffer;
 
@@ -165,13 +163,6 @@ static GLuint linesBuffer[2];
 static GLuint trianglesBuffer[2];
 static GLuint quadsBuffer[4];
 
-#ifdef USE_VBO_DOUBLE_BUFFERS
-// Double buffering
-static GLuint vaoQuadsB;
-static GLuint quadsBufferB[4];
-static bool useBufferB = false;
-#endif
-
 static DrawCall *draws;
 static int drawsCounter;
 
@@ -566,7 +557,7 @@ void rlNormal3f(float x, float y, float z)
 }
 
 // Define one vertex (color)
-void rlColor4f(float x, float y, float z, float w)
+void rlColor4ub(byte x, byte y, byte z, byte w)
 {
     switch (currentDrawMode)
     {
@@ -605,15 +596,15 @@ void rlColor4f(float x, float y, float z, float w)
 }
 
 // Define one vertex (color)
-void rlColor4ub(byte r, byte g, byte b, byte a)
+void rlColor4f(float r, float g, float b, float a)
 {
-    rlColor4f((float)r/255, (float)g/255, (float)b/255, (float)a/255); 
+    rlColor4ub((byte)(r*255), (byte)(g*255), (byte)(b*255), (byte)(a*255)); 
 }
 
 // Define one vertex (color)
 void rlColor3f(float x, float y, float z)
 {
-    rlColor4f(x, y, z, 1.0);
+    rlColor4ub((byte)(x*255), (byte)(y*255), (byte)(z*255), 255);
 }
 
 #endif
@@ -826,48 +817,23 @@ void rlglClose()
 
 void rlglDraw()
 {
+    UpdateBuffers();
+    
     glUseProgram(shaderProgram);        // Use our shader
     
     glUniformMatrix4fv(projectionMatrixLoc, 1, false, GetMatrixVector(projection));
     glUniformMatrix4fv(modelviewMatrixLoc, 1, false, GetMatrixVector(modelview));
     glUniform1i(textureLoc, 0);
-
-    UpdateBuffers();
-
-    if (lines.vCounter > 0)
-    {
-        glBindTexture(GL_TEXTURE_2D, whiteTexture);
-    
-        glBindVertexArray(vaoLines);
-        glDrawArrays(GL_LINES, 0, lines.vCounter);
-        
-        glBindTexture(GL_TEXTURE_2D, 0);
-    }
-    
-    if (triangles.vCounter > 0)
-    {
-        glBindTexture(GL_TEXTURE_2D, whiteTexture);
-    
-        glBindVertexArray(vaoTriangles);
-        glDrawArrays(GL_TRIANGLES, 0, triangles.vCounter);
-        
-        glBindTexture(GL_TEXTURE_2D, 0);
-    }
     
+    // NOTE: We draw in this order: textured quads, triangles shapes, lines   
+   
     if (quads.vCounter > 0)
     {
         int quadsCount = 0;
         int numIndicesToProcess = 0;
         int indicesOffset = 0;
 
-#ifdef USE_VBO_DOUBLE_BUFFERS
-        // Depending on useBufferB, use Buffer A or Buffer B
-        if (useBufferB) glBindVertexArray(vaoQuadsB);
-        else
-#endif
-        { 
-            glBindVertexArray(vaoQuads);
-        }
+        glBindVertexArray(vaoQuads);
         
         //TraceLog(DEBUG, "Draws required per frame: %i", drawsCounter);
      
@@ -885,9 +851,30 @@ void rlglDraw()
 
             indicesOffset += draws[i].vertexCount/4*6;
         }
+        
+        glBindTexture(GL_TEXTURE_2D, 0);  // Unbind textures 
+    }
+    
+    if (triangles.vCounter > 0)
+    {
+        glBindTexture(GL_TEXTURE_2D, whiteTexture);
+    
+        glBindVertexArray(vaoTriangles);
+        glDrawArrays(GL_TRIANGLES, 0, triangles.vCounter);
+        
+        glBindTexture(GL_TEXTURE_2D, 0);
+    }
+    
+    if (lines.vCounter > 0)
+    {
+        glBindTexture(GL_TEXTURE_2D, whiteTexture);
+    
+        glBindVertexArray(vaoLines);
+        glDrawArrays(GL_LINES, 0, lines.vCounter);
+        
+        glBindTexture(GL_TEXTURE_2D, 0);
     }
     
-    glBindTexture(GL_TEXTURE_2D, 0);  // Unbind textures
     glBindVertexArray(0);   // Unbind VAO
     
     // Reset draws counter
@@ -905,11 +892,6 @@ void rlglDraw()
     quads.vCounter = 0;
     quads.tcCounter = 0;
     quads.cCounter = 0;
- 
-    // TODO: Review double buffer performance -> no improvement! (?)
-#ifdef USE_VBO_DOUBLE_BUFFERS
-    useBufferB = !useBufferB;   // Change buffers usage!
-#endif
 }
 
 #endif      // End for OpenGL 3.3+ and ES2 only functions
@@ -931,7 +913,7 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scal
     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.mesh.colors);   // Pointer to colors array (NOT USED)
     
     //TraceLog(DEBUG, "Drawing model.mesh, VertexCount: %i", model.mesh.vertexCount);
     
@@ -966,15 +948,36 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scal
     glUniformMatrix4fv(projectionMatrixLoc, 1, false, GetMatrixVector(projection));
     glUniformMatrix4fv(modelviewMatrixLoc, 1, false, GetMatrixVector(modelviewworld));
     glUniform1i(textureLoc, 0);
+
+    // Apply color tinting to model: 2 OPTIONS
+/*  
+    // OPTION 1
+    // Update colors array (model.mesh.colors) with color
+    int j = 0;
+    for (int i = 0; i < model.mesh.vertexCount; i++)
+    {
+        model.mesh.colors[j] = color.r;
+        model.mesh.colors[j+1] = color.g;
+        model.mesh.colors[j+2] = color.b;
+        model.mesh.colors[j+3] = color.a;
+        j += 4;
+    }
+    
+    // Update colors buffer in CPU (using Shader)
+    glBindVertexArray(model.vaoId);
+    GLuint colorVboId;
+    glGetVertexAttribIuiv(2, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &colorVboId);   // NOTE: Color VBO is buffer index 2
+    glBindBuffer(GL_ARRAY_BUFFER, colorVboId);
+    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*model.mesh.vertexCount, model.mesh.colors);
+   
+    // OPTION 2: Just update one uniform on fragment shader
+    // NOTE: It requires shader modification to add uniform (fragment shader) and create location point
+    //glUniform4f(fragmentUniformColorLoc, (float)color.r/255, (float)color.g/255, (float)color.b/255, (float)color.a/255);
+*/ 
     
     //TraceLog(DEBUG, "ShaderProgram: %i, VAO ID: %i, VertexCount: %i", shaderProgram, model.vaoId, model.mesh.vertexCount);
    
     glBindVertexArray(model.vaoId);
-    
-    // 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.mesh.vertexCount);
@@ -989,8 +992,8 @@ void rlglDrawModel(Model model, Vector3 position, Vector3 rotation, Vector3 scal
 // Initialize Graphics Device (OpenGL stuff)
 void rlglInitGraphicsDevice(int fbWidth, int fbHeight)
 {
-    //glViewport(0, 0, fbWidth, fbHeight);  // Set viewport width and height
-                                            // NOTE: Not required, viewport will be full window space
+    glViewport(0, 0, fbWidth, fbHeight);  // Set viewport width and height
+                                          // NOTE: Required! viewport must be recalculated if screen resized!
 
     // NOTE: Don't confuse glViewport with the transformation matrix
     // NOTE: glViewport just defines the area of the context that you will actually draw to.
@@ -1052,7 +1055,7 @@ unsigned int rlglLoadTexture(unsigned char *data, int width, int height, bool ge
     // 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)
+    if (genMipmaps && !texIsPOT)
     {
         TraceLog(WARNING, "[ID %i] Texture is not power-of-two, mipmaps can not be generated", id);
         
@@ -1194,26 +1197,29 @@ unsigned int rlglLoadModel(VertexData mesh)
     // Create buffers for our vertex data (positions, texcoords, normals)
     glGenBuffers(3, vertexBuffer);
  
-    // Enable vertex attributes
+    // Enable vertex attributes: position
     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]);
     glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.vertices, GL_STATIC_DRAW);
     glEnableVertexAttribArray(vertexLoc);
     glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
     
+    // Enable vertex attributes: texcoords
     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]);
     glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh.vertexCount, mesh.texcoords, GL_STATIC_DRAW);      
     glEnableVertexAttribArray(texcoordLoc);
     glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
     
+    // Enable vertex attributes: normals
     //glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]);
     //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh.vertexCount, mesh.normals, GL_STATIC_DRAW);   
     //glEnableVertexAttribArray(normalLoc);
     //glVertexAttribPointer(normalLoc, 3, GL_FLOAT, 0, 0, 0);
     
+    // Enable vertex attributes: colors
     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[2]);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*mesh.vertexCount, mesh.colors, GL_STATIC_DRAW);   
+    glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*mesh.vertexCount, mesh.colors, GL_STATIC_DRAW);   
     glEnableVertexAttribArray(colorLoc);
-    glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
+    glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 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)");
@@ -1408,34 +1414,34 @@ static char *TextFileRead(char *fn)
 static void InitializeBuffers()
 {
     // Initialize lines arrays (vertex position and color data)
-    lines.vertices = (float *)malloc(sizeof(float)*3*2*MAX_LINES_BATCH);    // 3 float by vertex, 2 vertex by line
-    lines.colors = (float *)malloc(sizeof(float)*4*2*MAX_LINES_BATCH);      // 4 float by color, 2 colors by line
+    lines.vertices = (float *)malloc(sizeof(float)*3*2*MAX_LINES_BATCH);        // 3 float by vertex, 2 vertex by line
+    lines.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*2*MAX_LINES_BATCH);  // 4 float by color, 2 colors by line
 
     for (int i = 0; i < (3*2*MAX_LINES_BATCH); i++) lines.vertices[i] = 0.0;
-    for (int i = 0; i < (4*2*MAX_LINES_BATCH); i++) lines.colors[i] = 0.0;
+    for (int i = 0; i < (4*2*MAX_LINES_BATCH); i++) lines.colors[i] = 0;
     
     lines.vCounter = 0;
     lines.cCounter = 0;
     
     // Initialize triangles arrays (vertex position and color data)
-    triangles.vertices = (float *)malloc(sizeof(float)*3*3*MAX_TRIANGLES_BATCH);    // 3 float by vertex, 3 vertex by triangle
-    triangles.colors = (float *)malloc(sizeof(float)*4*3*MAX_TRIANGLES_BATCH);      // 4 float by color, 3 colors by triangle
+    triangles.vertices = (float *)malloc(sizeof(float)*3*3*MAX_TRIANGLES_BATCH);        // 3 float by vertex, 3 vertex by triangle
+    triangles.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*3*MAX_TRIANGLES_BATCH);  // 4 float by color, 3 colors by triangle
 
     for (int i = 0; i < (3*3*MAX_TRIANGLES_BATCH); i++) triangles.vertices[i] = 0.0;
-    for (int i = 0; i < (4*3*MAX_TRIANGLES_BATCH); i++) triangles.colors[i] = 0.0;
+    for (int i = 0; i < (4*3*MAX_TRIANGLES_BATCH); i++) triangles.colors[i] = 0;
     
     triangles.vCounter = 0;
     triangles.cCounter = 0;
     
     // Initialize quads arrays (vertex position, texcoord and color data... and indexes)
-    quads.vertices = (float *)malloc(sizeof(float)*3*4*MAX_QUADS_BATCH);    // 3 float by vertex, 4 vertex by quad
-    quads.texcoords = (float *)malloc(sizeof(float)*2*4*MAX_QUADS_BATCH);   // 2 float by texcoord, 4 texcoord by quad
-    quads.colors = (float *)malloc(sizeof(float)*4*4*MAX_QUADS_BATCH);      // 4 float by color, 4 colors by quad
-    quads.indices = (unsigned int *)malloc(sizeof(int)*6*MAX_QUADS_BATCH);  // 6 int by quad (indices)
+    quads.vertices = (float *)malloc(sizeof(float)*3*4*MAX_QUADS_BATCH);        // 3 float by vertex, 4 vertex by quad
+    quads.texcoords = (float *)malloc(sizeof(float)*2*4*MAX_QUADS_BATCH);       // 2 float by texcoord, 4 texcoord by quad
+    quads.colors = (unsigned char *)malloc(sizeof(unsigned char)*4*4*MAX_QUADS_BATCH);  // 4 float by color, 4 colors by quad
+    quads.indices = (unsigned int *)malloc(sizeof(int)*6*MAX_QUADS_BATCH);      // 6 int by quad (indices)
     
     for (int i = 0; i < (3*4*MAX_QUADS_BATCH); i++) quads.vertices[i] = 0.0;
     for (int i = 0; i < (2*4*MAX_QUADS_BATCH); i++) quads.texcoords[i] = 0.0;
-    for (int i = 0; i < (4*4*MAX_QUADS_BATCH); i++) quads.colors[i] = 0.0;
+    for (int i = 0; i < (4*4*MAX_QUADS_BATCH); i++) quads.colors[i] = 0;
     
     int k = 0;
     
@@ -1475,9 +1481,9 @@ static void InitializeVAOs()
     
     // Lines - colors buffer
     glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW);
     glEnableVertexAttribArray(colorLoc);
-    glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
+    glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
     
     TraceLog(INFO, "[ID %i] Lines VAO initialized successfully", vaoLines);
     //-------------------------------------------------------------- 
@@ -1496,9 +1502,9 @@ static void InitializeVAOs()
     glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
     
     glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW);
     glEnableVertexAttribArray(colorLoc);
-    glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
+    glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
     
     TraceLog(INFO, "[ID %i] Triangles VAO initialized successfully", vaoTriangles);
     //-------------------------------------------------------------- 
@@ -1522,46 +1528,15 @@ static void InitializeVAOs()
     glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
     
     glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW);   
+    glBufferData(GL_ARRAY_BUFFER, sizeof(unsigned char)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW);   
     glEnableVertexAttribArray(colorLoc);
-    glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
+    glVertexAttribPointer(colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
     
     // Fill index buffer
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBuffer[3]);
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW);
     
     TraceLog(INFO, "[ID %i] Quads VAO initialized successfully", vaoQuads);
-    
-#ifdef USE_VBO_DOUBLE_BUFFERS
-    // Initialize Quads VAO (Buffer B)
-    glGenVertexArrays(1, &vaoQuadsB);
-    glBindVertexArray(vaoQuadsB);
- 
-    // Create buffers for our vertex data
-    glGenBuffers(4, quadsBufferB);
- 
-    // Enable vertex attributes
-    glBindBuffer(GL_ARRAY_BUFFER, quadsBufferB[0]);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW);
-    glEnableVertexAttribArray(vertexLoc);
-    glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0);
-    
-    glBindBuffer(GL_ARRAY_BUFFER, quadsBufferB[1]);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW);      
-    glEnableVertexAttribArray(texcoordLoc);
-    glVertexAttribPointer(texcoordLoc, 2, GL_FLOAT, 0, 0, 0);
-    
-    glBindBuffer(GL_ARRAY_BUFFER, quadsBufferB[2]);
-    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW);   
-    glEnableVertexAttribArray(colorLoc);
-    glVertexAttribPointer(colorLoc, 4, GL_FLOAT, 0, 0, 0);
-    
-    // Fill index buffer
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadsBufferB[3]);
-    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6*MAX_QUADS_BATCH, quads.indices, GL_STATIC_DRAW);
-    
-    TraceLog(INFO, "[ID %i] Second Quads VAO successfully initilized (double buffering)", vaoQuadsB);
-#endif
  
     // Unbind the current VAO
     glBindVertexArray(0);
@@ -1581,7 +1556,7 @@ static void UpdateBuffers()
     // Lines - colors buffer
     glBindBuffer(GL_ARRAY_BUFFER, linesBuffer[1]);
     //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*2*MAX_LINES_BATCH, lines.colors, GL_DYNAMIC_DRAW);
-    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*4*lines.vCounter, lines.colors);
+    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*lines.cCounter, lines.colors);
     
     //--------------------------------------------------------------    
     
@@ -1596,54 +1571,27 @@ static void UpdateBuffers()
     // Triangles - colors buffer
     glBindBuffer(GL_ARRAY_BUFFER, trianglesBuffer[1]);
     //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*3*MAX_TRIANGLES_BATCH, triangles.colors, GL_DYNAMIC_DRAW);
-    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*4*triangles.cCounter, triangles.colors);
+    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*triangles.cCounter, triangles.colors);
     
     //--------------------------------------------------------------
 
-    // Depending on useBufferB, update Buffer A or Buffer B
-#ifdef USE_VBO_DOUBLE_BUFFERS
-    if (useBufferB)
-    {
-        // Activate Quads VAO (Buffer B)
-        glBindVertexArray(vaoQuadsB);
-     
-        // Quads - vertex positions buffer
-        glBindBuffer(GL_ARRAY_BUFFER, quadsBufferB[0]);
-        //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW);
-        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*quads.vCounter, quads.vertices);
-
-        // Quads - texture coordinates buffer
-        glBindBuffer(GL_ARRAY_BUFFER, quadsBufferB[1]);
-        //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW);
-        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*quads.vCounter, quads.texcoords);
-        
-        // Quads - colors buffer
-        glBindBuffer(GL_ARRAY_BUFFER, quadsBufferB[2]);
-        //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW);
-        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*4*quads.vCounter, quads.colors);
-    }
-    else
-#endif
-    {
-        // Activate Quads VAO (Buffer A)
-        glBindVertexArray(vaoQuads);
-     
-        // Quads - vertex positions buffer
-        glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]);
-        //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW);
-        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*quads.vCounter, quads.vertices);
-
-        // Quads - texture coordinates buffer
-        glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]);
-        //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW);
-        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*quads.vCounter, quads.texcoords);
-        
-        // Quads - colors buffer
-        glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]);
-        //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW);
-        glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*4*quads.vCounter, quads.colors);
-    }
+    // Activate Quads VAO
+    glBindVertexArray(vaoQuads);
+ 
+    // Quads - vertex positions buffer
+    glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[0]);
+    //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*4*MAX_QUADS_BATCH, quads.vertices, GL_DYNAMIC_DRAW);
+    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*3*quads.vCounter, quads.vertices);
+
+    // Quads - texture coordinates buffer
+    glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[1]);
+    //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*4*MAX_QUADS_BATCH, quads.texcoords, GL_DYNAMIC_DRAW);
+    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*2*quads.vCounter, quads.texcoords);
     
+    // Quads - colors buffer
+    glBindBuffer(GL_ARRAY_BUFFER, quadsBuffer[2]);
+    //glBufferData(GL_ARRAY_BUFFER, sizeof(float)*4*4*MAX_QUADS_BATCH, quads.colors, GL_DYNAMIC_DRAW);
+    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(unsigned char)*4*quads.vCounter, quads.colors);
         
     // Another option would be using buffer mapping...
     //triangles.vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);

+ 1 - 1
src/rlgl.h

@@ -65,7 +65,7 @@ typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode;
         float *vertices;            // 3 components per vertex
         float *texcoords;           // 2 components per vertex
         float *normals;             // 3 components per vertex
-        float *colors;
+        unsigned char *colors;
     } VertexData;
 
     typedef struct Model {

+ 3 - 1
src/text.c

@@ -230,12 +230,14 @@ SpriteFont LoadSpriteFont(const char* fileName)
         
         // At this point we have a pixel array with all the data...
         
+        TraceLog(INFO, "[%s] SpriteFont image loaded: %i x %i", fileName, imgWidth, imgHeight);
+        
         // Process bitmap Font pixel data to get measures (Character array)
         // spriteFont.charSet data is filled inside the function and memory is allocated!
         int numChars = ParseImageData(imgDataPixel, imgWidth, imgHeight, &spriteFont.charSet);
         
         TraceLog(INFO, "[%s] SpriteFont data parsed correctly", fileName);
-        TraceLog(INFO, "[%s] SpriteFont num chars detected: %i", numChars);
+        TraceLog(INFO, "[%s] SpriteFont num chars detected: %i", fileName, numChars);
         
         spriteFont.numChars = numChars;
         

+ 22 - 18
src/textures.c

@@ -100,26 +100,30 @@ Image LoadImage(const char *fileName)
         // Force loading to 4 components (RGBA)
         byte *imgData = stbi_load(fileName, &imgWidth, &imgHeight, &imgBpp, 4);    
         
-        // Convert array to pixel array for working convenience
-        image.pixels = (Color *)malloc(imgWidth * imgHeight * sizeof(Color));
-        
-        int pix = 0;
-        
-        for (int i = 0; i < (imgWidth * imgHeight * 4); i += 4)
+        if (imgData != NULL)
         {
-            image.pixels[pix].r = imgData[i];
-            image.pixels[pix].g = imgData[i+1];
-            image.pixels[pix].b = imgData[i+2];
-            image.pixels[pix].a = imgData[i+3];
-            pix++;
+            // Convert array to pixel array for working convenience
+            image.pixels = (Color *)malloc(imgWidth * imgHeight * sizeof(Color));
+            
+            int pix = 0;
+            
+            for (int i = 0; i < (imgWidth * imgHeight * 4); i += 4)
+            {
+                image.pixels[pix].r = imgData[i];
+                image.pixels[pix].g = imgData[i+1];
+                image.pixels[pix].b = imgData[i+2];
+                image.pixels[pix].a = imgData[i+3];
+                pix++;
+            }
+            
+            stbi_image_free(imgData);
+            
+            image.width = imgWidth;
+            image.height = imgHeight;
+            
+            TraceLog(INFO, "[%s] Image loaded successfully", fileName);
         }
-        
-        stbi_image_free(imgData);
-        
-        image.width = imgWidth;
-        image.height = imgHeight;
-        
-        TraceLog(INFO, "[%s] Image loaded successfully", fileName);
+        else TraceLog(WARNING, "[%s] Image could not be loaded", fileName);
     }
     else if (strcmp(GetExtension(fileName),"dds") == 0)
     {

BIN
tests/resources/cubesmap.png


+ 83 - 0
tests/test_cubesmap.c

@@ -0,0 +1,83 @@
+/*******************************************************************************************
+*
+*   raylib test - Testing Heightmap Loading and Drawing
+*
+*   This test has been created using raylib 1.0 (www.raylib.com)
+*   raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
+*
+*   Copyright (c) 2014 Ramon Santamaria (Ray San - [email protected])
+*
+********************************************************************************************/
+
+#include "../raylib.h"
+
+int main()
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+    int screenWidth = 800;
+    int screenHeight = 450;
+
+    Vector3 position = { 0.5, 0.0, 0.5 };
+    
+    // Define the camera to look into our 3d world
+    Camera camera = {{ 7.0, 6.0, 7.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }};
+    
+    InitWindow(screenWidth, screenHeight, "raylib test - Heightmap loading and drawing");
+    
+    Image img = LoadImage("resources/cubesmap.png");
+    Model map = LoadCubesmap(img);
+    Texture2D texture = CreateTexture(img, false);
+    UnloadImage(img);
+    
+    SetModelTexture(&map, texture);  
+    
+    SetTargetFPS(60);   // Set our game to run at 60 frames-per-second
+    //--------------------------------------------------------------------------------------
+    
+    // Main game loop
+    while (!WindowShouldClose())    // Detect window close button or ESC key
+    {
+        // Update
+        //----------------------------------------------------------------------------------
+        if (IsKeyDown(KEY_UP)) camera.position.y += 0.2f;
+        else if (IsKeyDown(KEY_DOWN)) camera.position.y -= 0.2f;
+        
+        if (IsKeyDown(KEY_RIGHT)) camera.position.z += 0.2f;
+        else if (IsKeyDown(KEY_LEFT)) camera.position.z -= 0.2f;
+        //----------------------------------------------------------------------------------
+        
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+        
+            ClearBackground(RAYWHITE);
+            
+            Begin3dMode(camera);
+            
+                //DrawCube(position, 1.0f, 1.0f, 1.0f, RED);
+            
+                DrawModel(map, position, 1.0f, MAROON);
+                
+                DrawGrid(10.0, 1.0);        // Draw a grid
+                
+                DrawGizmo(position); 
+                
+            End3dMode();
+            
+            DrawFPS(10, 10);
+        
+        EndDrawing();
+        //----------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadTexture(texture);     // Unload texture
+    UnloadModel(map);       // Unload model
+    
+    CloseWindow();          // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+    
+    return 0;
+}

+ 4 - 4
tests/test_heightmap.c

@@ -30,7 +30,7 @@ int main()
     Texture2D texture = CreateTexture(img, false);
     UnloadImage(img);
     
-    SetModelTexture(&map, texture);  
+    SetModelTexture(&map, texture);
     
     SetTargetFPS(60);   // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
@@ -51,11 +51,11 @@ int main()
             
             Begin3dMode(camera);
             
-                DrawModel(map, position, 0.5f, MAROON);   
+                DrawModel(map, position, 0.5f, MAROON);
                 
                 DrawGrid(10.0, 1.0);        // Draw a grid
                 
-                DrawGizmo(position, false); 
+                DrawGizmo(position); 
                 
             End3dMode();
             
@@ -67,7 +67,7 @@ int main()
 
     // De-Initialization
     //--------------------------------------------------------------------------------------
-    UnloadTexture(tex);     // Unload texture
+    UnloadTexture(texture); // Unload texture
     UnloadModel(map);       // Unload model
     
     CloseWindow();          // Close window and OpenGL context