Browse Source

Working on PBR system

Moved PBR material loading to example, right decision?
raysan5 8 years ago
parent
commit
76c6f0b1e6
6 changed files with 398 additions and 301 deletions
  1. 95 100
      examples/models/models_material_pbr.c
  2. 2 1
      examples/models/resources/shaders/pbr.fs
  3. 177 0
      examples/models/rlights.h
  4. 27 76
      src/models.c
  5. 7 7
      src/raylib.h
  6. 90 117
      src/rlgl.c

+ 95 - 100
examples/models/models_material_pbr.c

@@ -12,32 +12,16 @@
 #include "raylib.h"
 #include "raymath.h"
 
-#define         MAX_LIGHTS            4         // Max lights supported by shader
-#define         LIGHT_DISTANCE        3.5f      // Light distance from world center
-#define         LIGHT_HEIGHT          1.0f      // Light height position
-
-typedef enum {
-    LIGHT_DIRECTIONAL,
-    LIGHT_POINT
-} LightType;
-
-typedef struct {
-    bool enabled;
-    LightType type;
-    Vector3 position;
-    Vector3 target;
-    Color color;
-    int enabledLoc;
-    int typeLoc;
-    int posLoc;
-    int targetLoc;
-    int colorLoc;
-} Light;
-
-int lightsCount = 0;                     // Current amount of created lights
-
-Light CreateLight(int type, Vector3 pos, Vector3 targ, Color color, Shader shader);         // Defines a light and get locations from PBR shader
-void UpdateLightValues(Shader shader, Light light);                                         // Send to PBR shader light values
+#define RLIGHTS_IMPLEMENTATION
+#include "rlights.h"
+
+#define CUBEMAP_SIZE         512        // Cubemap texture size
+#define IRRADIANCE_SIZE       32        // Irradiance texture size
+#define PREFILTERED_SIZE     256        // Prefiltered HDR environment texture size
+#define BRDF_SIZE            512        // BRDF LUT texture size
+
+// PBR material loading
+static Material LoadMaterialPBR(Color albedo, float metalness, float roughness);
 
 int main()
 {
@@ -54,33 +38,15 @@ int main()
 
     // Load model and PBR material
     Model model = LoadModel("resources/pbr/trooper.obj");
-    
-    Texture2D texHDR = LoadTexture("resources/pinetree.hdr");
-    model.material = LoadMaterialPBR(texHDR, (Color){ 255, 255, 255, 255 }, 1.0f, 1.0f);
-    
-    SetMaterialTexture(&model.material, MAP_ALBEDO, LoadTexture("resources/pbr/trooper_albedo.png"));
-    SetMaterialTexture(&model.material, MAP_NORMAL, LoadTexture("resources/pbr/trooper_normals.png"));
-    SetMaterialTexture(&model.material, MAP_METALNESS, LoadTexture("resources/pbr/trooper_metalness.png"));
-    SetMaterialTexture(&model.material, MAP_ROUGHNESS, LoadTexture("resources/pbr/trooper_roughness.png"));
-    SetMaterialTexture(&model.material, MAP_OCCLUSION, LoadTexture("resources/pbr/trooper_ao.png"));
-    
-    // Set textures filtering for better quality
-    SetTextureFilter(model.material.maps[MAP_ALBEDO].texture, FILTER_BILINEAR);
-    SetTextureFilter(model.material.maps[MAP_NORMAL].texture, FILTER_BILINEAR);
-    SetTextureFilter(model.material.maps[MAP_METALNESS].texture, FILTER_BILINEAR);
-    SetTextureFilter(model.material.maps[MAP_ROUGHNESS].texture, FILTER_BILINEAR);
-    SetTextureFilter(model.material.maps[MAP_OCCLUSION].texture, FILTER_BILINEAR);
-    
-    int renderModeLoc = GetShaderLocation(model.material.shader, "renderMode");
-    SetShaderValuei(model.material.shader, renderModeLoc, (int[1]){ 0 }, 1);
+    model.material = LoadMaterialPBR((Color){ 255, 255, 255, 255 }, 1.0f, 1.0f);
 
-    SetCameraMode(camera, CAMERA_ORBITAL);  // Set an orbital camera mode
-    
     // Define lights attributes
     Light lights[MAX_LIGHTS] = { CreateLight(LIGHT_POINT, (Vector3){ LIGHT_DISTANCE, LIGHT_HEIGHT, 0.0f }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 255, 0, 0, 255 }, model.material.shader),
     CreateLight(LIGHT_POINT, (Vector3){ 0.0f, LIGHT_HEIGHT, LIGHT_DISTANCE }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 0, 255, 0, 255 }, model.material.shader),
     CreateLight(LIGHT_POINT, (Vector3){ -LIGHT_DISTANCE, LIGHT_HEIGHT, 0.0f }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 0, 0, 255, 255 }, model.material.shader),
     CreateLight(LIGHT_DIRECTIONAL, (Vector3){ 0.0f, LIGHT_HEIGHT*2.0f, -LIGHT_DISTANCE }, (Vector3){ 0.0f, 0.0f, 0.0f }, (Color){ 255, 0, 255, 255 }, model.material.shader) };
+    
+    SetCameraMode(camera, CAMERA_ORBITAL);  // Set an orbital camera mode
 
     SetTargetFPS(60);                       // Set our game to run at 60 frames-per-second
     //--------------------------------------------------------------------------------------
@@ -127,59 +93,88 @@ int main()
     return 0;
 }
 
