Browse Source

Remove dependencies from PBR example (#3649)

* Remove dependencies from PBR example

* Reviewed example PR

---------

Co-authored-by: Ray <[email protected]>
TheManTheMythTheGameDev 1 year ago
parent
commit
34a9163c52
2 changed files with 172 additions and 514 deletions
  1. 0 466
      examples/shaders/rpbr.h
  2. 172 48
      examples/shaders/shaders_basic_pbr.c

+ 0 - 466
examples/shaders/rpbr.h

@@ -1,466 +0,0 @@
-/**********************************************************************************************
-*
-*   raylib.pbr - Some useful functions to deal with pbr materials and lights
-*
-*   CONFIGURATION:
-*
-*   #define RPBR_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) 2023-2024 Afan OLOVCIC (@_DevDad) 2017-2020 Victor Fisac(@victorfisac),Ramon Santamaria (@raysan5)
-*
-*   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 RPBR_H
-#define RPBR_H
-#include "raylib.h"
-
-
-//----------------------------------------------------------------------------------
-// Defines and Macros
-//----------------------------------------------------------------------------------
-#define MAX_LIGHTS  4        // Max dynamic lights supported by shader
-#define SHADER_LOC_MAP_MRA SHADER_LOC_MAP_METALNESS  //METALLIC, ROUGHNESS and AO
-#define SHADER_LOC_MAP_EMISSIVE  SHADER_LOC_MAP_HEIGHT     //EMISSIVE
-#define MATERIAL_MAP_MRA MATERIAL_MAP_METALNESS
-#define MATERIAL_MAP_EMISSIVE  MATERIAL_MAP_HEIGHT
-#define NULL 0
-#define COLOR_TO_ARRAY(c)
-
-typedef struct {
-    int enabled;
-    int type;
-    Vector3 position;
-    Vector3 target;
-    float color[4];
-    float intensity;
-
-    int enabledLoc;
-    int typeLoc;
-    int positionLoc;
-    int targetLoc;
-    int colorLoc;
-    int intensityLoc;
-} PBRLight;
-
-typedef enum {
-    LIGHT_DIRECTIONAL = 0,
-    LIGHT_POINT,
-    LIGHT_SPOT
-} PBRLightType;
-
-typedef struct{
-    Shader pbrShader;
-    Shader skyShader;
-    unsigned int cubemap;
-    unsigned int irradiance;
-    unsigned int prefilter;
-    unsigned int brdf;
-    int modelMatrixLoc;
-    int pbrViewLoc;
-    int skyViewLoc;
-    int skyResolutionLoc;
-} PBREnvironment;
-
-typedef enum{
-    PBR_COLOR_ALBEDO = 0,
-    PBR_COLOR_EMISSIVE
-}PBRColorType;
-
-typedef enum{
-    PBR_VEC2_TILING = 0,
-    PBR_VEC2_OFFSET
-}PBRVec2Type;
-
-typedef enum{
-    PBR_PARAM_NORMAL =0,
-    PBR_PARAM_METALLIC,
-    PBR_PARAM_ROUGHNESS,
-    PBR_PARAM_EMISSIVE,
-    PBR_PARAM_AO
-}PBRFloatType;
-
-typedef enum{
-    PBR_TEXTURE_ALBEDO = 0,
-    PBR_TEXTURE_NORMAL,
-    PBR_TEXTURE_MRA,
-    PBR_TEXTURE_EMISSIVE
-}PBRTexType;
-
-// Textures are moved to material from params to pack better and use less textures on the end
-// texture MRAE 4Channel R: Metallic G: Roughness B: A: Ambient Occlusion
-// texEmissive use just one channel, so we have 3 channels still to use if we need
-typedef struct {
-    Shader pbrShader;
-    float albedo[4];
-    float normal;
-    float metallic;
-    float roughness;
-    float ao;
-    float emissive[4];
-    float ambient[3];
-    float emissivePower;
-
-    Texture2D texAlbedo;
-    Texture2D texNormal;
-    Texture2D texMRA;//r: Metallic  g: Roughness b: AO a:Empty
-    Texture2D texEmissive; //Emissive Texture
-    // Using float4 to store tilling at 1st and 2nd position and offset at 3rd and 4th
-    float texTiling[2];
-    float texOffset[2];
-
-    int useTexAlbedo;
-    int useTexNormal;
-    int useTexMRA;
-    int useTexEmissive;
-
-    int albedoLoc;
-    int normalLoc;
-    int metallicLoc;
-    int roughnessLoc;
-    int aoLoc;
-    int emissiveColorLoc;
-    int emissivePowerLoc;
-
-    int texTilingLoc;
-    int texOffsetLoc;
-
-    int useTexAlbedoLoc;
-    int useTexNormalLoc;
-    int useTexMRAELoc;
-    int useTexEmissiveLoc;
-} PBRMaterial;
-
-typedef struct{
-    Model model;
-    PBRMaterial pbrMat;
-}PBRModel;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-//----------------------------------------------------------------------------------
-// Module Functions Declaration
-//----------------------------------------------------------------------------------
-
-// Create a light and get shader locations
-PBRLight PBRLightCreate(int type, Vector3 position, Vector3 target, Color color,float intensity, Shader shader);
-// Send light properties to shader
-void PBRLightUpdate(Shader shader, PBRLight light);
-
-//For now until we do real skylight
-void PBRSetAmbient(Shader shader, Color color, float intensity);
-
-PBRModel PBRModelLoad(const char *fileName);
-PBRModel PBRModelLoadFromMesh(Mesh mesh);
-
-void PBRLoadTextures(PBRMaterial *pbrMat,PBRTexType pbrTexType,const char *fileName);
-void UnloadPBRMaterial(PBRMaterial pbrMat);
-void PBRSetColor(PBRMaterial *pbrMat,PBRColorType pbrColorType,Color color);
-void PBRSetVec2(PBRMaterial *pbrMat,PBRVec2Type type,Vector2 value);
-void PBRSetFloat(PBRMaterial *pbrMat, PBRFloatType pbrParamType, float value);
-
-void PBRMaterialSetup( PBRMaterial *pbrMat,Shader pbrShader, PBREnvironment* environment);
-void PBRSetMaterial(PBRModel* model,PBRMaterial* pbrMat,int matIndex);
-void PBRDrawModel(PBRModel pbrModel, Vector3 position, float scale);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif //RPBR_H
-
-/***********************************************************************************
-*
-*   RPBR IMPLEMENTATION
-*
-************************************************************************************/
-
-#if defined(RPBR_IMPLEMENTATION)
-
-//----------------------------------------------------------------------------------
-// Global Variables Definition
-//----------------------------------------------------------------------------------
-static int lightsCount = 0;    // Current amount of created lights
-
-// Create a light and get shader locations
-PBRLight PBRLightCreate(int type, Vector3 position, Vector3 target, Color color,float intensity, Shader shader)
-{
-    PBRLight light = { 0 };
-
-    if (lightsCount < MAX_LIGHTS)
-    {
-        light.enabled = 1;
-        light.type = type;
-        light.position = position;
-        light.target = target;
-        light.color[0] = (float)color.r/(float)255;
-        light.color[1] = (float)color.g/(float)255;
-        light.color[2] = (float)color.b/(float)255;
-        light.color[3] = (float)color.a/(float)255;
-        light.intensity = intensity;
-        // NOTE: Lighting shader naming must be the provided ones
-        light.enabledLoc =  GetShaderLocation(shader, TextFormat("lights[%i].enabled", lightsCount));
-        light.typeLoc =     GetShaderLocation(shader, TextFormat("lights[%i].type", lightsCount));
-        light.positionLoc = GetShaderLocation(shader, TextFormat("lights[%i].position", lightsCount));
-        light.targetLoc =   GetShaderLocation(shader, TextFormat("lights[%i].target", lightsCount));
-        light.colorLoc =    GetShaderLocation(shader, TextFormat("lights[%i].color", lightsCount));
-        light.intensityLoc =    GetShaderLocation(shader, TextFormat("lights[%i].intensity", lightsCount));
-        PBRLightUpdate(shader, light);
-
-        lightsCount++;
-    }
-
-    return light;
-}
-
-// Send light properties to shader
-// NOTE: Light shader locations should be available
-void PBRLightUpdate(Shader shader, PBRLight light)
-{
-    SetShaderValue(shader, light.enabledLoc, &light.enabled, SHADER_UNIFORM_INT);
-    SetShaderValue(shader, light.typeLoc, &light.type, SHADER_UNIFORM_INT);
-    // Send to shader light position values
-    float position[3] = { light.position.x, light.position.y, light.position.z };
-    SetShaderValue(shader, light.positionLoc, position, SHADER_UNIFORM_VEC3);
-
-    // Send to shader light target position values
-    float target[3] = { light.target.x, light.target.y, light.target.z };
-    SetShaderValue(shader, light.targetLoc, target, SHADER_UNIFORM_VEC3);
-    SetShaderValue(shader, light.colorLoc, light.color, SHADER_UNIFORM_VEC4);
-    SetShaderValue(shader, light.intensityLoc, &light.intensity, SHADER_UNIFORM_FLOAT);
-}
-
-void PBRSetAmbient(Shader shader, Color color, float intensity){
-    float col[3] = {color.r/255,color.g/255,color.b/255};
-    SetShaderValue(shader, GetShaderLocation(shader, "ambientColor"), col, SHADER_UNIFORM_VEC3);
-    SetShaderValue(shader, GetShaderLocation(shader, "ambient"), &intensity, SHADER_UNIFORM_FLOAT);
-}
-
-void PBRMaterialSetup(PBRMaterial *pbrMat, Shader pbrShader, PBREnvironment* environment){
-    pbrMat->pbrShader = pbrShader;
-
-    pbrMat->texAlbedo = (Texture2D){0};
-    pbrMat->texNormal = (Texture2D){0};
-    pbrMat->texMRA = (Texture2D){0};
-    pbrMat->texEmissive = (Texture2D){0};
-
-    //PBRParam
-    pbrMat->albedo[0] = 1.0;
-    pbrMat->albedo[1] = 1.0;
-    pbrMat->albedo[2] = 1.0;
-    pbrMat->albedo[3] = 1.0;
-    pbrMat->metallic = 0;
-    pbrMat->roughness = 0;
-    pbrMat->ao = 1.0;
-    pbrMat->normal = 1;
-    pbrMat->emissive[0] = 0;
-    pbrMat->emissive[1] = 0;
-    pbrMat->emissive[2] = 0;
-    pbrMat->emissive[3] = 0;
-
-    pbrMat->texTiling[0] = 1.0;
-    pbrMat->texTiling[1] = 1.0;
-    pbrMat->texOffset[0] = 0.0;
-    pbrMat->texOffset[1] = 0.0;
-    pbrMat->emissivePower = 1.0;
-    // Set up PBR shader material locations
-
-    pbrMat->albedoLoc = GetShaderLocation(pbrMat->pbrShader, "albedoColor");
-    pbrMat->normalLoc = GetShaderLocation(pbrMat->pbrShader, "normalValue");
-    pbrMat->metallicLoc = GetShaderLocation(pbrMat->pbrShader, "metallicValue");
-    pbrMat->roughnessLoc = GetShaderLocation(pbrMat->pbrShader, "roughnessValue");
-    pbrMat->aoLoc = GetShaderLocation(pbrMat->pbrShader, "aoValue");
-    pbrMat->emissiveColorLoc = GetShaderLocation(pbrMat->pbrShader, "emissiveColor");
-    pbrMat->emissivePowerLoc = GetShaderLocation(pbrMat->pbrShader, "emissivePower");
-
-    pbrMat->texTilingLoc = GetShaderLocation(pbrMat->pbrShader, "tiling");
-    pbrMat->texOffsetLoc = GetShaderLocation(pbrMat->pbrShader, "offset");
-
-    pbrMat->useTexAlbedoLoc = GetShaderLocation(pbrMat->pbrShader, "useTexAlbedo");
-    pbrMat->useTexNormalLoc = GetShaderLocation(pbrMat->pbrShader, "useTexNormal");
-    pbrMat->useTexMRAELoc = GetShaderLocation(pbrMat->pbrShader, "useTexMRA");
-    pbrMat->useTexEmissiveLoc = GetShaderLocation(pbrMat->pbrShader, "useTexEmissive");
-
-    SetShaderValue(pbrMat->pbrShader,pbrMat->albedoLoc,pbrMat->albedo,SHADER_UNIFORM_VEC4);
-    SetShaderValue(pbrMat->pbrShader, pbrMat->emissiveColorLoc, pbrMat->emissive, SHADER_UNIFORM_VEC4);
-    SetShaderValue(pbrMat->pbrShader, pbrMat->emissivePowerLoc, &pbrMat->emissivePower, SHADER_UNIFORM_FLOAT);
-    SetShaderValue(pbrMat->pbrShader,pbrMat->metallicLoc,&pbrMat->metallic,SHADER_UNIFORM_FLOAT);
-    SetShaderValue(pbrMat->pbrShader,pbrMat->roughnessLoc,&pbrMat->roughness,SHADER_UNIFORM_FLOAT);
-    SetShaderValue(pbrMat->pbrShader,pbrMat->aoLoc,&pbrMat->ao,SHADER_UNIFORM_FLOAT);
-    SetShaderValue(pbrMat->pbrShader,pbrMat->normalLoc,&pbrMat->normal,SHADER_UNIFORM_FLOAT);
-    SetShaderValue(pbrMat->pbrShader,pbrMat->texTilingLoc,pbrMat->texTiling,SHADER_UNIFORM_VEC2);
-    SetShaderValue(pbrMat->pbrShader,pbrMat->texOffsetLoc,pbrMat->texOffset,SHADER_UNIFORM_VEC2);
-}
-
-void PBRLoadTextures(PBRMaterial *pbrMat,PBRTexType pbrTexType,const char *fileName){
-    if(pbrMat == NULL) return;
-    switch(pbrTexType){
-        case PBR_TEXTURE_ALBEDO:
-            pbrMat->texAlbedo = LoadTexture(fileName);
-            pbrMat->useTexAlbedo = 1;
-            break;
-        case PBR_TEXTURE_MRA:
-            pbrMat->texMRA = LoadTexture(fileName);
-            pbrMat->useTexMRA = 1;
-            break;
-        case PBR_TEXTURE_NORMAL:
-            pbrMat->texNormal = LoadTexture(fileName);
-            pbrMat->useTexNormal = 1;
-            break;
-        case PBR_TEXTURE_EMISSIVE:
-            pbrMat->texEmissive = LoadTexture(fileName);
-            pbrMat->useTexEmissive = 1;
-            break;
-    }
-}
-
-void UnloadPBRMaterial(PBRMaterial pbrMat){
-    if(pbrMat.useTexAlbedo == 1) UnloadTexture(pbrMat.texAlbedo);
-    if(pbrMat.useTexNormal == 1) UnloadTexture(pbrMat.texNormal);
-    if(pbrMat.useTexMRA == 1) UnloadTexture(pbrMat.texMRA);
-    if(pbrMat.useTexEmissive == 1) UnloadTexture(pbrMat.texEmissive);
-}
-
-void PBRSetColor(PBRMaterial *pbrMat,PBRColorType pbrColorType,Color color){
-    if(pbrMat == NULL) return;
-    switch(pbrColorType){
-        case PBR_COLOR_ALBEDO:
-            pbrMat->albedo[0] = (float) color.r / 255;
-            pbrMat->albedo[1] = (float) color.g / 255;
-            pbrMat->albedo[2] = (float) color.b / 255;
-            pbrMat->albedo[3] = (float) color.a / 255;
-            SetShaderValue(pbrMat->pbrShader,pbrMat->albedoLoc,pbrMat->albedo,SHADER_UNIFORM_VEC4);
-            break;
-        case PBR_COLOR_EMISSIVE:
-            pbrMat->emissive[0] = (float) color.r / 255;
-            pbrMat->emissive[1] = (float) color.g / 255;
-            pbrMat->emissive[2] = (float) color.b / 255;
-            pbrMat->emissive[3] = (float) color.a / 255;
-            SetShaderValue(pbrMat->pbrShader, pbrMat->emissiveColorLoc, pbrMat->emissive, SHADER_UNIFORM_VEC4);
-            break;
-    }
-}
-
-void PBRSetFloat(PBRMaterial *pbrMat, PBRFloatType pbrParamType, float value){
-    if(pbrMat == NULL) return;
-    switch(pbrParamType){
-        case PBR_PARAM_METALLIC:
-            pbrMat->metallic = value;
-            SetShaderValue(pbrMat->pbrShader,pbrMat->metallicLoc,&pbrMat->metallic,SHADER_UNIFORM_FLOAT);
-            break;
-        case PBR_PARAM_ROUGHNESS:
-            pbrMat->roughness = value;
-            SetShaderValue(pbrMat->pbrShader,pbrMat->roughnessLoc,&pbrMat->roughness,SHADER_UNIFORM_FLOAT);
-            break;
-        case PBR_PARAM_NORMAL:
-            pbrMat->normal = value;
-            SetShaderValue(pbrMat->pbrShader,pbrMat->normalLoc,&pbrMat->normal,SHADER_UNIFORM_FLOAT);
-            break;
-        case PBR_PARAM_AO:
-            pbrMat->ao = value;
-            SetShaderValue(pbrMat->pbrShader,pbrMat->aoLoc,&pbrMat->ao,SHADER_UNIFORM_FLOAT);
-            break;
-        case PBR_PARAM_EMISSIVE:
-            pbrMat->emissivePower = value;
-            SetShaderValue(pbrMat->pbrShader,pbrMat->emissivePowerLoc,&pbrMat->emissivePower,SHADER_UNIFORM_FLOAT);
-            break;
-    }
-}
-
-
-void PBRSetVec2(PBRMaterial *pbrMat,PBRVec2Type type,Vector2 value){
-    switch(type){
-        case PBR_VEC2_TILING:
-            pbrMat->texTiling[0] = value.x;
-            pbrMat->texTiling[1] = value.y;
-            SetShaderValue(pbrMat->pbrShader,pbrMat->texTilingLoc,&pbrMat->texTiling,SHADER_UNIFORM_VEC2);
-            break;
-        case PBR_VEC2_OFFSET:
-            pbrMat->texOffset[0] = value.x;
-            pbrMat->texOffset[1] = value.y;
-            SetShaderValue(pbrMat->pbrShader,pbrMat->texOffsetLoc,&pbrMat->texOffset,SHADER_UNIFORM_VEC2);
-            break;
-    }
-}
-
-void PBRSetMaterial(PBRModel* model,PBRMaterial* pbrMat,int matIndex){
-
-
-    model->pbrMat = *pbrMat;
-    model->model.materials[matIndex].shader = model->pbrMat.pbrShader;
-    pbrMat->pbrShader.locs[SHADER_LOC_MAP_MRA] = GetShaderLocation(pbrMat->pbrShader, "mraMap");
-    pbrMat->pbrShader.locs[SHADER_LOC_MAP_EMISSIVE] = GetShaderLocation(pbrMat->pbrShader, "emissiveMap");
-    pbrMat->pbrShader.locs[SHADER_LOC_MAP_NORMAL] = GetShaderLocation(pbrMat->pbrShader, "normalMap");
-
-    if(pbrMat->useTexAlbedo) {
-        model->model.materials[matIndex].maps[MATERIAL_MAP_ALBEDO].texture = pbrMat->texAlbedo;
-    }
-    if(pbrMat->useTexMRA) {
-        model->model.materials[matIndex].maps[MATERIAL_MAP_MRA].texture = pbrMat->texMRA;
-    }
-    if(pbrMat->useTexNormal) {
-        model->model.materials[matIndex].maps[MATERIAL_MAP_NORMAL].texture = pbrMat->texNormal;
-    }
-    if(pbrMat->useTexEmissive) {
-        model->model.materials[matIndex].maps[MATERIAL_MAP_EMISSIVE].texture = pbrMat->texEmissive;
-    }
-
-    SetShaderValue(pbrMat->pbrShader,pbrMat->useTexAlbedoLoc,&pbrMat->useTexAlbedo,SHADER_UNIFORM_INT);
-    SetShaderValue(pbrMat->pbrShader,pbrMat->useTexNormalLoc,&pbrMat->useTexNormal,SHADER_UNIFORM_INT);
-    SetShaderValue(pbrMat->pbrShader, pbrMat->useTexMRAELoc, &pbrMat->useTexMRA, SHADER_UNIFORM_INT);
-    SetShaderValue(pbrMat->pbrShader, pbrMat->useTexEmissiveLoc, &pbrMat->useTexEmissive, SHADER_UNIFORM_INT);
-}
-
-void PBRDrawModel(PBRModel pbrModel, Vector3 position, float scale){
-    PBRMaterial *pbrMat = &pbrModel.pbrMat;
-    SetShaderValue(pbrMat->pbrShader,pbrMat->albedoLoc,pbrMat->albedo,SHADER_UNIFORM_VEC4);
-    SetShaderValue(pbrMat->pbrShader, pbrMat->emissiveColorLoc, pbrMat->emissive, SHADER_UNIFORM_VEC4);
-    SetShaderValue(pbrMat->pbrShader,pbrMat->metallicLoc,&pbrMat->metallic,SHADER_UNIFORM_FLOAT);
-    SetShaderValue(pbrMat->pbrShader,pbrMat->roughnessLoc,&pbrMat->roughness,SHADER_UNIFORM_FLOAT);
-    SetShaderValue(pbrMat->pbrShader,pbrMat->aoLoc,&pbrMat->ao,SHADER_UNIFORM_FLOAT);
-    SetShaderValue(pbrMat->pbrShader,pbrMat->normalLoc,&pbrMat->normal,SHADER_UNIFORM_FLOAT);
-    SetShaderValue(pbrMat->pbrShader,pbrMat->texTilingLoc,pbrMat->texTiling,SHADER_UNIFORM_VEC2);
-    SetShaderValue(pbrMat->pbrShader,pbrMat->texOffsetLoc,pbrMat->texOffset,SHADER_UNIFORM_VEC2);
-
-    SetShaderValue(pbrMat->pbrShader,pbrMat->useTexAlbedoLoc,&pbrMat->useTexAlbedo,SHADER_UNIFORM_INT);
-    SetShaderValue(pbrMat->pbrShader,pbrMat->useTexNormalLoc,&pbrMat->useTexNormal,SHADER_UNIFORM_INT);
-    SetShaderValue(pbrMat->pbrShader, pbrMat->useTexMRAELoc, &pbrMat->useTexMRA, SHADER_UNIFORM_INT);
-    SetShaderValue(pbrMat->pbrShader, pbrMat->useTexEmissiveLoc, &pbrMat->useTexEmissive, SHADER_UNIFORM_INT);
-
-    DrawModel(pbrModel.model,position,scale,WHITE);
-}
-
-PBRModel PBRModelLoad(const char *fileName){
-    PBRModel pbrModel = (PBRModel){0};
-    pbrModel.model = LoadModel(fileName);
-    return pbrModel;
-}
-
-PBRModel PBRModelLoadFromMesh(Mesh mesh){
-    PBRModel pbrModel = (PBRModel){0};
-    pbrModel.model = LoadModelFromMesh(mesh);
-    return pbrModel;
-}
-#endif // RPBR_IMPLEMENTATION

+ 172 - 48
examples/shaders/shaders_basic_pbr.c

@@ -19,15 +19,45 @@
 #include <emscripten/emscripten.h>
 #endif
 
-#define RPBR_IMPLEMENTATION
-#include "rpbr.h"
-
 #if defined(PLATFORM_DESKTOP)
 #define GLSL_VERSION            330
 #else   // PLATFORM_ANDROID, PLATFORM_WEB
 #define GLSL_VERSION            120
 #endif
 
+#include <stdlib.h>             // Required for: NULL
+
+#define MAX_LIGHTS  4           // Max dynamic lights supported by shader
+int lightsCount;                // Current number of dynamic lights that have been created
+
+typedef struct {
+    int enabled;
+    int type;
+    Vector3 position;
+    Vector3 target;
+    float color[4];
+    float intensity;
+
+    int enabledLoc;
+    int typeLoc;
+    int positionLoc;
+    int targetLoc;
+    int colorLoc;
+    int intensityLoc;
+} PBRLight;
+
+typedef enum {
+    LIGHT_DIRECTIONAL = 0,
+    LIGHT_POINT,
+    LIGHT_SPOT
+} PBRLightType;
+
+// Create a light and get shader locations
+PBRLight PBRLightCreate(int type, Vector3 position, Vector3 target, Color color, float intensity, Shader shader);
+
+// Send light properties to shader
+// NOTE: Light shader locations should be available
+void PBRLightUpdate(Shader shader, PBRLight light);
 
 //----------------------------------------------------------------------------------
 // Main Entry Point
@@ -53,44 +83,69 @@ int main()
 
     Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/pbr.vs",GLSL_VERSION),
                                TextFormat("resources/shaders/glsl%i/pbr.fs",GLSL_VERSION));
