Browse Source

adding normal map example

sir-irk 5 months ago
parent
commit
510dc763e9

+ 1 - 0
examples/Makefile

@@ -631,6 +631,7 @@ SHADERS = \
     shaders/shaders_mesh_instancing \
     shaders/shaders_mesh_instancing \
     shaders/shaders_model_shader \
     shaders/shaders_model_shader \
     shaders/shaders_multi_sample2d \
     shaders/shaders_multi_sample2d \
+    shaders/shaders_normalmap \
     shaders/shaders_palette_switch \
     shaders/shaders_palette_switch \
     shaders/shaders_postprocessing \
     shaders/shaders_postprocessing \
     shaders/shaders_raymarching \
     shaders/shaders_raymarching \

+ 1 - 0
examples/Makefile.Web

@@ -513,6 +513,7 @@ SHADERS = \
     shaders/shaders_mesh_instancing \
     shaders/shaders_mesh_instancing \
     shaders/shaders_model_shader \
     shaders/shaders_model_shader \
     shaders/shaders_multi_sample2d \
     shaders/shaders_multi_sample2d \
+    shaders/shaders_normalmap \
     shaders/shaders_palette_switch \
     shaders/shaders_palette_switch \
     shaders/shaders_postprocessing \
     shaders/shaders_postprocessing \
     shaders/shaders_raymarching \
     shaders/shaders_raymarching \

+ 64 - 0
examples/shaders/resources/shaders/glsl100/normalmap.fs

@@ -0,0 +1,64 @@
+#version 100
+
+precision mediump float;
+
+// Input vertex attributes (from vertex shader)
+varying vec3 fragPosition;
+varying vec2 fragTexCoord;
+varying vec3 fragNormal; //used for when normal mapping is toggled off
+varying vec4 fragColor;
+varying mat3 TBN;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform sampler2D normalMap;
+uniform vec4 colDiffuse;
+uniform vec3 viewPos;
+
+// NOTE: Add your custom variables here
+
+uniform vec3 lightPos;
+uniform bool useNormalMap;
+uniform float specularExponent;
+
+void main()
+{
+    vec4 texelColor = texture(texture0, vec2(fragTexCoord.x, fragTexCoord.y));
+    vec3 specular = vec3(0.0);
+    vec3 viewDir = normalize(viewPos - fragPosition);
+    vec3 lightDir = normalize(lightPos - fragPosition);
+
+    vec3 normal;
+    if (useNormalMap)
+    {
+        normal = texture(normalMap, vec2(fragTexCoord.x, fragTexCoord.y)).rgb;
+
+        //Transform normal values to the range -1.0 ... 1.0
+        normal = normalize(normal * 2.0 - 1.0);
+
+        //Transform the normal from tangent-space to world-space for lighting calculation
+        normal = normalize(normal * TBN);
+    }
+    else
+    {
+        normal = normalize(fragNormal);
+    }
+
+    vec4 tint = colDiffuse * fragColor;
+
+    vec3 lightColor = vec3(1.0, 1.0, 1.0);
+    float NdotL = max(dot(normal, lightDir), 0.0);
+    vec3 lightDot = lightColor * NdotL;
+
+    float specCo = 0.0;
+
+    if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewDir, reflect(-lightDir, normal))), specularExponent); // 16 refers to shine
+
+    specular += specCo;
+
+    finalColor = (texelColor * ((tint + vec4(specular, 1.0)) * vec4(lightDot, 1.0)));
+    finalColor += texelColor * (vec4(1.0, 1.0, 1.0, 1.0) / 40.0) * tint;
+
+    // Gamma correction
+    gl_FragColor = pow(finalColor, vec4(1.0 / 2.2));
+}

+ 76 - 0
examples/shaders/resources/shaders/glsl100/normalmap.vs

