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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 Ds0gX) literal 0 HcmV?d00001