From 26f6a64a39671487f5d1eeeffe7fce6538669051 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Sun, 16 Aug 2020 11:18:25 +0200 Subject: [PATCH] NEW EXAMPLE: shaders_hot_reloading #1198 --- .../resources/shaders/glsl330/reload.fs | 40 ++++++ examples/shaders/shaders_hot_reloading.c | 129 ++++++++++++++++++ examples/shaders/shaders_hot_reloading.png | Bin 0 -> 17029 bytes 3 files changed, 169 insertions(+) create mode 100644 examples/shaders/resources/shaders/glsl330/reload.fs create mode 100644 examples/shaders/shaders_hot_reloading.c create mode 100644 examples/shaders/shaders_hot_reloading.png diff --git a/examples/shaders/resources/shaders/glsl330/reload.fs b/examples/shaders/resources/shaders/glsl330/reload.fs new file mode 100644 index 000000000..9891a4b5f --- /dev/null +++ b/examples/shaders/resources/shaders/glsl330/reload.fs @@ -0,0 +1,40 @@ +#version 330 + +// Input vertex attributes (from vertex shader) +in vec2 fragTexCoord; // Texture coordinates (sampler2D) +in vec4 fragColor; // Tint color + +// Output fragment color +out vec4 finalColor; // Output fragment color + +// Uniform inputs +uniform vec2 resolution; // Viewport resolution (in pixels) +uniform vec2 mouse; // Mouse pixel xy coordinates +uniform float time; // Total run time (in secods) + +// Draw circle +vec4 DrawCircle(vec2 fragCoord, vec2 position, float radius, vec3 color) +{ + float d = length(position - fragCoord) - radius; + float t = clamp(d, 0.0, 1.0); + return vec4(color, 1.0 - t); +} + +void main() +{ + vec2 fragCoord = gl_FragCoord.xy; + vec2 position = vec2(mouse.x, resolution.y - mouse.y); + float radius = 40.0; + + // Draw background layer + vec4 colorA = vec4(0.2,0.2,0.8, 1.0); + vec4 colorB = vec4(1.0,0.7,0.2, 1.0); + vec4 layer1 = mix(colorA, colorB, abs(sin(time*0.1))); + + // Draw circle layer + vec3 color = vec3(0.9, 0.16, 0.21); + vec4 layer2 = DrawCircle(fragCoord, position, radius, color); + + // Blend the two layers + finalColor = mix(layer1, layer2, layer2.a); +} diff --git a/examples/shaders/shaders_hot_reloading.c b/examples/shaders/shaders_hot_reloading.c new file mode 100644 index 000000000..dcd3f8012 --- /dev/null +++ b/examples/shaders/shaders_hot_reloading.c @@ -0,0 +1,129 @@ +/******************************************************************************************* +* +* raylib [shaders] example - Hot reloading +* +* NOTE: This example requires raylib OpenGL 3.3 for shaders support and only #version 330 +* is currently supported. OpenGL ES 2.0 platforms are not supported at the moment. +* +* This example has been created using raylib 3.0 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Copyright (c) 2020 Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" + +#include // Required for: localtime(), asctime() + +#if defined(PLATFORM_DESKTOP) + #define GLSL_VERSION 330 +#else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB + #define GLSL_VERSION 100 +#endif + +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + int screenWidth = 800; + int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, "raylib [shaders] example - hot reloading"); + + const char *fragShaderFileName = "resources/shaders/glsl%i/reload.fs"; + long fragShaderFileModTime = GetFileModTime(FormatText(fragShaderFileName, GLSL_VERSION)); + + // Load raymarching shader + // NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader + Shader shader = LoadShader(0, FormatText(fragShaderFileName, GLSL_VERSION)); + + // Get shader locations for required uniforms + int resolutionLoc = GetShaderLocation(shader, "resolution"); + int mouseLoc = GetShaderLocation(shader, "mouse"); + int timeLoc = GetShaderLocation(shader, "time"); + + float resolution[2] = { (float)screenWidth, (float)screenHeight }; + SetShaderValue(shader, resolutionLoc, resolution, UNIFORM_VEC2); + + float totalTime = 0.0f; + bool shaderAutoReloading = false; + + 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 + //---------------------------------------------------------------------------------- + totalTime += GetFrameTime(); + Vector2 mouse = GetMousePosition(); + float mousePos[2] = { mouse.x, mouse.y }; + + // Set shader required uniform values + SetShaderValue(shader, timeLoc, &totalTime, UNIFORM_FLOAT); + SetShaderValue(shader, mouseLoc, mousePos, UNIFORM_VEC2); + + // Hot shader reloading + if (shaderAutoReloading || (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))) + { + long currentFragShaderModTime = GetFileModTime(FormatText(fragShaderFileName, GLSL_VERSION)); + + // Check if shader file has been modified + if (currentFragShaderModTime != fragShaderFileModTime) + { + // Try reloading updated shader + Shader updatedShader = LoadShader(0, FormatText(fragShaderFileName, GLSL_VERSION)); + + if (updatedShader.id != GetShaderDefault().id) // It was correctly loaded + { + UnloadShader(shader); + shader = updatedShader; + + // Get shader locations for required uniforms + resolutionLoc = GetShaderLocation(shader, "resolution"); + mouseLoc = GetShaderLocation(shader, "mouse"); + timeLoc = GetShaderLocation(shader, "time"); + + // Reset required uniforms + SetShaderValue(shader, resolutionLoc, resolution, UNIFORM_VEC2); + } + + fragShaderFileModTime = currentFragShaderModTime; + } + } + + if (IsKeyPressed(KEY_A)) shaderAutoReloading = !shaderAutoReloading; + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + // We only draw a white full-screen rectangle, frame is generated in shader + BeginShaderMode(shader); + DrawRectangle(0, 0, screenWidth, screenHeight, WHITE); + EndShaderMode(); + + DrawText(FormatText("PRESS [A] to TOGGLE SHADER AUTOLOADING: %s", + shaderAutoReloading? "AUTO" : "MANUAL"), 10, 10, 10, shaderAutoReloading? RED : BLACK); + if (!shaderAutoReloading) DrawText("MOUSE CLICK to SHADER RE-LOADING", 10, 30, 10, BLACK); + + DrawText(TextFormat("Shader last modification: %s", asctime(localtime(&fragShaderFileModTime))), 10, 430, 10, BLACK); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadShader(shader); // Unload shader + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/examples/shaders/shaders_hot_reloading.png b/examples/shaders/shaders_hot_reloading.png new file mode 100644 index 0000000000000000000000000000000000000000..e4c23fa2d6ae769fc677439bb28ba86f201e0e1d GIT binary patch literal 17029 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 literal 0 HcmV?d00001