@@ -0,0 +1,76 @@
+#version 100
+
+// Input vertex attributes
+attribute vec3 vertexPosition;
+attribute vec2 vertexTexCoord;
+attribute vec3 vertexNormal;
+attribute vec4 vertexTangent;
+attribute vec4 vertexColor;
+
+// Input uniform values
+uniform mat4 mvp;
+uniform mat4 matModel;
+
+// Output vertex attributes (to fragment shader)
+varying vec3 fragPosition;
+varying vec2 fragTexCoord;
+varying vec3 fragNormal; //used for when normal mapping is toggled off
+varying vec4 fragColor;
+varying mat3 TBN;
+
+// NOTE: Add your custom variables here
+
+// https://github.com/glslify/glsl-inverse
+mat3 inverse(mat3 m)
+{
+    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];
+    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];
+    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];
+
+    float b01 = a22 * a11 - a12 * a21;
+    float b11 = -a22 * a10 + a12 * a20;
+    float b21 = a21 * a10 - a11 * a20;
+
+    float det = a00 * b01 + a01 * b11 + a02 * b21;
+
+    return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),
+        b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),
+        b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;
+}
+
+// https://github.com/glslify/glsl-transpose
+mat3 transpose(mat3 m)
+{
+    return mat3(m[0][0], m[1][0], m[2][0],
+        m[0][1], m[1][1], m[2][1],
+        m[0][2], m[1][2], m[2][2]);
+}
+
+void main()
+{
+    // Compute binormal from vertex normal and tangent. W component is the tangent handedness
+    vec3 vertexBinormal = cross(vertexNormal, vertexTangent.xyz) * vertexTangent.w;
+
+    // Compute fragment normal based on normal transformations
+    mat3 normalMatrix = transpose(inverse(mat3(matModel)));
+
+    // Compute fragment position based on model transformations
+    fragPosition = vec3(matModel * vec4(vertexPosition, 1.0));
+
+    //Create TBN matrix for transforming the normal map values from tangent-space to world-space
+    fragNormal = normalize(normalMatrix * vertexNormal);
+
+    vec3 fragTangent = normalize(normalMatrix * vertexTangent.xyz);
+    fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal) * fragNormal);
+
+    vec3 fragBinormal = normalize(normalMatrix * vertexBinormal);
+    fragBinormal = cross(fragNormal, fragTangent);
+
+    TBN = transpose(mat3(fragTangent, fragBinormal, fragNormal));
+
+    fragColor = vertexColor;
+
+    fragTexCoord = vertexTexCoord;
+
+    gl_Position = mvp * vec4(vertexPosition, 1.0);
+}

+ 62 - 0
examples/shaders/resources/shaders/glsl120/normalmap.fs

@@ -0,0 +1,62 @@
+#version 120
+
+// Input vertex attributes (from vertex shader)
+varying vec3 fragPosition;
+varying vec2 fragTexCoord;
+varying vec3 fragNormal; //used for when normal mapping is toggled off
+varying vec4 fragColor;
+varying mat3 TBN;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform sampler2D normalMap;
+uniform vec4 colDiffuse;
+uniform vec3 viewPos;
+
+// NOTE: Add your custom variables here
+
+uniform vec3 lightPos;
+uniform bool useNormalMap;
+uniform float specularExponent;
+
+void main()
+{
+    vec4 texelColor = texture(texture0, vec2(fragTexCoord.x, fragTexCoord.y));
+    vec3 specular = vec3(0.0);
+    vec3 viewDir = normalize(viewPos - fragPosition);
+    vec3 lightDir = normalize(lightPos - fragPosition);
+
+    vec3 normal;
+    if (useNormalMap)
+    {
+        normal = texture(normalMap, vec2(fragTexCoord.x, fragTexCoord.y)).rgb;
+
+        //Transform normal values to the range -1.0 ... 1.0
+        normal = normalize(normal * 2.0 - 1.0);
+
+        //Transform the normal from tangent-space to world-space for lighting calculation
+        normal = normalize(normal * TBN);
+    }
+    else
+    {
+        normal = normalize(fragNormal);
+    }
+
+    vec4 tint = colDiffuse * fragColor;
+
+    vec3 lightColor = vec3(1.0, 1.0, 1.0);
+    float NdotL = max(dot(normal, lightDir), 0.0);
+    vec3 lightDot = lightColor * NdotL;
+
+    float specCo = 0.0;
+
+    if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewDir, reflect(-lightDir, normal))), specularExponent); // 16 refers to shine
+
+    specular += specCo;
+
+    finalColor = (texelColor * ((tint + vec4(specular, 1.0)) * vec4(lightDot, 1.0)));
+    finalColor += texelColor * (vec4(1.0, 1.0, 1.0, 1.0) / 40.0) * tint;
+
+    // Gamma correction
+    gl_FragColor = pow(finalColor, vec4(1.0 / 2.2));
+}