-// Defines a light and get locations from PBR shader
-Light CreateLight(int type, Vector3 pos, Vector3 targ, Color color, Shader shader)
+// Load PBR material (Supports: ALBEDO, NORMAL, METALNESS, ROUGHNESS, AO, EMMISIVE, HEIGHT maps)
+// NOTE: PBR shader is loaded inside this function
+static Material LoadMaterialPBR(Color albedo, float metalness, float roughness)
 {
-    Light light = { 0 };
-
-    if (lightsCount < MAX_LIGHTS)
-    {
-        light.enabled = true;
-        light.type = type;
-        light.position = pos;
-        light.target = targ;
-        light.color = color;
-
-        char enabledName[32] = "lights[x].enabled\0";
-        char typeName[32] = "lights[x].type\0";
-        char posName[32] = "lights[x].position\0";
-        char targetName[32] = "lights[x].target\0";
-        char colorName[32] = "lights[x].color\0";
-        enabledName[7] = '0' + lightsCount;
-        typeName[7] = '0' + lightsCount;
-        posName[7] = '0' + lightsCount;
-        targetName[7] = '0' + lightsCount;
-        colorName[7] = '0' + lightsCount;
-
-        light.enabledLoc = GetShaderLocation(shader, enabledName);
-        light.typeLoc = GetShaderLocation(shader, typeName);
-        light.posLoc = GetShaderLocation(shader, posName);
-        light.targetLoc = GetShaderLocation(shader, targetName);
-        light.colorLoc = GetShaderLocation(shader, colorName);
-
-        UpdateLightValues(shader, light);
-        lightsCount++;
-    }
-
-    return light;
-}
-
-// Send to PBR shader light values
-void UpdateLightValues(Shader shader, Light light)
-{
-    // Send to shader light enabled state and type
-    SetShaderValuei(shader, light.enabledLoc, (int[1]){ light.enabled }, 1);
-    SetShaderValuei(shader, light.typeLoc, (int[1]){ light.type }, 1);
-
-    // Send to shader light position values
-    float position[3] = { light.position.x, light.position.y, light.position.z };
-    SetShaderValue(shader, light.posLoc, position, 3);
-
-    // Send to shader light target position values
-    float target[3] = { light.target.x, light.target.y, light.target.z };
-    SetShaderValue(shader, light.targetLoc, target, 3);
+    Material mat = { 0 };       // NOTE: All maps textures are set to { 0 }
+    
+    #define     PATH_PBR_VS     "resources/shaders/pbr.vs"      // Path to physically based rendering vertex shader
+    #define     PATH_PBR_FS     "resources/shaders/pbr.fs"      // Path to physically based rendering fragment shader
+   
+    mat.shader = LoadShader(PATH_PBR_VS, PATH_PBR_FS);
+    
+    // Get required locations points for PBR material
+    // NOTE: Those location names must be available and used in the shader code
+    mat.shader.locs[LOC_MAP_ALBEDO] = GetShaderLocation(mat.shader, "albedo.sampler");
+    mat.shader.locs[LOC_MAP_METALNESS] = GetShaderLocation(mat.shader, "metalness.sampler");
+    mat.shader.locs[LOC_MAP_NORMAL] = GetShaderLocation(mat.shader, "normals.sampler");
+    mat.shader.locs[LOC_MAP_ROUGHNESS] = GetShaderLocation(mat.shader, "roughness.sampler");
+    mat.shader.locs[LOC_MAP_OCCUSION] = GetShaderLocation(mat.shader, "occlusion.sampler");
+    mat.shader.locs[LOC_MAP_EMISSION] = GetShaderLocation(mat.shader, "emission.sampler");
+    mat.shader.locs[LOC_MAP_HEIGHT] = GetShaderLocation(mat.shader, "height.sampler");
+    mat.shader.locs[LOC_MAP_IRRADIANCE] = GetShaderLocation(mat.shader, "irradianceMap");
+    mat.shader.locs[LOC_MAP_PREFILTER] = GetShaderLocation(mat.shader, "prefilterMap");
+    mat.shader.locs[LOC_MAP_BRDF] = GetShaderLocation(mat.shader, "brdfLUT");
+
+    // Set view matrix location
+    mat.shader.locs[LOC_MATRIX_MODEL] = GetShaderLocation(mat.shader, "mMatrix");
+    mat.shader.locs[LOC_MATRIX_VIEW] = GetShaderLocation(mat.shader, "view");
+    mat.shader.locs[LOC_VECTOR_VIEW] = GetShaderLocation(mat.shader, "viewPos");
+    
+    // Set PBR standard maps 
+    SetMaterialTexture(&mat, MAP_ALBEDO, LoadTexture("resources/pbr/trooper_albedo.png"));
+    SetMaterialTexture(&mat, MAP_NORMAL, LoadTexture("resources/pbr/trooper_normals.png"));
+    SetMaterialTexture(&mat, MAP_METALNESS, LoadTexture("resources/pbr/trooper_metalness.png"));
+    SetMaterialTexture(&mat, MAP_ROUGHNESS, LoadTexture("resources/pbr/trooper_roughness.png"));
+    SetMaterialTexture(&mat, MAP_OCCLUSION, LoadTexture("resources/pbr/trooper_ao.png"));
+    
+    // Set environment maps
+    #define     PATH_CUBEMAP_VS         "resources/shaders/cubemap.vs"          // Path to equirectangular to cubemap vertex shader
+    #define     PATH_CUBEMAP_FS         "resources/shaders/cubemap.fs"          // Path to equirectangular to cubemap fragment shader
+    #define     PATH_SKYBOX_VS          "resources/shaders/skybox.vs"           // Path to skybox vertex shader
+    #define     PATH_IRRADIANCE_FS      "resources/shaders/irradiance.fs"       // Path to irradiance (GI) calculation fragment shader
+    #define     PATH_SKYBOX_VS          "resources/shaders/skybox.vs"           // Path to skybox vertex shader
+    #define     PATH_PREFILTER_FS       "resources/shaders/prefilter.fs"        // Path to reflection prefilter calculation fragment shader
+    #define     PATH_BRDF_VS            "resources/shaders/brdf.vs"     // Path to bidirectional reflectance distribution function vertex shader 
+    #define     PATH_BRDF_FS            "resources/shaders/brdf.fs"     // Path to bidirectional reflectance distribution function fragment shader
+    
+    Shader shdrCubemap = LoadShader(PATH_CUBEMAP_VS, PATH_CUBEMAP_FS);
+    Shader shdrIrradiance = LoadShader(PATH_SKYBOX_VS, PATH_IRRADIANCE_FS);
+    Shader shdrPrefilter = LoadShader(PATH_SKYBOX_VS, PATH_PREFILTER_FS);
+    Shader shdrBRDF = LoadShader(PATH_BRDF_VS, PATH_BRDF_FS);
 
-    // Send to shader light color values
-    float diff[4] = { (float)light.color.r/(float)255, (float)light.color.g/(float)255, (float)light.color.b/(float)255, (float)light.color.a/(float)255 };
-    SetShaderValue(shader, light.colorLoc, diff, 4);
+    Texture2D texHDR = LoadTexture("resources/pinetree.hdr");
+    Texture2D cubemap = GenTextureCubemap(shdrCubemap, texHDR, CUBEMAP_SIZE);
+    SetMaterialTexture(&mat, MAP_IRRADIANCE, GenTextureIrradiance(shdrIrradiance, cubemap, IRRADIANCE_SIZE));
+    SetMaterialTexture(&mat, MAP_PREFILTER, GenTexturePrefilter(shdrPrefilter, cubemap, PREFILTERED_SIZE));
+    SetMaterialTexture(&mat, MAP_BRDF, GenTextureBRDF(shdrBRDF, cubemap, BRDF_SIZE));
+    UnloadTexture(cubemap);
+    UnloadTexture(texHDR);
+    
+    UnloadShader(shdrCubemap);
+    UnloadShader(shdrIrradiance);
+    UnloadShader(shdrPrefilter);
+    UnloadShader(shdrBRDF);
+    
+    // Set textures filtering for better quality
+    SetTextureFilter(mat.maps[MAP_ALBEDO].texture, FILTER_BILINEAR);
+    SetTextureFilter(mat.maps[MAP_NORMAL].texture, FILTER_BILINEAR);
+    SetTextureFilter(mat.maps[MAP_METALNESS].texture, FILTER_BILINEAR);
+    SetTextureFilter(mat.maps[MAP_ROUGHNESS].texture, FILTER_BILINEAR);
+    SetTextureFilter(mat.maps[MAP_OCCLUSION].texture, FILTER_BILINEAR);
+    
+    int renderModeLoc = GetShaderLocation(mat.shader, "renderMode");
+    SetShaderValuei(mat.shader, renderModeLoc, (int[1]){ 0 }, 1);
+
+    // Set up material properties color
+    mat.maps[MAP_ALBEDO].color = albedo;
+    mat.maps[MAP_NORMAL].color = (Color){ 128, 128, 255, 255 };
+    mat.maps[MAP_METALNESS].value = metalness;
+    mat.maps[MAP_ROUGHNESS].value = roughness;
+    mat.maps[MAP_OCCLUSION].value = 1.0f;
+    mat.maps[MAP_EMISSION].value = 0.5f;
+    mat.maps[MAP_HEIGHT].value = 0.5f;
+
+    return mat;
 }

