|  |  | @ -0,0 +1,321 @@ | 
		
	
		
			
			|  |  |  | /******************************************************************************************* | 
		
	
		
			
			|  |  |  | * | 
		
	
		
			
			|  |  |  | *   raylib [shaders] example - deferred rendering | 
		
	
		
			
			|  |  |  | * | 
		
	
		
			
			|  |  |  | *   NOTE: This example requires raylib OpenGL 3.3 or ES 3 versions. | 
		
	
		
			
			|  |  |  | * | 
		
	
		
			
			|  |  |  | *   Example originally created with raylib 4.5, last time updated with raylib 4.5 | 
		
	
		
			
			|  |  |  | * | 
		
	
		
			
			|  |  |  | *   Example contributed by Justin Andreas Lacoste (@27justin) 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) 2023 Justin Andreas Lacoste (@27justin) | 
		
	
		
			
			|  |  |  | * | 
		
	
		
			
			|  |  |  | ********************************************************************************************/ | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | #include <stdlib.h> | 
		
	
		
			
			|  |  |  | #include <GLES3/gl3.h> | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | #include "raylib.h" | 
		
	
		
			
			|  |  |  | #include "rlgl.h" | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | #include "raymath.h" | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | #define RLIGHTS_IMPLEMENTATION | 
		
	
		
			
			|  |  |  | #include "rlights.h" | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | #if defined(PLATFORM_DESKTOP) | 
		
	
		
			
			|  |  |  | #define GLSL_VERSION            330 | 
		
	
		
			
			|  |  |  | #else   // PLATFORM_ANDROID, PLATFORM_WEB | 
		
	
		
			
			|  |  |  | #define GLSL_VERSION            100 | 
		
	
		
			
			|  |  |  | #endif | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | typedef struct { | 
		
	
		
			
			|  |  |  | unsigned int framebuffer; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | unsigned int positionTexture; | 
		
	
		
			
			|  |  |  | unsigned int normalTexture; | 
		
	
		
			
			|  |  |  | unsigned int albedoSpecTexture; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | unsigned int depthRenderbuffer; | 
		
	
		
			
			|  |  |  | } GBuffer; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | int main(void) { | 
		
	
		
			
			|  |  |  | // Initialization | 
		
	
		
			
			|  |  |  | // ------------------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | const int screenWidth = 800; | 
		
	
		
			
			|  |  |  | const int screenHeight = 450; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | InitWindow(screenWidth, screenHeight, "raylib [shaders] example - deferred render"); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | Camera camera = { 0 }; | 
		
	
		
			
			|  |  |  | camera.position = (Vector3){ 5.0f, 4.0f, 5.0f };    // Camera position | 
		
	
		
			
			|  |  |  | camera.target = (Vector3){ 0.0f, 1.0f, 0.0f };      // Camera looking at point | 
		
	
		
			
			|  |  |  | camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };          // Camera up vector (rotation towards target) | 
		
	
		
			
			|  |  |  | camera.fovy = 60.0f;                                // Camera field-of-view Y | 
		
	
		
			
			|  |  |  | camera.projection = CAMERA_PERSPECTIVE;             // Camera projection type | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Load plane model from a generated mesh | 
		
	
		
			
			|  |  |  | Model model = LoadModelFromMesh(GenMeshPlane(10.0f, 10.0f, 3, 3)); | 
		
	
		
			
			|  |  |  | Model cube = LoadModelFromMesh(GenMeshCube(2.0f, 2.0f, 2.0f)); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Load geometry buffer (G-buffer) shader and deferred shader | 
		
	
		
			
			|  |  |  | Shader gbufferShader = LoadShader("resources/shaders/glsl330/gbuffer.vs", | 
		
	
		
			
			|  |  |  | "resources/shaders/glsl330/gbuffer.fs"); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | Shader deferredShader = LoadShader("resources/shaders/glsl330/deferred_shading.vs", | 
		
	
		
			
			|  |  |  | "resources/shaders/glsl330/deferred_shading.fs"); | 
		
	
		
			
			|  |  |  | deferredShader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(deferredShader, "viewPosition"); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Initialize the G-buffer | 
		
	
		
			
			|  |  |  | GBuffer gBuffer = { 0 }; | 
		
	
		
			
			|  |  |  | gBuffer.framebuffer = rlLoadFramebuffer(screenWidth, screenHeight); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | if(!gBuffer.framebuffer) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | TraceLog(LOG_WARNING, "Failed to create framebuffer"); | 
		
	
		
			
			|  |  |  | exit(1); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | rlEnableFramebuffer(gBuffer.framebuffer); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Since we are storing position and normal data in these textures, | 
		
	
		
			
			|  |  |  | // we need to use a floating point format. | 
		
	
		
			
			|  |  |  | gBuffer.positionTexture = rlLoadTexture(NULL, screenWidth, screenHeight, RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32, 1); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | gBuffer.normalTexture = rlLoadTexture(NULL, screenWidth, screenHeight, RL_PIXELFORMAT_UNCOMPRESSED_R32G32B32, 1); | 
		
	
		
			
			|  |  |  | // Albedo (diffuse color) and specular strength can be combined into one texture. | 
		
	
		
			
			|  |  |  | // The color in RGB, and the specular strength in the alpha channel. | 
		
	
		
			
			|  |  |  | gBuffer.albedoSpecTexture = rlLoadTexture(NULL, screenWidth, screenHeight, RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Activate the draw buffers for our framebuffer | 
		
	
		
			
			|  |  |  | rlActiveDrawBuffers(3); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Now we attach our textures to the framebuffer. | 
		
	
		
			
			|  |  |  | rlFramebufferAttach(gBuffer.framebuffer, gBuffer.positionTexture, RL_ATTACHMENT_COLOR_CHANNEL0, RL_ATTACHMENT_TEXTURE2D, 0); | 
		
	
		
			
			|  |  |  | rlFramebufferAttach(gBuffer.framebuffer, gBuffer.normalTexture, RL_ATTACHMENT_COLOR_CHANNEL1, RL_ATTACHMENT_TEXTURE2D, 0); | 
		
	
		
			
			|  |  |  | rlFramebufferAttach(gBuffer.framebuffer, gBuffer.albedoSpecTexture, RL_ATTACHMENT_COLOR_CHANNEL2, RL_ATTACHMENT_TEXTURE2D, 0); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Finally we attach the depth buffer. | 
		
	
		
			
			|  |  |  | gBuffer.depthRenderbuffer = rlLoadTextureDepth(screenWidth, screenHeight, true); | 
		
	
		
			
			|  |  |  | rlFramebufferAttach(gBuffer.framebuffer, gBuffer.depthRenderbuffer, RL_ATTACHMENT_DEPTH, RL_ATTACHMENT_RENDERBUFFER, 0); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Make sure our framebuffer is complete. | 
		
	
		
			
			|  |  |  | // NOTE: rlFramebufferComplete() automatically unbinds the framebuffer, so we don't have | 
		
	
		
			
			|  |  |  | // to rlDisableFramebuffer() here. | 
		
	
		
			
			|  |  |  | if(rlFramebufferComplete(gBuffer.framebuffer) != true) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | TraceLog(LOG_WARNING, "Framebuffer is not complete"); | 
		
	
		
			
			|  |  |  | exit(1); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Now we initialize the sampler2D uniform's in the deferred shader. | 
		
	
		
			
			|  |  |  | // We do this by setting the uniform's value to the color channel slot we earlier | 
		
	
		
			
			|  |  |  | // bound our textures to. | 
		
	
		
			
			|  |  |  | rlEnableShader(deferredShader.id); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | rlSetUniformSampler(rlGetLocationUniform(deferredShader.id, "gPosition"), 0); | 
		
	
		
			
			|  |  |  | rlSetUniformSampler(rlGetLocationUniform(deferredShader.id, "gNormal"), 1); | 
		
	
		
			
			|  |  |  | rlSetUniformSampler(rlGetLocationUniform(deferredShader.id, "gAlbedoSpec"), 2); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | rlDisableShader(); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Assign out lighting shader to model | 
		
	
		
			
			|  |  |  | model.materials[0].shader = gbufferShader; | 
		
	
		
			
			|  |  |  | cube.materials[0].shader = gbufferShader; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Create lights | 
		
	
		
			
			|  |  |  | //-------------------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | Light lights[MAX_LIGHTS] = { 0 }; | 
		
	
		
			
			|  |  |  | lights[0] = CreateLight(LIGHT_POINT, (Vector3){ -2, 1, -2 }, Vector3Zero(), YELLOW, deferredShader); | 
		
	
		
			
			|  |  |  | lights[1] = CreateLight(LIGHT_POINT, (Vector3){ 2, 1, 2 }, Vector3Zero(), RED, deferredShader); | 
		
	
		
			
			|  |  |  | lights[2] = CreateLight(LIGHT_POINT, (Vector3){ -2, 1, 2 }, Vector3Zero(), GREEN, deferredShader); | 
		
	
		
			
			|  |  |  | lights[3] = CreateLight(LIGHT_POINT, (Vector3){ 2, 1, -2 }, Vector3Zero(), BLUE, deferredShader); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | const int MAX_CUBES = 30; | 
		
	
		
			
			|  |  |  | const float CUBE_SCALE = 0.25; | 
		
	
		
			
			|  |  |  | Vector3 cubePositions[MAX_CUBES]; | 
		
	
		
			
			|  |  |  | float cubeRotations[MAX_CUBES]; | 
		
	
		
			
			|  |  |  | for(int i = 0; i < MAX_CUBES; i++) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | cubePositions[i] = (Vector3) { | 
		
	
		
			
			|  |  |  | .x = (float)(rand() % 10) - 5, | 
		
	
		
			
			|  |  |  | .y = (float)(rand() % 5), | 
		
	
		
			
			|  |  |  | .z = (float)(rand() % 10) - 5, | 
		
	
		
			
			|  |  |  | }; | 
		
	
		
			
			|  |  |  | cubeRotations[i] = (float)(rand() % 360); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | enum { | 
		
	
		
			
			|  |  |  | POSITION, | 
		
	
		
			
			|  |  |  | NORMAL, | 
		
	
		
			
			|  |  |  | ALBEDO, | 
		
	
		
			
			|  |  |  | DEFERRED_SHADING | 
		
	
		
			
			|  |  |  | } activeTexture = DEFERRED_SHADING; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | rlEnableDepthTest(); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | SetTargetFPS(60);                   // Set our game to run at 60 frames-per-second | 
		
	
		
			
			|  |  |  | //--------------------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Main game loop | 
		
	
		
			
			|  |  |  | while (!WindowShouldClose()) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | // Update | 
		
	
		
			
			|  |  |  | //---------------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | UpdateCamera(&camera, CAMERA_ORBITAL); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Update the shader with the camera view vector (points towards { 0.0f, 0.0f, 0.0f }) | 
		
	
		
			
			|  |  |  | float cameraPos[3] = { camera.position.x, camera.position.y, camera.position.z }; | 
		
	
		
			
			|  |  |  | SetShaderValue(deferredShader, deferredShader.locs[SHADER_LOC_VECTOR_VIEW], cameraPos, SHADER_UNIFORM_VEC3); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Check key inputs to enable/disable lights | 
		
	
		
			
			|  |  |  | if (IsKeyPressed(KEY_Y)) { lights[0].enabled = !lights[0].enabled; } | 
		
	
		
			
			|  |  |  | if (IsKeyPressed(KEY_R)) { lights[1].enabled = !lights[1].enabled; } | 
		
	
		
			
			|  |  |  | if (IsKeyPressed(KEY_G)) { lights[2].enabled = !lights[2].enabled; } | 
		
	
		
			
			|  |  |  | if (IsKeyPressed(KEY_B)) { lights[3].enabled = !lights[3].enabled; } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Check key inputs to switch between G-buffer textures | 
		
	
		
			
			|  |  |  | if(IsKeyPressed(KEY_ONE)) activeTexture = POSITION; | 
		
	
		
			
			|  |  |  | if(IsKeyPressed(KEY_TWO)) activeTexture = NORMAL; | 
		
	
		
			
			|  |  |  | if(IsKeyPressed(KEY_THREE)) activeTexture = ALBEDO; | 
		
	
		
			
			|  |  |  | if(IsKeyPressed(KEY_FOUR)) activeTexture = DEFERRED_SHADING; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Update light values (actually, only enable/disable them) | 
		
	
		
			
			|  |  |  | for (int i = 0; i < MAX_LIGHTS; i++) UpdateLightValues(deferredShader, lights[i]); | 
		
	
		
			
			|  |  |  | //---------------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Draw | 
		
	
		
			
			|  |  |  | // --------------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | BeginDrawing(); | 
		
	
		
			
			|  |  |  | // Draw to the geometry buffer by first activating it. | 
		
	
		
			
			|  |  |  | rlEnableFramebuffer(gBuffer.framebuffer); | 
		
	
		
			
			|  |  |  | rlClearScreenBuffers();  // Clear color & depth buffer | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | rlDisableColorBlend(); | 
		
	
		
			
			|  |  |  | BeginMode3D(camera); | 
		
	
		
			
			|  |  |  | // NOTE: | 
		
	
		
			
			|  |  |  | // We have to use rlEnableShader here. `BeginShaderMode` or thus `rlSetShader` | 
		
	
		
			
			|  |  |  | // will not work, as they won't immediately load the shader program. | 
		
	
		
			
			|  |  |  | rlEnableShader(gbufferShader.id); | 
		
	
		
			
			|  |  |  | // When drawing a model here, make sure that the material's shaders | 
		
	
		
			
			|  |  |  | // are set to the gbuffer shader! | 
		
	
		
			
			|  |  |  | DrawModel(model, Vector3Zero(), 1.0f, WHITE); | 
		
	
		
			
			|  |  |  | DrawModel(cube, (Vector3) { 0.0, 1.0f, 0.0 }, 1.0f, WHITE); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | for(int i = 0; i < MAX_CUBES; i++) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | Vector3 position = cubePositions[i]; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | DrawModelEx(cube, position, (Vector3) { 1, 1, 1 }, cubeRotations[i], (Vector3) { CUBE_SCALE, CUBE_SCALE, CUBE_SCALE }, WHITE); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | rlDisableShader(); | 
		
	
		
			
			|  |  |  | EndMode3D(); | 
		
	
		
			
			|  |  |  | rlEnableColorBlend(); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Go back to the default framebuffer (0) and draw our deferred shading. | 
		
	
		
			
			|  |  |  | rlDisableFramebuffer(); | 
		
	
		
			
			|  |  |  | rlClearScreenBuffers(); // Clear color & depth buffer | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | switch(activeTexture) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | case DEFERRED_SHADING: | 
		
	
		
			
			|  |  |  | BeginMode3D(camera); | 
		
	
		
			
			|  |  |  | rlDisableColorBlend(); | 
		
	
		
			
			|  |  |  | rlEnableShader(deferredShader.id); | 
		
	
		
			
			|  |  |  | // Activate our g-buffer textures | 
		
	
		
			
			|  |  |  | // These will now be bound to the sampler2D uniforms `gPosition`, `gNormal`, | 
		
	
		
			
			|  |  |  | // and `gAlbedoSpec` | 
		
	
		
			
			|  |  |  | rlActiveTextureSlot(0); | 
		
	
		
			
			|  |  |  | rlEnableTexture(gBuffer.positionTexture); | 
		
	
		
			
			|  |  |  | rlActiveTextureSlot(1); | 
		
	
		
			
			|  |  |  | rlEnableTexture(gBuffer.normalTexture); | 
		
	
		
			
			|  |  |  | rlActiveTextureSlot(2); | 
		
	
		
			
			|  |  |  | rlEnableTexture(gBuffer.albedoSpecTexture); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Finally, we draw a fullscreen quad to our default framebuffer | 
		
	
		
			
			|  |  |  | // This will now be shaded using our deferred shader | 
		
	
		
			
			|  |  |  | rlLoadDrawQuad(); | 
		
	
		
			
			|  |  |  | rlDisableShader(); | 
		
	
		
			
			|  |  |  | rlEnableColorBlend(); | 
		
	
		
			
			|  |  |  | EndMode3D(); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // As a last step, we now copy over the depth buffer from our g-buffer to the | 
		
	
		
			
			|  |  |  | // default framebuffer. | 
		
	
		
			
			|  |  |  | glBindFramebuffer(GL_READ_FRAMEBUFFER, gBuffer.framebuffer); | 
		
	
		
			
			|  |  |  | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | 
		
	
		
			
			|  |  |  | glBlitFramebuffer(0, 0, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight, GL_DEPTH_BUFFER_BIT, GL_NEAREST); | 
		
	
		
			
			|  |  |  | rlDisableFramebuffer(); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Since our shader is now done and disabled, we can draw our lights in default | 
		
	
		
			
			|  |  |  | // forward rendering | 
		
	
		
			
			|  |  |  | BeginMode3D(camera); | 
		
	
		
			
			|  |  |  | rlEnableShader(rlGetShaderIdDefault()); | 
		
	
		
			
			|  |  |  | for(int i = 0; i < MAX_LIGHTS; i++) | 
		
	
		
			
			|  |  |  | { | 
		
	
		
			
			|  |  |  | if(lights[i].enabled) DrawSphereEx(lights[i].position, 0.2f, 8, 8, lights[i].color); | 
		
	
		
			
			|  |  |  | else DrawSphereWires(lights[i].position, 0.2f, 8, 8, ColorAlpha(lights[i].color, 0.3f)); | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  | rlDisableShader(); | 
		
	
		
			
			|  |  |  | EndMode3D(); | 
		
	
		
			
			|  |  |  | DrawText("FINAL RESULT", 10, screenHeight - 30, 20, DARKGREEN); | 
		
	
		
			
			|  |  |  | break; | 
		
	
		
			
			|  |  |  | case POSITION: | 
		
	
		
			
			|  |  |  | DrawTextureRec((Texture2D) { | 
		
	
		
			
			|  |  |  | .id = gBuffer.positionTexture, | 
		
	
		
			
			|  |  |  | .width = screenWidth, | 
		
	
		
			
			|  |  |  | .height = screenHeight, | 
		
	
		
			
			|  |  |  | }, (Rectangle) { 0, 0, screenWidth, -screenHeight }, Vector2Zero(), RAYWHITE); | 
		
	
		
			
			|  |  |  | DrawText("POSITION TEXTURE", 10, screenHeight - 30, 20, DARKGREEN); | 
		
	
		
			
			|  |  |  | break; | 
		
	
		
			
			|  |  |  | case NORMAL: | 
		
	
		
			
			|  |  |  | DrawTextureRec((Texture2D) { | 
		
	
		
			
			|  |  |  | .id = gBuffer.normalTexture, | 
		
	
		
			
			|  |  |  | .width = screenWidth, | 
		
	
		
			
			|  |  |  | .height = screenHeight, | 
		
	
		
			
			|  |  |  | }, (Rectangle) { 0, 0, screenWidth, -screenHeight }, Vector2Zero(), RAYWHITE); | 
		
	
		
			
			|  |  |  | DrawText("NORMAL TEXTURE", 10, screenHeight - 30, 20, DARKGREEN); | 
		
	
		
			
			|  |  |  | break; | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | case ALBEDO: | 
		
	
		
			
			|  |  |  | DrawTextureRec((Texture2D) { | 
		
	
		
			
			|  |  |  | .id = gBuffer.albedoSpecTexture, | 
		
	
		
			
			|  |  |  | .width = screenWidth, | 
		
	
		
			
			|  |  |  | .height = screenHeight, | 
		
	
		
			
			|  |  |  | }, (Rectangle) { 0, 0, screenWidth, -screenHeight }, Vector2Zero(), RAYWHITE); | 
		
	
		
			
			|  |  |  | DrawText("ALBEDO TEXTURE", 10, screenHeight - 30, 20, DARKGREEN); | 
		
	
		
			
			|  |  |  | break; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | DrawFPS(10, 10); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | DrawText("Use keys [Y][R][G][B] to toggle lights", 10, 40, 20, DARKGRAY); | 
		
	
		
			
			|  |  |  | DrawText("Use keys [1]-[4] to switch between G-buffer textures", 10, 70, 20, DARKGRAY); | 
		
	
		
			
			|  |  |  | EndDrawing(); | 
		
	
		
			
			|  |  |  | // ----------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // De-Initialization | 
		
	
		
			
			|  |  |  | //-------------------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  | UnloadModel(model);     // Unload the models | 
		
	
		
			
			|  |  |  | UnloadModel(cube); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | UnloadShader(deferredShader);   // Unload shaders | 
		
	
		
			
			|  |  |  | UnloadShader(gbufferShader); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | // Unload geometry buffer and all attached textures | 
		
	
		
			
			|  |  |  | rlUnloadFramebuffer(gBuffer.framebuffer); | 
		
	
		
			
			|  |  |  | rlUnloadTexture(gBuffer.positionTexture); | 
		
	
		
			
			|  |  |  | rlUnloadTexture(gBuffer.normalTexture); | 
		
	
		
			
			|  |  |  | rlUnloadTexture(gBuffer.albedoSpecTexture); | 
		
	
		
			
			|  |  |  | rlUnloadTexture(gBuffer.depthRenderbuffer); | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | CloseWindow();          // Close window and OpenGL context | 
		
	
		
			
			|  |  |  | //-------------------------------------------------------------------------------------- | 
		
	
		
			
			|  |  |  |  | 
		
	
		
			
			|  |  |  | return 0; | 
		
	
		
			
			|  |  |  | } | 
		
	
		
			
			|  |  |  |  |