+ 76 - 0
examples/shaders/resources/shaders/glsl120/normalmap.vs

@@ -0,0 +1,76 @@
+#version 120
+
+// Input vertex attributes
+attribute vec3 vertexPosition;
+attribute vec2 vertexTexCoord;
+attribute vec3 vertexNormal;
+attribute vec4 vertexTangent;
+attribute vec4 vertexColor;
+
+// Input uniform values
+uniform mat4 mvp;
+uniform mat4 matModel;
+
+// Output vertex attributes (to fragment shader)
+varying vec3 fragPosition;
+varying vec2 fragTexCoord;
+varying vec3 fragNormal; //used for when normal mapping is toggled off
+varying vec4 fragColor;
+varying mat3 TBN;
+
+// NOTE: Add your custom variables here
+
+// https://github.com/glslify/glsl-inverse
+mat3 inverse(mat3 m)
+{
+    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];
+    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];
+    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];
+
+    float b01 = a22 * a11 - a12 * a21;
+    float b11 = -a22 * a10 + a12 * a20;
+    float b21 = a21 * a10 - a11 * a20;
+
+    float det = a00 * b01 + a01 * b11 + a02 * b21;
+
+    return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),
+        b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),
+        b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;
+}
+
+// https://github.com/glslify/glsl-transpose
+mat3 transpose(mat3 m)
+{
+    return mat3(m[0][0], m[1][0], m[2][0],
+        m[0][1], m[1][1], m[2][1],
+        m[0][2], m[1][2], m[2][2]);
+}
+
+void main()
+{
+    // Compute binormal from vertex normal and tangent. W component is the tangent handedness
+    vec3 vertexBinormal = cross(vertexNormal, vertexTangent.xyz) * vertexTangent.w;
+
+    // Compute fragment normal based on normal transformations
+    mat3 normalMatrix = transpose(inverse(mat3(matModel)));
+
+    // Compute fragment position based on model transformations
+    fragPosition = vec3(matModel * vec4(vertexPosition, 1.0));
+
+    //Create TBN matrix for transforming the normal map values from tangent-space to world-space
+    fragNormal = normalize(normalMatrix * vertexNormal);
+
+    vec3 fragTangent = normalize(normalMatrix * vertexTangent.xyz);
+    fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal) * fragNormal);
+
+    vec3 fragBinormal = normalize(normalMatrix * vertexBinormal);
+    fragBinormal = cross(fragNormal, fragTangent);
+
+    TBN = transpose(mat3(fragTangent, fragBinormal, fragNormal));
+
+    fragColor = vertexColor;
+
+    fragTexCoord = vertexTexCoord;
+
+    gl_Position = mvp * vec4(vertexPosition, 1.0);
+}

+ 67 - 0
examples/shaders/resources/shaders/glsl330/normalmap.fs