+ 2 - 1
examples/models/resources/shaders/pbr.fs

@@ -8,10 +8,11 @@
 
 #version 330
 
-#define     MAX_LIGHTS              4
 #define     MAX_REFLECTION_LOD      4.0
 #define     MAX_DEPTH_LAYER         20
 #define     MIN_DEPTH_LAYER         10
+
+#define     MAX_LIGHTS              4
 #define     LIGHT_DIRECTIONAL       0
 #define     LIGHT_POINT             1
 

+ 177 - 0
examples/models/rlights.h

@@ -0,0 +1,177 @@
+/**********************************************************************************************
+*
+*   raylib.lights - Some useful functions to deal with lights data
+*
+*   CONFIGURATION:
+*
+*   #define RLIGHTS_IMPLEMENTATION
+*       Generates the implementation of the library into the included file.
+*       If not defined, the library is in header only mode and can be included in other headers 
+*       or source files without problems. But only ONE file should hold the implementation.
+*
+*   LICENSE: zlib/libpng
+*
+*   Copyright (c) 2017 Victor Fisac and Ramon Santamaria
+*
+*   This software is provided "as-is", without any express or implied warranty. In no event
+*   will the authors be held liable for any damages arising from the use of this software.
+*
+*   Permission is granted to anyone to use this software for any purpose, including commercial
+*   applications, and to alter it and redistribute it freely, subject to the following restrictions:
+*
+*     1. The origin of this software must not be misrepresented; you must not claim that you
+*     wrote the original software. If you use this software in a product, an acknowledgment
+*     in the product documentation would be appreciated but is not required.
+*
+*     2. Altered source versions must be plainly marked as such, and must not be misrepresented
+*     as being the original software.
+*
+*     3. This notice may not be removed or altered from any source distribution.
+*
+**********************************************************************************************/
+
+#ifndef RLIGHTS_H
+#define RLIGHTS_H
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+#define         MAX_LIGHTS            4         // Max lights supported by shader
+#define         LIGHT_DISTANCE        3.5f      // Light distance from world center
+#define         LIGHT_HEIGHT          1.0f      // Light height position
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+typedef enum {
+    LIGHT_DIRECTIONAL,
+    LIGHT_POINT
+} LightType;
+
+typedef struct {
+    bool enabled;
+    LightType type;
+    Vector3 position;
+    Vector3 target;
+    Color color;
+    int enabledLoc;
+    int typeLoc;
+    int posLoc;
+    int targetLoc;
+    int colorLoc;
+} Light;
+
+#ifdef __cplusplus
+extern "C" {            // Prevents name mangling of functions
+#endif
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+int lightsCount = 0;                     // Current amount of created lights
+
+//----------------------------------------------------------------------------------
+// Module Functions Declaration
+//----------------------------------------------------------------------------------
+Light CreateLight(int type, Vector3 pos, Vector3 targ, Color color, Shader shader);         // Defines a light and get locations from PBR shader
+void UpdateLightValues(Shader shader, Light light);                                         // Send to PBR shader light values
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // RLIGHTS_H
+
+
+/***********************************************************************************
+*
+*   RLIGHTS IMPLEMENTATION
+*
+************************************************************************************/
+
+#if defined(RLIGHTS_IMPLEMENTATION)
+
+#include "raylib.h"
+
+//----------------------------------------------------------------------------------
+// Defines and Macros
+//----------------------------------------------------------------------------------
+// ...
+
+//----------------------------------------------------------------------------------
+// Types and Structures Definition
+//----------------------------------------------------------------------------------
+// ...
+
+//----------------------------------------------------------------------------------
+// Global Variables Definition
+//----------------------------------------------------------------------------------
+// ...
+
+//----------------------------------------------------------------------------------
+// Module specific Functions Declaration
+//----------------------------------------------------------------------------------
+// ...
+
+//----------------------------------------------------------------------------------
+// Module Functions Definition
+//----------------------------------------------------------------------------------
+
+// Defines a light and get locations from PBR shader
+Light CreateLight(int type, Vector3 pos, Vector3 targ, Color color, Shader shader)
+{
+    Light light = { 0 };
+
+    if (lightsCount < MAX_LIGHTS)
+    {
+        light.enabled = true;
+        light.type = type;
+        light.position = pos;
+        light.target = targ;
+        light.color = color;
+
+        char enabledName[32] = "lights[x].enabled\0";
+        char typeName[32] = "lights[x].type\0";
+        char posName[32] = "lights[x].position\0";
+        char targetName[32] = "lights[x].target\0";
+        char colorName[32] = "lights[x].color\0";
+        enabledName[7] = '0' + lightsCount;
+        typeName[7] = '0' + lightsCount;
+        posName[7] = '0' + lightsCount;
+        targetName[7] = '0' + lightsCount;
+        colorName[7] = '0' + lightsCount;
+
+        light.enabledLoc = GetShaderLocation(shader, enabledName);
+        light.typeLoc = GetShaderLocation(shader, typeName);
+        light.posLoc = GetShaderLocation(shader, posName);
+        light.targetLoc = GetShaderLocation(shader, targetName);
+        light.colorLoc = GetShaderLocation(shader, colorName);
+
+        UpdateLightValues(shader, light);
+        lightsCount++;
+    }
+
+    return light;
+}
+
+// Send to PBR shader light values
+void UpdateLightValues(Shader shader, Light light)
+{
+    // Send to shader light enabled state and type
+    SetShaderValuei(shader, light.enabledLoc, (int[1]){ light.enabled }, 1);
+    SetShaderValuei(shader, light.typeLoc, (int[1]){ light.type }, 1);
+
+    // Send to shader light position values
+    float position[3] = { light.position.x, light.position.y, light.position.z };
+    SetShaderValue(shader, light.posLoc, position, 3);
+
+    // Send to shader light target position values
+    float target[3] = { light.target.x, light.target.y, light.target.z };
+    SetShaderValue(shader, light.targetLoc, target, 3);
+
+    // Send to shader light color values
+    float diff[4] = { (float)light.color.r/(float)255, (float)light.color.g/(float)255, (float)light.color.b/(float)255, (float)light.color.a/(float)255 };
+    SetShaderValue(shader, light.colorLoc, diff, 4);
+}
+
+#endif // RLIGHTS_IMPLEMENTATION

+ 27 - 76
src/models.c

@@ -1272,6 +1272,9 @@ Material LoadMaterial(const char *fileName)
     TraceLog(LOG_WARNING, "[%s] Material fileformat not supported, it can't be loaded", fileName);
 #endif
 
+    // Our material uses the default shader (DIFFUSE, SPECULAR, NORMAL)
+    material.shader = GetShaderDefault();
+
     return material;
 }
 