-
-
-
-    PBRModel model = PBRModelLoad("resources/models/old_car_new.glb");
-    //if we use obj file formator if model doesn't have tangents we have to calculate MeshTangents
-    //by using raylib function GenMeshTangents(mesh) for example: obj file doesn't support tangents
-    //GenMeshTangents(&model.model.meshes[0]); 
-
-    PBRMaterial model_mat = (PBRMaterial){0};
-    PBRMaterialSetup(&model_mat, shader, NULL); //environment = NULL for now
-    PBRLoadTextures(&model_mat, PBR_TEXTURE_ALBEDO, "resources/old_car_d.png");
-    PBRLoadTextures(&model_mat, PBR_TEXTURE_MRA, "resources/old_car_mra.png");
-    PBRLoadTextures(&model_mat, PBR_TEXTURE_NORMAL, "resources/old_car_n.png");
-    PBRLoadTextures(&model_mat, PBR_TEXTURE_EMISSIVE, "resources/old_car_e.png");
-    PBRSetColor(&model_mat,PBR_COLOR_EMISSIVE, (Color){255,162,0,255});
-    PBRSetVec2(&model_mat, PBR_VEC2_TILING,(Vector2){0.5,0.5});
-    PBRSetMaterial(&model,&model_mat,0);
-
-    PBRModel floor = PBRModelLoad("resources/models/plane.glb");
-
-    PBRMaterial floor_mat = (PBRMaterial){0};
-    PBRMaterialSetup(&floor_mat, shader, NULL);
-    PBRLoadTextures(&floor_mat, PBR_TEXTURE_ALBEDO, "resources/road_a.png");
-    PBRLoadTextures(&floor_mat, PBR_TEXTURE_MRA, "resources/road_mra.png");
-    PBRLoadTextures(&floor_mat, PBR_TEXTURE_NORMAL, "resources/road_n.png");
-    PBRSetVec2(&floor_mat, PBR_VEC2_TILING,(Vector2){0.5,0.5});
-    PBRSetMaterial(&floor,&floor_mat,0);
+    shader.locs[SHADER_LOC_MAP_ALBEDO] = GetShaderLocation(shader, "albedoMap");
+    // In reality, metalness, roughness, and ambient occlusion are all packed into the MRA texture
+    // We'll pass it in as the metalness map
+    shader.locs[SHADER_LOC_MAP_METALNESS] = GetShaderLocation(shader, "mraMap");
+    shader.locs[SHADER_LOC_MAP_NORMAL] = GetShaderLocation(shader, "normalMap");
+    // Similarly to the MRA map, the emissive map packs different information into a single texture
+    // This map stores both height and emission in reality
+    shader.locs[SHADER_LOC_MAP_EMISSION] = GetShaderLocation(shader, "emissiveMap");
+    shader.locs[SHADER_LOC_COLOR_DIFFUSE] = GetShaderLocation(shader, "albedoColor");
 
     shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos");
     int numOfLightsLoc = GetShaderLocation(shader, "numOfLights");
     int numOfLights = 4;
     SetShaderValue(shader, numOfLightsLoc, &numOfLights, SHADER_UNIFORM_INT);
 
