shaders_hot_reloading.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /*******************************************************************************************
  2. *
  3. * raylib [shaders] example - hot reloading
  4. *
  5. * Example complexity rating: [★★★☆] 3/4
  6. *
  7. * NOTE: This example requires raylib OpenGL 3.3 for shaders support and only #version 330
  8. * is currently supported. OpenGL ES 2.0 platforms are not supported at the moment
  9. *
  10. * Example originally created with raylib 3.0, last time updated with raylib 3.5
  11. *
  12. * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
  13. * BSD-like license that allows static linking with closed source software
  14. *
  15. * Copyright (c) 2020-2025 Ramon Santamaria (@raysan5)
  16. *
  17. ********************************************************************************************/
  18. #include "raylib.h"
  19. #include "rlgl.h"
  20. #include <time.h> // Required for: localtime(), asctime()
  21. #if defined(PLATFORM_DESKTOP)
  22. #define GLSL_VERSION 330
  23. #else // PLATFORM_ANDROID, PLATFORM_WEB
  24. #define GLSL_VERSION 100
  25. #endif
  26. //------------------------------------------------------------------------------------
  27. // Program main entry point
  28. //------------------------------------------------------------------------------------
  29. int main(void)
  30. {
  31. // Initialization
  32. //--------------------------------------------------------------------------------------
  33. const int screenWidth = 800;
  34. const int screenHeight = 450;
  35. InitWindow(screenWidth, screenHeight, "raylib [shaders] example - hot reloading");
  36. const char *fragShaderFileName = "resources/shaders/glsl%i/reload.fs";
  37. time_t fragShaderFileModTime = GetFileModTime(TextFormat(fragShaderFileName, GLSL_VERSION));
  38. // Load raymarching shader
  39. // NOTE: Defining 0 (NULL) for vertex shader forces usage of internal default vertex shader
  40. Shader shader = LoadShader(0, TextFormat(fragShaderFileName, GLSL_VERSION));
  41. // Get shader locations for required uniforms
  42. int resolutionLoc = GetShaderLocation(shader, "resolution");
  43. int mouseLoc = GetShaderLocation(shader, "mouse");
  44. int timeLoc = GetShaderLocation(shader, "time");
  45. float resolution[2] = { (float)screenWidth, (float)screenHeight };
  46. SetShaderValue(shader, resolutionLoc, resolution, SHADER_UNIFORM_VEC2);
  47. float totalTime = 0.0f;
  48. bool shaderAutoReloading = false;
  49. SetTargetFPS(60); // Set our game to run at 60 frames-per-second
  50. //--------------------------------------------------------------------------------------
  51. // Main game loop
  52. while (!WindowShouldClose()) // Detect window close button or ESC key
  53. {
  54. // Update
  55. //----------------------------------------------------------------------------------
  56. totalTime += GetFrameTime();
  57. Vector2 mouse = GetMousePosition();
  58. float mousePos[2] = { mouse.x, mouse.y };
  59. // Set shader required uniform values
  60. SetShaderValue(shader, timeLoc, &totalTime, SHADER_UNIFORM_FLOAT);
  61. SetShaderValue(shader, mouseLoc, mousePos, SHADER_UNIFORM_VEC2);
  62. // Hot shader reloading
  63. if (shaderAutoReloading || (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)))
  64. {
  65. long currentFragShaderModTime = GetFileModTime(TextFormat(fragShaderFileName, GLSL_VERSION));
  66. // Check if shader file has been modified
  67. if (currentFragShaderModTime != fragShaderFileModTime)
  68. {
  69. // Try reloading updated shader
  70. Shader updatedShader = LoadShader(0, TextFormat(fragShaderFileName, GLSL_VERSION));
  71. if (updatedShader.id != rlGetShaderIdDefault()) // It was correctly loaded
  72. {
  73. UnloadShader(shader);
  74. shader = updatedShader;
  75. // Get shader locations for required uniforms
  76. resolutionLoc = GetShaderLocation(shader, "resolution");
  77. mouseLoc = GetShaderLocation(shader, "mouse");
  78. timeLoc = GetShaderLocation(shader, "time");
  79. // Reset required uniforms
  80. SetShaderValue(shader, resolutionLoc, resolution, SHADER_UNIFORM_VEC2);
  81. }
  82. fragShaderFileModTime = currentFragShaderModTime;
  83. }
  84. }
  85. if (IsKeyPressed(KEY_A)) shaderAutoReloading = !shaderAutoReloading;
  86. //----------------------------------------------------------------------------------
  87. // Draw
  88. //----------------------------------------------------------------------------------
  89. BeginDrawing();
  90. ClearBackground(RAYWHITE);
  91. // We only draw a white full-screen rectangle, frame is generated in shader
  92. BeginShaderMode(shader);
  93. DrawRectangle(0, 0, screenWidth, screenHeight, WHITE);
  94. EndShaderMode();
  95. DrawText(TextFormat("PRESS [A] to TOGGLE SHADER AUTOLOADING: %s",
  96. shaderAutoReloading? "AUTO" : "MANUAL"), 10, 10, 10, shaderAutoReloading? RED : BLACK);
  97. if (!shaderAutoReloading) DrawText("MOUSE CLICK to SHADER RE-LOADING", 10, 30, 10, BLACK);
  98. DrawText(TextFormat("Shader last modification: %s", asctime(localtime(&fragShaderFileModTime))), 10, 430, 10, BLACK);
  99. EndDrawing();
  100. //----------------------------------------------------------------------------------
  101. }
  102. // De-Initialization
  103. //--------------------------------------------------------------------------------------
  104. UnloadShader(shader); // Unload shader
  105. CloseWindow(); // Close window and OpenGL context
  106. //--------------------------------------------------------------------------------------
  107. return 0;
  108. }