@@ -1282,8 +1285,8 @@ Material LoadMaterialDefault(void)
 
     material.shader = GetShaderDefault();
     material.maps[MAP_DIFFUSE].texture = GetTextureDefault();   // White texture (1x1 pixel)
-    //material.maps[MAP_NORMAL].tex;           // NOTE: By default, not set
-    //material.maps[MAP_SPECULAR].tex;         // NOTE: By default, not set
+    //material.maps[MAP_NORMAL].texture;         // NOTE: By default, not set
+    //material.maps[MAP_SPECULAR].texture;       // NOTE: By default, not set
 
     material.maps[MAP_DIFFUSE].color = WHITE;    // Diffuse color
     material.maps[MAP_SPECULAR].color = WHITE;   // Specular color
@@ -1291,58 +1294,6 @@ Material LoadMaterialDefault(void)
     return material;
 }
 
-// Load PBR material (Supports: ALBEDO, NORMAL, METALNESS, ROUGHNESS, AO, EMMISIVE, HEIGHT maps)
-Material LoadMaterialPBR(Texture2D hdr, Color albedo, float metalness, float roughness)
-{
-    Material mat = { 0 };       // NOTE: All maps textures are set to { 0 }
-    
-    #define     PATH_PBR_VS     "resources/shaders/pbr.vs"              // Path to physically based rendering vertex shader
-    #define     PATH_PBR_FS     "resources/shaders/pbr.fs"              // Path to physically based rendering fragment shader
-   
-    mat.shader = LoadShader(PATH_PBR_VS, PATH_PBR_FS);
-    
-    // Get required locations points for PBR material
-    // NOTE: Those location names must be available and used in the shader code
-    mat.shader.locs[LOC_MAP_ALBEDO] = GetShaderLocation(mat.shader, "albedo.sampler");
-    mat.shader.locs[LOC_MAP_METALNESS] = GetShaderLocation(mat.shader, "metalness.sampler");
-    mat.shader.locs[LOC_MAP_NORMAL] = GetShaderLocation(mat.shader, "normals.sampler");
-    mat.shader.locs[LOC_MAP_ROUGHNESS] = GetShaderLocation(mat.shader, "roughness.sampler");
-    mat.shader.locs[LOC_MAP_OCCUSION] = GetShaderLocation(mat.shader, "occlusion.sampler");
-    mat.shader.locs[LOC_MAP_EMISSION] = GetShaderLocation(mat.shader, "emission.sampler");
-    mat.shader.locs[LOC_MAP_HEIGHT] = GetShaderLocation(mat.shader, "height.sampler");
-    mat.shader.locs[LOC_MAP_IRRADIANCE] = GetShaderLocation(mat.shader, "irradianceMap");
-    mat.shader.locs[LOC_MAP_PREFILTER] = GetShaderLocation(mat.shader, "prefilterMap");
-    mat.shader.locs[LOC_MAP_BRDF] = GetShaderLocation(mat.shader, "brdfLUT");
-
-    // Set view matrix location
-    mat.shader.locs[LOC_MATRIX_MODEL] = GetShaderLocation(mat.shader, "mMatrix");
-    mat.shader.locs[LOC_MATRIX_VIEW] = GetShaderLocation(mat.shader, "view");
-    mat.shader.locs[LOC_VECTOR_VIEW] = GetShaderLocation(mat.shader, "viewPos");
-
-    // Set up material properties color
-    mat.maps[MAP_ALBEDO].color = albedo;
-    mat.maps[MAP_NORMAL].color = (Color){ 128, 128, 255, 255 };
-    mat.maps[MAP_METALNESS].value = metalness;
-    mat.maps[MAP_ROUGHNESS].value = roughness;
-    mat.maps[MAP_OCCLUSION].value = 1.0f;
-    mat.maps[MAP_EMISSION].value = 0.0f;
-    mat.maps[MAP_HEIGHT].value = 0.0f;
-    
-    #define CUBEMAP_SIZE         512        // Cubemap texture size
-    #define IRRADIANCE_SIZE       32        // Irradiance map from cubemap texture size
-    #define PREFILTERED_SIZE     256        // Prefiltered HDR environment map texture size
-    #define BRDF_SIZE            512        // BRDF LUT texture map size
-
-    // Set up environment materials cubemap
-    Texture2D cubemap = GenTextureCubemap(hdr, CUBEMAP_SIZE);
-    mat.maps[MAP_IRRADIANCE].texture = GenTextureIrradiance(cubemap, IRRADIANCE_SIZE);
-    mat.maps[MAP_PREFILTER].texture = GenTexturePrefilter(cubemap, PREFILTERED_SIZE);
-    mat.maps[MAP_BRDF].texture = GenTextureBRDF(cubemap, BRDF_SIZE);
-    UnloadTexture(cubemap);
-
-    return mat;
-}
-
 // Unload material from memory
 void UnloadMaterial(Material material)
 {
@@ -1358,96 +1309,96 @@ void UnloadMaterial(Material material)
 }
 
 // Set material texture