@@ -0,0 +1,67 @@
+#version 330
+
+// Input vertex attributes (from vertex shader)
+in vec3 fragPosition;
+in vec2 fragTexCoord;
+in vec3 fragNormal; //used for when normal mapping is toggled off
+in vec4 fragColor;
+
+// Input uniform values
+uniform sampler2D texture0;
+uniform sampler2D normalMap;
+uniform vec4 colDiffuse;
+
+uniform vec3 viewPos;
+uniform vec4 tintColor;
+
+uniform vec3 lightPos;
+uniform bool useNormalMap;
+uniform float specularExponent;
+
+// Output fragment color
+out vec4 finalColor;
+
+in mat3 TBN;
+
+void main()
+{
+    vec4 texelColor = texture(texture0, vec2(fragTexCoord.x, fragTexCoord.y));
+    vec3 specular = vec3(0.0);
+    vec3 viewDir = normalize(viewPos - fragPosition);
+    vec3 lightDir = normalize(lightPos - fragPosition);
+
+    vec3 normal;
+    if (useNormalMap)
+    {
+        normal = texture(normalMap, vec2(fragTexCoord.x, fragTexCoord.y)).rgb;
+
+        //Transform normal values to the range -1.0 ... 1.0
+        normal = normalize(normal * 2.0 - 1.0);
+
+        //Transform the normal from tangent-space to world-space for lighting calculation
+        normal = normalize(normal * TBN);
+    }
+    else
+    {
+        normal = normalize(fragNormal);
+    }
+
+    vec4 tint = colDiffuse * fragColor;
+
+    vec3 lightColor = vec3(1.0, 1.0, 1.0);
+    float NdotL = max(dot(normal, lightDir), 0.0);
+    vec3 lightDot = lightColor * NdotL;
+
+    float specCo = 0.0;
+
+    if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewDir, reflect(-lightDir, normal))), specularExponent); // 16 refers to shine
+
+    specular += specCo;
+
+    finalColor = (texelColor * ((tint + vec4(specular, 1.0)) * vec4(lightDot, 1.0)));
+    finalColor += texelColor * (vec4(1.0, 1.0, 1.0, 1.0) / 40.0) * tint;
+
+    // Gamma correction
+    finalColor = pow(finalColor, vec4(1.0 / 2.2));
+    //finalColor = vec4(normal, 1.0);
+}

+ 48 - 0
examples/shaders/resources/shaders/glsl330/normalmap.vs

@@ -0,0 +1,48 @@
+#version 330
+
+// Input vertex attributes
+in vec3 vertexPosition;
+in vec2 vertexTexCoord;
+in vec3 vertexNormal;
+in vec4 vertexTangent;
+in vec4 vertexColor;
+
+// Input uniform values
+uniform mat4 mvp;
+uniform mat4 matModel;
+
+// Output vertex attributes (to fragment shader)
+out vec3 fragPosition;
+out vec2 fragTexCoord;
+out vec3 fragNormal; //used for when normal mapping is toggled off
+out vec4 fragColor;
+out mat3 TBN;
+
+void main()
+{
+    // Compute binormal from vertex normal and tangent. W component is the tangent handedness
+    vec3 vertexBinormal = cross(vertexNormal, vertexTangent.xyz) * vertexTangent.w;
+
+    // Compute fragment normal based on normal transformations
+    mat3 normalMatrix = transpose(inverse(mat3(matModel)));
+
+    // Compute fragment position based on model transformations
+    fragPosition = vec3(matModel * vec4(vertexPosition, 1.0));
+
+    //Create TBN matrix for transforming the normal map values from tangent-space to world-space
+    fragNormal = normalize(normalMatrix * vertexNormal);
+
+    vec3 fragTangent = normalize(normalMatrix * vertexTangent.xyz);
+    fragTangent = normalize(fragTangent - dot(fragTangent, fragNormal) * fragNormal);
+
+    vec3 fragBinormal = normalize(normalMatrix * vertexBinormal);
+    fragBinormal = cross(fragNormal, fragTangent);
+
+    TBN = transpose(mat3(fragTangent, fragBinormal, fragNormal));
+
+    fragColor = vertexColor;
+
+    fragTexCoord = vertexTexCoord;
+
+    gl_Position = mvp * vec4(vertexPosition, 1.0);
+}

BIN
examples/shaders/resources/tiles_diffuse.png


BIN
examples/shaders/resources/tiles_normal.png


+ 171 - 0
examples/shaders/shaders_normalmap.c