-    Color ambCol = (Color){26,32,135,255};
+    Color ambCol = (Color){ 26,32,135,255 };
+    Vector3 ambColNormalized = (Vector3){ ambCol.r / 255.0f, ambCol.g / 255.0f, ambCol.b / 255.0f };
     float ambIntens = 0.02;
 
     int albedoLoc = GetShaderLocation(shader, "albedo");
-    PBRSetAmbient(shader,ambCol,ambIntens);
+    int ambColLoc = GetShaderLocation(shader, "ambientColor");
+    int ambLoc = GetShaderLocation(shader, "ambient");
+    SetShaderValue(shader, ambColLoc, &ambColNormalized, SHADER_UNIFORM_VEC3);
+    SetShaderValue(shader, ambLoc, &ambIntens, SHADER_UNIFORM_FLOAT);
+
+    int emissiveIntensityLoc = GetShaderLocation(shader, "emissivePower");
+    int emissiveColorLoc = GetShaderLocation(shader, "emissiveColor");
+    int textureTilingLoc = GetShaderLocation(shader, "tiling");
+
+    Model model = LoadModel("resources/models/old_car_new.glb");
+    // If the OBJ file format is used, we will have to generate tangents manually:
+    // GenMeshTangents(&model.meshes[0]);
+
+    model.materials[0].shader = shader;
+
+    model.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE;
+    model.materials[0].maps[MATERIAL_MAP_METALNESS].value = 0.0f;
+    model.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value = 0.0f;
+    model.materials[0].maps[MATERIAL_MAP_OCCLUSION].value = 1.0f;
+    model.materials[0].maps[MATERIAL_MAP_EMISSION].color = (Color){ 255, 162, 0, 255 };
+
+    model.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = LoadTexture("resources/old_car_d.png");
+    model.materials[0].maps[MATERIAL_MAP_METALNESS].texture = LoadTexture("resources/old_car_mra.png");
+    model.materials[0].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture("resources/old_car_n.png");
+    model.materials[0].maps[MATERIAL_MAP_EMISSION].texture = LoadTexture("resources/old_car_e.png");
+    // We store tiling parameters in the generic parameter slots in the Material class
+    Vector2 modelTiling = (Vector2){ 0.5f, 0.5f };
+
+    Model floor = LoadModel("resources/models/plane.glb");
+
+    floor.materials[0].shader = shader;
+    
+    floor.materials[0].maps[MATERIAL_MAP_ALBEDO].color = WHITE;
+    floor.materials[0].maps[MATERIAL_MAP_METALNESS].value = 0.0f;
+    floor.materials[0].maps[MATERIAL_MAP_ROUGHNESS].value = 0.0f;
+    floor.materials[0].maps[MATERIAL_MAP_OCCLUSION].value = 1.0f;
+    floor.materials[0].maps[MATERIAL_MAP_EMISSION].color = BLACK;
+
+    floor.materials[0].maps[MATERIAL_MAP_ALBEDO].texture = LoadTexture("resources/road_a.png");
+    floor.materials[0].maps[MATERIAL_MAP_METALNESS].texture = LoadTexture("resources/road_mra.png");
+    floor.materials[0].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture("resources/road_n.png");
+
+    Vector2 floorTiling = (Vector2){ 0.5f, 0.5f };
 
     // Create lights
     PBRLight lights[MAX_LIGHTS] = { 0 };