-void SetMaterialTexture(Material *mat, int texmapType, Texture2D texture)
+void SetMaterialTexture(Material *mat, int mapType, Texture2D texture)
 {
-    mat->maps[texmapType].texture = texture;
+    mat->maps[mapType].texture = texture;
 
     // Update MaterialProperty use sampler state to use texture fetch instead of color attribute
     int location = -1;
-    switch (texmapType)
+    switch (mapType)
     {
         case MAP_ALBEDO:
         {
             location = GetShaderLocation(mat->shader, "albedo.useSampler");
-            SetShaderValuei(mat->shader, location, (int [1]){ 1 }, 1);
+            SetShaderValuei(mat->shader, location, (int[1]){ 1 }, 1);
         } break;
         case MAP_NORMAL:
         {
             location = GetShaderLocation(mat->shader, "normals.useSampler");
-            SetShaderValuei(mat->shader, location, (int [1]){ 1 }, 1);
+            SetShaderValuei(mat->shader, location, (int[1]){ 1 }, 1);
         } break;
         case MAP_METALNESS:
         {
             location = GetShaderLocation(mat->shader, "metalness.useSampler");
-            SetShaderValuei(mat->shader, location, (int [1]){ 1 }, 1);
+            SetShaderValuei(mat->shader, location, (int[1]){ 1 }, 1);
         } break;
         case MAP_ROUGHNESS:
         {
             location = GetShaderLocation(mat->shader, "roughness.useSampler");
-            SetShaderValuei(mat->shader, location, (int [1]){ 1 }, 1);
+            SetShaderValuei(mat->shader, location, (int[1]){ 1 }, 1);
         } break;
         case MAP_OCCLUSION:
         {
             location = GetShaderLocation(mat->shader, "occlusion.useSampler");
-            SetShaderValuei(mat->shader, location, (int [1]){ 1 }, 1);
+            SetShaderValuei(mat->shader, location, (int[1]){ 1 }, 1);
         } break;
         case MAP_EMISSION:
         {
             location = GetShaderLocation(mat->shader, "emission.useSampler");
-            SetShaderValuei(mat->shader, location, (int [1]){ 1 }, 1);
+            SetShaderValuei(mat->shader, location, (int[1]){ 1 }, 1);
         } break;
         case MAP_HEIGHT:
         {
             location = GetShaderLocation(mat->shader, "height.useSampler");
-            SetShaderValuei(mat->shader, location, (int [1]){ 1 }, 1);
+            SetShaderValuei(mat->shader, location, (int[1]){ 1 }, 1);
         } break;
     }
 }
 
 // Unset texture from material and unload it from GPU
-void UnsetMaterialTexture(Material *mat, int texmapType)
+void UnsetMaterialTexture(Material *mat, int mapType)
 {
-    UnloadTexture(mat->maps[texmapType].texture);
-    mat->maps[texmapType].texture = (Texture2D){ 0 };
+    UnloadTexture(mat->maps[mapType].texture);
+    mat->maps[mapType].texture = (Texture2D){ 0 };
 
     // Update MaterialProperty use sampler state to use texture fetch instead of color attribute
     int location = -1;
-    switch (texmapType)
+    switch (mapType)
     {
         case MAP_ALBEDO:
         {
             location = GetShaderLocation(mat->shader, "albedo.useSampler");
-            SetShaderValuei(mat->shader, location, (int [1]){ 0 }, 1);
+            SetShaderValuei(mat->shader, location, (int[1]){ 0 }, 1);
         } break;
         case MAP_NORMAL:
         {
             location = GetShaderLocation(mat->shader, "normals.useSampler");
-            SetShaderValuei(mat->shader, location, (int [1]){ 0 }, 1);
+            SetShaderValuei(mat->shader, location, (int[1]){ 0 }, 1);
         } break;
         case MAP_METALNESS:
         {
             location = GetShaderLocation(mat->shader, "metalness.useSampler");
-            SetShaderValuei(mat->shader, location, (int [1]){ 0 }, 1);
+            SetShaderValuei(mat->shader, location, (int[1]){ 0 }, 1);
         } break;
         case MAP_ROUGHNESS:
         {
             location = GetShaderLocation(mat->shader, "roughness.useSampler");
-            SetShaderValuei(mat->shader, location, (int [1]){ 0 }, 1);
+            SetShaderValuei(mat->shader, location, (int[1]){ 0 }, 1);
         } break;
         case MAP_OCCLUSION:
         {
             location = GetShaderLocation(mat->shader, "occlusion.useSampler");
-            SetShaderValuei(mat->shader, location, (int [1]){ 0 }, 1);
+            SetShaderValuei(mat->shader, location, (int[1]){ 0 }, 1);
         } break;
         case MAP_EMISSION:
         {
             location = GetShaderLocation(mat->shader, "emission.useSampler");
-            SetShaderValuei(mat->shader, location, (int [1]){ 0 }, 1);
+            SetShaderValuei(mat->shader, location, (int[1]){ 0 }, 1);
         } break;
         case MAP_HEIGHT:
         {
             location = GetShaderLocation(mat->shader, "height.useSampler");
-            SetShaderValuei(mat->shader, location, (int [1]){ 0 }, 1);
+            SetShaderValuei(mat->shader, location, (int[1]){ 0 }, 1);
         } break;
     }
 }