@@ -0,0 +1,171 @@
+/*******************************************************************************************
+ *
+ *   raylib [shaders] example - normalmap
+ *
+ *   Example complexity rating: [★★★★] 4/4
+ *
+ *   NOTE: This example requires raylib OpenGL 3.3 or ES2 versions for shaders support,
+ *         OpenGL 1.1 does not support shaders, recompile raylib to OpenGL 3.3 version.
+ *
+ *   Example originally created with raylib 5.6, last time updated with raylib 5.6
+ *
+ *   Example contributed by Jeremy Montgomery (@Sir_Irk) and reviewed by Ramon Santamaria (@raysan5)
+ *
+ *   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
+ *   BSD-like license that allows static linking with closed source software
+ *
+ *   Copyright (c) 2025-2025 Jeremy Montgomery (@Sir_Irk) and Ramon Santamaria (@raysan5)
+ *k
+ ********************************************************************************************/
+
+#include <raylib.h>
+#include <raymath.h>
+
+#if defined(PLATFORM_DESKTOP)
+#define GLSL_VERSION 330
+#else // PLATFORM_ANDROID, PLATFORM_WEB
+#define GLSL_VERSION 100
+#endif
+
+//------------------------------------------------------------------------------------
+// Program main entry point
+//------------------------------------------------------------------------------------
+int
+main(void)
+{
+    // Initialization
+    //--------------------------------------------------------------------------------------
+
+    SetConfigFlags(FLAG_MSAA_4X_HINT);
+    InitWindow(800, 450, "Normal Map");
+
+    Camera camera = {0};
+    camera.position = (Vector3){0.0f, 2.0f, -4.0f};
+    camera.target = (Vector3){0.0f, 0.0f, 0.0f};
+    camera.up = (Vector3){0.0f, 1.0f, 0.0f};
+    camera.fovy = 45.0f;
+    camera.projection = CAMERA_PERSPECTIVE;
+
+    // Load basic normal map lighting shader
+    Shader shader = LoadShader(TextFormat("resources/shaders/glsl%i/normalmap.vs", GLSL_VERSION), 
+                               TextFormat("resources/shaders/glsl%i/normalmap.fs", GLSL_VERSION));
+
+    // Get some required shader locations
+    shader.locs[SHADER_LOC_MAP_NORMAL] = GetShaderLocation(shader, "normalMap");
+    shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(shader, "viewPos");
+    // NOTE: "matModel" location name is automatically assigned on shader loading,
+    // no need to get the location again if using that uniform name
+    // shader.locs[SHADER_LOC_MATRIX_MODEL] = GetShaderLocation(shader, "matModel");
+
+    // This example uses just 1 point light.
+    Vector3 lightPosition = {0.0f, 1.0f, 0.0f};
+    int lightPosLoc = GetShaderLocation(shader, "lightPos");
+
+    // Load a plane model that has proper normals and tangents
+    Model plane = LoadModel("resources/models/plane.glb");
+
+    // Set the plane model's shader and texture maps
+    plane.materials[0].shader = shader;
+    plane.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = LoadTexture("resources/tiles_diffuse.png");
+    plane.materials[0].maps[MATERIAL_MAP_NORMAL].texture = LoadTexture("resources/tiles_normal.png");
+
+    // Generate Mipmaps and use TRILINEAR filtering to help with texture aliasing
+    GenTextureMipmaps(&plane.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture);
+    GenTextureMipmaps(&plane.materials[0].maps[MATERIAL_MAP_NORMAL].texture);
+
+    SetTextureFilter(plane.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture, TEXTURE_FILTER_TRILINEAR);
+    SetTextureFilter(plane.materials[0].maps[MATERIAL_MAP_NORMAL].texture, TEXTURE_FILTER_TRILINEAR);
+
+    // Specular exponent AKA shininess of the material.
+    float specularExponent = 8.0f;
+    int specularExponentLoc = GetShaderLocation(shader, "specularExponent");
+
+    // Allow toggling the normal map on and off for comparison purposes
+    int useNormalMap = 1;
+    int useNormalMapLoc = GetShaderLocation(shader, "useNormalMap");
+
+    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
+        //----------------------------------------------------------------------------------
+
+        // Move the light around on the X and Z axis using WASD keys
+        Vector3 direction = {0};
+        if (IsKeyDown(KEY_W)) direction = Vector3Add(direction, (Vector3){0.0f, 0.0f, 1.0f});
+        if (IsKeyDown(KEY_S)) direction = Vector3Add(direction, (Vector3){0.0f, 0.0f, -1.0f});
+        if (IsKeyDown(KEY_D)) direction = Vector3Add(direction, (Vector3){-1.0f, 0.0f, 0.0f});
+        if (IsKeyDown(KEY_A)) direction = Vector3Add(direction, (Vector3){1.0f, 0.0f, 0.0f});
+
+        direction = Vector3Normalize(direction);
+        lightPosition = Vector3Add(lightPosition, Vector3Scale(direction, GetFrameTime() * 3.0f));
+
+        // Increase/Decrease the specular exponent(shininess)
+        if (IsKeyDown(KEY_UP)) specularExponent = Clamp(specularExponent + 40.0f * GetFrameTime(), 2.0f, 128.0f);
+        if (IsKeyDown(KEY_DOWN)) specularExponent = Clamp(specularExponent - 40.0f * GetFrameTime(), 2.0f, 128.0f);
+
+        // Toggle normal map on and off
+        if (IsKeyPressed(KEY_N)) useNormalMap = !useNormalMap;
+
+        // Spin plane model at a constant rate
+        plane.transform = MatrixRotateY(GetTime() * 0.5f);
+
+        // Update shader values
+        float lightPos[3] = {lightPosition.x, lightPosition.y, lightPosition.z};
+        SetShaderValue(shader, lightPosLoc, lightPos, SHADER_UNIFORM_VEC3);
+
+        float camPos[3] = {camera.position.x, camera.position.y, camera.position.z};
+        SetShaderValue(shader, shader.locs[SHADER_LOC_VECTOR_VIEW], camPos, SHADER_UNIFORM_VEC3);
+
+        SetShaderValue(shader, specularExponentLoc, &specularExponent, SHADER_UNIFORM_FLOAT);
+
+        SetShaderValue(shader, useNormalMapLoc, &useNormalMap, SHADER_UNIFORM_INT);
+        //--------------------------------------------------------------------------------------
+
+        // Draw
+        //----------------------------------------------------------------------------------
+        BeginDrawing();
+
+            ClearBackground(RAYWHITE);
+
+            BeginMode3D(camera);
+
+                BeginShaderMode(shader);
+
+                    DrawModel(plane, Vector3Zero(), 2.0f, WHITE);
+
+                EndShaderMode();
+
+                //Draw sphere to show light position
+                DrawSphereWires(lightPosition, 0.2f, 8, 8, ORANGE);
+
+            EndMode3D();
+
+            Color textColor = (useNormalMap) ? DARKGREEN : RED;
+            const char *toggleStr = (useNormalMap) ? "On" : "Off";
+            DrawText(TextFormat("Use key [N] to toggle normal map: %s", toggleStr), 10, 30, 20, textColor);
+
+            int yOffset = 24;
+            DrawText("Use keys [W][A][S][D] to move the light", 10, 30 + yOffset * 1, 20, BLACK);
+            DrawText("Use kyes [Up][Down] to change specular exponent", 10, 30 + yOffset * 2, 20, BLACK);
+            DrawText(TextFormat("Specular Exponent: %.2f", specularExponent), 10, 30 + yOffset * 3, 20, BLUE);
+
+            DrawFPS(10, 10);
+
+        EndDrawing();
+        //--------------------------------------------------------------------------------------
+    }
+
+    // De-Initialization
+    //--------------------------------------------------------------------------------------
+    UnloadShader(shader);
+    UnloadModel(plane);
+
+    CloseWindow(); // Close window and OpenGL context
+    //--------------------------------------------------------------------------------------
+
+    return 0;
+}