@@ -98,7 +153,13 @@ int main()
     lights[1] = PBRLightCreate(LIGHT_POINT, (Vector3){ 2,  1, 1 }, (Vector3){0,0,0}, GREEN,3.3, shader);
     lights[2] = PBRLightCreate(LIGHT_POINT, (Vector3){ -2, 1, 1 }, (Vector3){0,0,0}, RED,8.3, shader);
     lights[3] = PBRLightCreate(LIGHT_POINT, (Vector3){ 1,  1, -2 }, (Vector3){0,0,0}, BLUE,2, shader);
-    SetShaderValueV(shader, GetShaderLocation(shader, "lights"), lights, SHADER_UNIFORM_FLOAT, numOfLights);
+
+    // The textures are always used
+    int one = 1;
+    SetShaderValue(shader, GetShaderLocation(shader, "useTexAlbedo"), &one, SHADER_UNIFORM_INT);
+    SetShaderValue(shader, GetShaderLocation(shader, "useTexNormal"), &one, SHADER_UNIFORM_INT);
+    SetShaderValue(shader, GetShaderLocation(shader, "useTexMRA"), &one, SHADER_UNIFORM_INT);
+    SetShaderValue(shader, GetShaderLocation(shader, "useTexEmissive"), &one, SHADER_UNIFORM_INT);
 
     SetTargetFPS(60);               // Set our game to run at 60 frames-per-second-------------------------------------------------------------
 