@@ -2188,7 +2139,7 @@ static Material LoadMTL(const char *fileName)
 {
     #define MAX_BUFFER_SIZE     128
 
-    Material material = { 0 };  // LoadDefaultMaterial();
+    Material material = { 0 };
 
     char buffer[MAX_BUFFER_SIZE];
     Vector3 color = { 1.0f, 1.0f, 1.0f };

+ 7 - 7
src/raylib.h

@@ -996,10 +996,9 @@ RLAPI Mesh GenMeshCubicmap(Image cubicmap, Vector3 cubeSize);
 // Material loading/unloading functions
 RLAPI Material LoadMaterial(const char *fileName);                                                      // Load material from file
 RLAPI Material LoadMaterialDefault(void);                                                               // Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)
-RLAPI Material LoadMaterialPBR(Texture2D cubemap, Color albedo, float metalness, float roughness);      // Load PBR material (Supports: ALBEDO, NORMAL, METALNESS, ROUGHNESS...)
 RLAPI void UnloadMaterial(Material material);                                                           // Unload material from GPU memory (VRAM)
-RLAPI void SetMaterialTexture(Material *mat, int texmapType, Texture2D texture);                        // Set material texture
-RLAPI void UnsetMaterialTexture(Material *mat, int texmapType);                                         // Unset texture from material and unload it from GPU
+RLAPI void SetMaterialTexture(Material *mat, int mapType, Texture2D texture);                           // Set material texture
+RLAPI void UnsetMaterialTexture(Material *mat, int mapType);                                            // Unset texture from material and unload it from GPU
 
 // Model drawing functions
 RLAPI void DrawModel(Model model, Vector3 position, float scale, Color tint);                           // Draw a model (with texture if set)
@@ -1048,10 +1047,11 @@ RLAPI void SetMatrixProjection(Matrix proj);                              // Set
 RLAPI void SetMatrixModelview(Matrix view);                               // Set a custom modelview matrix (replaces internal modelview matrix)
 
 // Texture maps generation (PBR)
-RLAPI Texture2D GenTextureCubemap(Texture2D skyHDR, int size);            // Generate cubemap texture from HDR texture
-RLAPI Texture2D GenTextureIrradiance(Texture2D cubemap, int size);        // Generate irradiance texture using cubemap data
-RLAPI Texture2D GenTexturePrefilter(Texture2D cubemap, int size);         // Generate prefilter texture using cubemap data
-RLAPI Texture2D GenTextureBRDF(Texture2D cubemap, int size);              // Generate BRDF texture using cubemap data
+// NOTE: Required shaders should be provided
+RLAPI Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size);       // Generate cubemap texture from HDR texture
+RLAPI Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size);   // Generate irradiance texture using cubemap data
+RLAPI Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size);    // Generate prefilter texture using cubemap data
+RLAPI Texture2D GenTextureBRDF(Shader shader, Texture2D cubemap, int size);         // Generate BRDF texture using cubemap data
 
 // Shading begin/end functions
 RLAPI void BeginShaderMode(Shader shader);                                // Begin custom shader drawing

+ 90 - 117
src/rlgl.c

@@ -1957,15 +1957,14 @@ void rlDrawMesh(Mesh mesh, Material material, Matrix transform)
     // Bind shader program
     glUseProgram(material.shader.id);   
 
-    
     // Matrices and other values required by shader
     //-----------------------------------------------------
-    
     // Calculate and send to shader model matrix (used by PBR shader)
     SetShaderValueMatrix(material.shader, material.shader.locs[LOC_MATRIX_MODEL], transform);
     
     // Upload to shader material.colDiffuse
-    glUniform4f(material.shader.locs[LOC_COLOR_DIFFUSE], (float)material.maps[MAP_DIFFUSE].color.r/255, 
+    if (material.shader.locs[LOC_COLOR_DIFFUSE] != -1)
+        glUniform4f(material.shader.locs[LOC_COLOR_DIFFUSE], (float)material.maps[MAP_DIFFUSE].color.r/255, 
                                                            (float)material.maps[MAP_DIFFUSE].color.g/255, 
                                                            (float)material.maps[MAP_DIFFUSE].color.b/255, 
                                                            (float)material.maps[MAP_DIFFUSE].color.a/255);
@@ -1976,6 +1975,9 @@ void rlDrawMesh(Mesh mesh, Material material, Matrix transform)
                                                                (float)material.maps[MAP_SPECULAR].color.g/255, 
                                                                (float)material.maps[MAP_SPECULAR].color.b/255, 
                                                                (float)material.maps[MAP_SPECULAR].color.a/255);
+                                                               
+    if (material.shader.locs[LOC_MATRIX_VIEW] != -1) SetShaderValueMatrix(material.shader, material.shader.locs[LOC_MATRIX_VIEW], modelview);
+    if (material.shader.locs[LOC_MATRIX_PROJECTION] != -1) SetShaderValueMatrix(material.shader, material.shader.locs[LOC_MATRIX_PROJECTION], projection);
 
     // At this point the modelview matrix just contains the view matrix (camera)
     // That's because Begin3dMode() sets it an no model-drawing function modifies it, all use rlPushMatrix() and rlPopMatrix()
@@ -2417,7 +2419,7 @@ Shader LoadShader(char *vsFileName, char *fsFileName)
         // Get the location of the named uniform
         GLuint location = glGetUniformLocation(shader.id, name);
         
-        TraceLog(LOG_INFO, "[SHDR ID %i] Active uniform [%s] set at location: %i", shader.id, name, location);
+        TraceLog(LOG_DEBUG, "[SHDR ID %i] Active uniform [%s] set at location: %i", shader.id, name, location);
     }
     
 #endif
@@ -2529,18 +2531,13 @@ void SetMatrixModelview(Matrix view)
 }
 
 // Generate cubemap texture from HDR texture
-Texture2D GenTextureCubemap(Texture2D skyHDR, int size)
+Texture2D GenTextureCubemap(Shader shader, Texture2D skyHDR, int size)
 {
     Texture2D cubemap = { 0 };
     
-    #define     PATH_CUBEMAP_VS         "resources/shaders/cubemap.vs"          // Path to equirectangular to cubemap vertex shader
-    #define     PATH_CUBEMAP_FS         "resources/shaders/cubemap.fs"          // Path to equirectangular to cubemap fragment shader
-    
-    Shader shader = LoadShader(PATH_CUBEMAP_VS, PATH_CUBEMAP_FS);
-    
     // Get cubemap shader locations
-    int projectionLoc = GetShaderLocation(shader, "projection");
-    int viewLoc = GetShaderLocation(shader, "view");
+    //int projectionLoc = GetShaderLocation(shader, "projection");      // Already set at SetShaderDefaultLocations()
+    //int viewLoc = GetShaderLocation(shader, "view");                  // Already set at SetShaderDefaultLocations()
     int texmapLoc = GetShaderLocation(shader, "equirectangularMap");
 
     SetShaderValuei(shader, texmapLoc, (int[1]){ 0 }, 1);   // Set default active texture to 0
@@ -2586,7 +2583,7 @@ Texture2D GenTextureCubemap(Texture2D skyHDR, int size)
     glUseProgram(shader.id);
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, skyHDR.id);
-    SetShaderValueMatrix(shader, projectionLoc, fboProjection);
+    SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_PROJECTION], fboProjection);
 
     // Note: don't forget to configure the viewport to the capture dimensions
     glViewport(0, 0, size, size);
@@ -2594,7 +2591,7 @@ Texture2D GenTextureCubemap(Texture2D skyHDR, int size)
 
     for (unsigned int i = 0; i < 6; i++)
     {
-        SetShaderValueMatrix(shader, viewLoc, fboViews[i]);
+        SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]);
         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cubemap.id, 0);
         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
         GenDrawCube();
@@ -2607,8 +2604,6 @@ Texture2D GenTextureCubemap(Texture2D skyHDR, int size)
     glViewport(0, 0, GetScreenWidth(), GetScreenHeight());
     //glEnable(GL_CULL_FACE);
 
-    UnloadShader(shader);
-    
     cubemap.width = size;
     cubemap.height = size;
     
@@ -2616,18 +2611,13 @@ Texture2D GenTextureCubemap(Texture2D skyHDR, int size)
 }
 
 // Generate irradiance texture using cubemap data
-Texture2D GenTextureIrradiance(Texture2D cubemap, int size)
+Texture2D GenTextureIrradiance(Shader shader, Texture2D cubemap, int size)
 {
     Texture2D irradiance = { 0 };
     
-    #define     PATH_SKYBOX_VS          "resources/shaders/skybox.vs"           // Path to skybox vertex shader
-    #define     PATH_IRRADIANCE_FS      "resources/shaders/irradiance.fs"       // Path to irradiance (GI) calculation fragment shader
-
-    Shader shader = LoadShader(PATH_SKYBOX_VS, PATH_IRRADIANCE_FS);
-    
     // Get irradiance shader locations
-    int projectionLoc = GetShaderLocation(shader, "projection");
-    int viewLoc = GetShaderLocation(shader, "view");
+    //int projectionLoc = GetShaderLocation(shader, "projection");  // Already set at SetShaderDefaultLocations()
+    //int viewLoc = GetShaderLocation(shader, "view");              // Already set at SetShaderDefaultLocations()
     int texmapLoc = GetShaderLocation(shader, "environmentMap");
     
     // Set up shaders constant values
@@ -2669,7 +2659,7 @@ Texture2D GenTextureIrradiance(Texture2D cubemap, int size)
     glUseProgram(shader.id);
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id);
-    SetShaderValueMatrix(shader, projectionLoc, fboProjection);
+    SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_PROJECTION], fboProjection);
 
     // Note: don't forget to configure the viewport to the capture dimensions
     glViewport(0, 0, size, size);
@@ -2677,7 +2667,7 @@ Texture2D GenTextureIrradiance(Texture2D cubemap, int size)
 
     for (unsigned int i = 0; i < 6; i++)
     {
-        SetShaderValueMatrix(shader, viewLoc, fboViews[i]);
+        SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]);
         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradiance.id, 0);
         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
         GenDrawCube();
@@ -2688,9 +2678,7 @@ Texture2D GenTextureIrradiance(Texture2D cubemap, int size)
     
     // Reset viewport dimensions to default
     glViewport(0, 0, GetScreenWidth(), GetScreenHeight());
-    
-    UnloadShader(shader);
-    
+
     irradiance.width = size;
     irradiance.height = size;
     
@@ -2698,18 +2686,13 @@ Texture2D GenTextureIrradiance(Texture2D cubemap, int size)
 }
 
 // Generate prefilter texture using cubemap data
-Texture2D GenTexturePrefilter(Texture2D cubemap, int size)
+Texture2D GenTexturePrefilter(Shader shader, Texture2D cubemap, int size)
 {
     Texture2D prefilter = { 0 };
     
-    #define     PATH_SKYBOX_VS          "resources/shaders/skybox.vs"           // Path to skybox vertex shader
-    #define     PATH_PREFILTER_FS       "resources/shaders/prefilter.fs"        // Path to reflection prefilter calculation fragment shader
-    
-    Shader shader = LoadShader(PATH_SKYBOX_VS, PATH_PREFILTER_FS);
-    
     // Get prefilter shader locations
-    int projectionLoc = GetShaderLocation(shader, "projection");
-    int viewLoc = GetShaderLocation(shader, "view");
+    //int projectionLoc = GetShaderLocation(shader, "projection");  // Already set at SetShaderDefaultLocations()
+    //int viewLoc = GetShaderLocation(shader, "view");              // Already set at SetShaderDefaultLocations()
     int roughnessLoc = GetShaderLocation(shader, "roughness");
     int texmapLoc = GetShaderLocation(shader, "environmentMap");
     
@@ -2754,7 +2737,7 @@ Texture2D GenTexturePrefilter(Texture2D cubemap, int size)
     glUseProgram(shader.id);
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap.id);
-    SetShaderValueMatrix(shader, projectionLoc, fboProjection);
+    SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_PROJECTION], fboProjection);
 
     glBindFramebuffer(GL_FRAMEBUFFER, fbo);
     