@@ -122,32 +183,45 @@ int main()
 
         // Update light values (actually, only enable/disable them)
         for (int i = 0; i < MAX_LIGHTS; i++) PBRLightUpdate(shader, lights[i]);
-        emissiveCnt--;
-        if(emissiveCnt<=0){
-            emissiveCnt = GetRandomValue(0,20);
-            PBRSetFloat(&model_mat,PBR_PARAM_EMISSIVE,(float)GetRandomValue(0,100)/100);
-        }
         //----------------------------------------------------------------------------------
 
         // Draw
         //----------------------------------------------------------------------------------
         BeginDrawing();
+        
             ClearBackground(BLACK);
+            
             BeginMode3D(camera);
-
-                PBRDrawModel(floor, (Vector3){0,0,0}, 5.0f);
-                PBRDrawModel(model, (Vector3) {0, 0.0, 0}, 0.005);
+                
+                SetShaderValue(shader, textureTilingLoc, &floorTiling, SHADER_UNIFORM_VEC2);
+                Vector4 floorEmission = ColorNormalize(floor.materials[0].maps[MATERIAL_MAP_EMISSION].color);
+                SetShaderValue(shader, emissiveColorLoc, &floorEmission, SHADER_UNIFORM_VEC4);
+                DrawModel(floor, (Vector3){0,0,0}, 5.0f, WHITE);
+
+                emissiveCnt--;
+                if (emissiveCnt <= 0)
+                {
+                    emissiveCnt = GetRandomValue(0, 20);
+                    float intensity = (float)GetRandomValue(0, 100) / 100;
+                    SetShaderValue(shader, emissiveIntensityLoc, &intensity, SHADER_UNIFORM_FLOAT);
+                }
+                SetShaderValue(shader, textureTilingLoc, &modelTiling, SHADER_UNIFORM_VEC2);
+                Vector4 modelEmission = ColorNormalize(model.materials[0].maps[MATERIAL_MAP_EMISSION].color);
+                SetShaderValue(shader, emissiveColorLoc, &modelEmission, SHADER_UNIFORM_VEC4);
+                DrawModel(model, (Vector3) {0, 0.0, 0}, 0.005, WHITE);
 
                 // Draw spheres to show where the lights are