@@ -2775,7 +2758,7 @@ Texture2D GenTexturePrefilter(Texture2D cubemap, int size)
 
         for (unsigned int i = 0; i < 6; ++i)
         {
-            SetShaderValueMatrix(shader, viewLoc, fboViews[i]);
+            SetShaderValueMatrix(shader, shader.locs[LOC_MATRIX_VIEW], fboViews[i]);
             glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, prefilter.id, mip);
             glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
             GenDrawCube();
@@ -2787,9 +2770,7 @@ Texture2D GenTexturePrefilter(Texture2D cubemap, int size)
     
     // Reset viewport dimensions to default
     glViewport(0, 0, GetScreenWidth(), GetScreenHeight());
-    
-    UnloadShader(shader);
-    
+
     prefilter.width = size;
     prefilter.height = size;
     
@@ -2797,15 +2778,10 @@ Texture2D GenTexturePrefilter(Texture2D cubemap, int size)
 }
 
 // Generate BRDF texture using cubemap data
-Texture2D GenTextureBRDF(Texture2D cubemap, int size)
+Texture2D GenTextureBRDF(Shader shader, Texture2D cubemap, int size)
 {
     Texture2D brdf = { 0 };
     
-    #define PATH_BRDF_VS    "resources/shaders/brdf.vs"     // Path to bidirectional reflectance distribution function vertex shader 
-    #define PATH_BRDF_FS    "resources/shaders/brdf.fs"     // Path to bidirectional reflectance distribution function fragment shader
-    
-    Shader shader = LoadShader(PATH_BRDF_VS, PATH_BRDF_FS);
-    
     // Generate BRDF convolution texture
     glGenTextures(1, &brdf.id);
     glBindTexture(GL_TEXTURE_2D, brdf.id);
@@ -2835,8 +2811,6 @@ Texture2D GenTextureBRDF(Texture2D cubemap, int size)
     // Reset viewport dimensions to default
     glViewport(0, 0, GetScreenWidth(), GetScreenHeight());
    
-    UnloadShader(shader);
-    
     brdf.width = size;
     brdf.height = size;
     
@@ -3380,6 +3354,8 @@ static void SetShaderDefaultLocations(Shader *shader)
 
     // Get handles to GLSL uniform locations (vertex shader)
     shader->locs[LOC_MATRIX_MVP]  = glGetUniformLocation(shader->id, "mvpMatrix");
+    shader->locs[LOC_MATRIX_PROJECTION]  = glGetUniformLocation(shader->id, "projection");
+    shader->locs[LOC_MATRIX_VIEW]  = glGetUniformLocation(shader->id, "view");
 
     // Get handles to GLSL uniform locations (fragment shader)
     shader->locs[LOC_COLOR_DIFFUSE] = glGetUniformLocation(shader->id, "colDiffuse");
@@ -3894,9 +3870,9 @@ static void GenDrawQuad(void)
 
     // Link vertex attributes
     glEnableVertexAttribArray(0);
-    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (GLvoid*)0);
+    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)0);
     glEnableVertexAttribArray(1);
-    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)));
+    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void *)(3*sizeof(float)));
 
     // Draw quad
     glBindVertexArray(quadVAO);
@@ -3908,79 +3884,76 @@ static void GenDrawQuad(void)
 }
 
 // Renders a 1x1 3D cube in NDC
-GLuint cubeVAO = 0;
-GLuint cubeVBO = 0;
 static void GenDrawCube(void)
 {
-    // Lazy initialization
-    if (cubeVAO == 0)
-    {
-        GLfloat vertices[] = {
-            -1.0f, -1.0f, -1.0f,  0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-            1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
-            1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
-            1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
-            -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-            -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-            -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-            1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
-            1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-            1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-            -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-            -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-            -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-            -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-            -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-            -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-            -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-            -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-            1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-            1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-            1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-            1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-            1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-            1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-            -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
-            1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
-            1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-            1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-            -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-            -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
-            -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-            1.0f, 1.0f , 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-            1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
-            1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-            -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-            -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f
-        };
-
-        // Set up cube VAO
-        glGenVertexArrays(1, &cubeVAO);
-        glGenBuffers(1, &cubeVBO);
-
-        // Fill buffer
-        glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
-        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
-
-        // Link vertex attributes
-        glBindVertexArray(cubeVAO);
-        glEnableVertexAttribArray(0);
-        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), (GLvoid*)0);
-        glEnableVertexAttribArray(1);
-        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)));
-        glEnableVertexAttribArray(2);
-        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8*sizeof(GLfloat), (GLvoid*)(6*sizeof(GLfloat)));
-        glBindBuffer(GL_ARRAY_BUFFER, 0);
-        glBindVertexArray(0);
-    }
+    unsigned int cubeVAO = 0;
+    unsigned int cubeVBO = 0;
+
+    float vertices[] = {
+        -1.0f, -1.0f, -1.0f,  0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
+        1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
+        1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
+        1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
+        -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
+        -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
+        -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
+        1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
+        1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
+        1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
+        -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
+        -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
+        -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
+        -1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
+        -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+        -1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+        -1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+        -1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
+        1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
+        1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+        1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
+        1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
+        1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
+        1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+        -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
+        1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
+        1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
+        1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
+        -1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
+        -1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
+        -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
+        1.0f, 1.0f , 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
+        1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
+        1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
+        -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
+        -1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f
+    };
+
+    // Set up cube VAO
+    glGenVertexArrays(1, &cubeVAO);
+    glGenBuffers(1, &cubeVBO);
+
+    // Fill buffer
+    glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
+    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
+
+    // Link vertex attributes
+    glBindVertexArray(cubeVAO);
+    glEnableVertexAttribArray(0);
+    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)0);
+    glEnableVertexAttribArray(1);
+    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(3*sizeof(float)));
+    glEnableVertexAttribArray(2);
+    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void *)(6*sizeof(float)));
+    glBindBuffer(GL_ARRAY_BUFFER, 0);
+    glBindVertexArray(0);
 
     // Draw cube
     glBindVertexArray(cubeVAO);
     glDrawArrays(GL_TRIANGLES, 0, 36);
     glBindVertexArray(0);
     
-    //glDeleteBuffers(1, &cubeVBO);
-    //glDeleteVertexArrays(1, &cubeVAO);
+    glDeleteBuffers(1, &cubeVBO);
+    glDeleteVertexArrays(1, &cubeVAO);
 }
 
 #if defined(SUPPORT_VR_SIMULATOR)