-                for (int i = 0; i < MAX_LIGHTS; i++) {
+                for (int i = 0; i < MAX_LIGHTS; i++)
+                {
                     Color col = (Color) {lights[i].color[0] * 255, lights[i].color[1] * 255, lights[i].color[2] * 255,
                                          lights[i].color[3] * 255};
                     if (lights[i].enabled) DrawSphereEx(lights[i].position, 0.2f, 8, 8, col);
                     else DrawSphereWires(lights[i].position, 0.2f, 8, 8, ColorAlpha(col, 0.3f));
                 }
+                
             EndMode3D();
 
-            DrawText("(c) Old Rusty Car model by Renafox (https://skfb.ly/LxRy)", screenWidth - 320, screenHeight - 20, 10, GRAY);
+            DrawText("(c) Old Rusty Car model by Renafox (https://skfb.ly/LxRy)", screenWidth - 320, screenHeight - 20, 10, LIGHTGRAY);
             DrawFPS(10, 10);
 
         EndDrawing();
@@ -157,15 +231,65 @@ int main()
     //--------------------------------------------------------------------------------------
     // De-Initialization
     //--------------------------------------------------------------------------------------
-
-    UnloadModel(floor.model);           // Unload model
-    UnloadModel(model.model);           // Unload model
+    model.materials[0].shader = (Shader){ 0 };
+    floor.materials[0].shader = (Shader){ 0 };
+    UnloadMaterial(model.materials[0]);
+    UnloadMaterial(floor.materials[0]);
+    model.materials[0].maps = NULL;
+    floor.materials[0].maps = NULL;
+    UnloadModel(floor);                 // Unload model
+    UnloadModel(model);                 // Unload model
     UnloadShader(shader);               // Unload Shader
-    UnloadPBRMaterial(floor_mat);       // Unload PBRMaterial
-    UnloadPBRMaterial(model_mat);       // Unload PBRMaterial
     
     CloseWindow();              // Close window and OpenGL context
     //--------------------------------------------------------------------------------------
 
     return 0;
+}
+
+PBRLight PBRLightCreate(int type, Vector3 position, Vector3 target, Color color, float intensity, Shader shader)
+{
+    PBRLight light = { 0 };
+
+    if (lightsCount < MAX_LIGHTS)
+    {
+        light.enabled = 1;
+        light.type = type;
+        light.position = position;
+        light.target = target;
+        light.color[0] = (float)color.r / (float)255;
+        light.color[1] = (float)color.g / (float)255;
+        light.color[2] = (float)color.b / (float)255;
+        light.color[3] = (float)color.a / (float)255;
+        light.intensity = intensity;
+        // NOTE: Lighting shader naming must be the provided ones
+        light.enabledLoc = GetShaderLocation(shader, TextFormat("lights[%i].enabled", lightsCount));
+        light.typeLoc = GetShaderLocation(shader, TextFormat("lights[%i].type", lightsCount));
+        light.positionLoc = GetShaderLocation(shader, TextFormat("lights[%i].position", lightsCount));
+        light.targetLoc = GetShaderLocation(shader, TextFormat("lights[%i].target", lightsCount));
+        light.colorLoc = GetShaderLocation(shader, TextFormat("lights[%i].color", lightsCount));
+        light.intensityLoc = GetShaderLocation(shader, TextFormat("lights[%i].intensity", lightsCount));
+        PBRLightUpdate(shader, light);
+
+        lightsCount++;
     }
+
+    return light;
+}
+
+// Send light properties to shader
+// NOTE: Light shader locations should be available
+void PBRLightUpdate(Shader shader, PBRLight light)
+{
+    SetShaderValue(shader, light.enabledLoc, &light.enabled, SHADER_UNIFORM_INT);
+    SetShaderValue(shader, light.typeLoc, &light.type, SHADER_UNIFORM_INT);
+    // Send to shader light position values
+    float position[3] = { light.position.x, light.position.y, light.position.z };
+    SetShaderValue(shader, light.positionLoc, position, SHADER_UNIFORM_VEC3);
+
+    // Send to shader light target position values
+    float target[3] = { light.target.x, light.target.y, light.target.z };
+    SetShaderValue(shader, light.targetLoc, target, SHADER_UNIFORM_VEC3);
+    SetShaderValue(shader, light.colorLoc, light.color, SHADER_UNIFORM_VEC4);
+    SetShaderValue(shader, light.intensityLoc, &light.intensity, SHADER_UNIFORM_FLOAT);
+}