Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

176 wiersze
7.2 KiB

  1. /*******************************************************************************************
  2. *
  3. * raylib [rlgl] example - compute shader - Conway's Game of Life
  4. *
  5. * NOTE: This example requires raylib OpenGL 4.3 versions for compute shaders support,
  6. * shaders used in this example are #version 430 (OpenGL 4.3)
  7. *
  8. * Example complexity rating: [] 4/4
  9. *
  10. * Example originally created with raylib 4.0, last time updated with raylib 2.5
  11. *
  12. * Example contributed by Teddy Astie (@tsnake41) and reviewed by Ramon Santamaria (@raysan5)
  13. *
  14. * Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
  15. * BSD-like license that allows static linking with closed source software
  16. *
  17. * Copyright (c) 2021-2025 Teddy Astie (@tsnake41)
  18. *
  19. ********************************************************************************************/
  20. #include "raylib.h"
  21. #include "rlgl.h"
  22. #include <stdlib.h>
  23. // IMPORTANT: This must match gol*.glsl GOL_WIDTH constant.
  24. // This must be a multiple of 16 (check golLogic compute dispatch).
  25. #define GOL_WIDTH 768
  26. // Maximum amount of queued draw commands (squares draw from mouse down events).
  27. #define MAX_BUFFERED_TRANSFERTS 48
  28. // Game Of Life Update Command
  29. typedef struct GolUpdateCmd {
  30. unsigned int x; // x coordinate of the gol command
  31. unsigned int y; // y coordinate of the gol command
  32. unsigned int w; // width of the filled zone
  33. unsigned int enabled; // whether to enable or disable zone
  34. } GolUpdateCmd;
  35. // Game Of Life Update Commands SSBO
  36. typedef struct GolUpdateSSBO {
  37. unsigned int count;
  38. GolUpdateCmd commands[MAX_BUFFERED_TRANSFERTS];
  39. } GolUpdateSSBO;
  40. //------------------------------------------------------------------------------------
  41. // Program main entry point
  42. //------------------------------------------------------------------------------------
  43. int main(void)
  44. {
  45. // Initialization
  46. //--------------------------------------------------------------------------------------
  47. InitWindow(GOL_WIDTH, GOL_WIDTH, "raylib [rlgl] example - compute shader - game of life");
  48. const Vector2 resolution = { GOL_WIDTH, GOL_WIDTH };
  49. unsigned int brushSize = 8;
  50. // Game of Life logic compute shader
  51. char *golLogicCode = LoadFileText("resources/shaders/glsl430/gol.glsl");
  52. unsigned int golLogicShader = rlCompileShader(golLogicCode, RL_COMPUTE_SHADER);
  53. unsigned int golLogicProgram = rlLoadComputeShaderProgram(golLogicShader);
  54. UnloadFileText(golLogicCode);
  55. // Game of Life logic render shader
  56. Shader golRenderShader = LoadShader(NULL, "resources/shaders/glsl430/gol_render.glsl");
  57. int resUniformLoc = GetShaderLocation(golRenderShader, "resolution");
  58. // Game of Life transfert shader (CPU<->GPU download and upload)
  59. char *golTransfertCode = LoadFileText("resources/shaders/glsl430/gol_transfert.glsl");
  60. unsigned int golTransfertShader = rlCompileShader(golTransfertCode, RL_COMPUTE_SHADER);
  61. unsigned int golTransfertProgram = rlLoadComputeShaderProgram(golTransfertShader);
  62. UnloadFileText(golTransfertCode);
  63. // Load shader storage buffer object (SSBO), id returned
  64. unsigned int ssboA = rlLoadShaderBuffer(GOL_WIDTH*GOL_WIDTH*sizeof(unsigned int), NULL, RL_DYNAMIC_COPY);
  65. unsigned int ssboB = rlLoadShaderBuffer(GOL_WIDTH*GOL_WIDTH*sizeof(unsigned int), NULL, RL_DYNAMIC_COPY);
  66. unsigned int ssboTransfert = rlLoadShaderBuffer(sizeof(GolUpdateSSBO), NULL, RL_DYNAMIC_COPY);
  67. GolUpdateSSBO transfertBuffer = { 0 };
  68. // Create a white texture of the size of the window to update
  69. // each pixel of the window using the fragment shader: golRenderShader
  70. Image whiteImage = GenImageColor(GOL_WIDTH, GOL_WIDTH, WHITE);
  71. Texture whiteTex = LoadTextureFromImage(whiteImage);
  72. UnloadImage(whiteImage);
  73. //--------------------------------------------------------------------------------------
  74. // Main game loop
  75. while (!WindowShouldClose())
  76. {
  77. // Update
  78. //----------------------------------------------------------------------------------
  79. brushSize += (int)GetMouseWheelMove();
  80. if ((IsMouseButtonDown(MOUSE_BUTTON_LEFT) || IsMouseButtonDown(MOUSE_BUTTON_RIGHT))
  81. && (transfertBuffer.count < MAX_BUFFERED_TRANSFERTS))
  82. {
  83. // Buffer a new command
  84. transfertBuffer.commands[transfertBuffer.count].x = GetMouseX() - brushSize/2;
  85. transfertBuffer.commands[transfertBuffer.count].y = GetMouseY() - brushSize/2;
  86. transfertBuffer.commands[transfertBuffer.count].w = brushSize;
  87. transfertBuffer.commands[transfertBuffer.count].enabled = IsMouseButtonDown(MOUSE_BUTTON_LEFT);
  88. transfertBuffer.count++;
  89. }
  90. else if (transfertBuffer.count > 0) // Process transfert buffer
  91. {
  92. // Send SSBO buffer to GPU
  93. rlUpdateShaderBuffer(ssboTransfert, &transfertBuffer, sizeof(GolUpdateSSBO), 0);
  94. // Process SSBO commands on GPU
  95. rlEnableShader(golTransfertProgram);
  96. rlBindShaderBuffer(ssboA, 1);
  97. rlBindShaderBuffer(ssboTransfert, 3);
  98. rlComputeShaderDispatch(transfertBuffer.count, 1, 1); // Each GPU unit will process a command!
  99. rlDisableShader();
  100. transfertBuffer.count = 0;
  101. }
  102. else
  103. {
  104. // Process game of life logic
  105. rlEnableShader(golLogicProgram);
  106. rlBindShaderBuffer(ssboA, 1);
  107. rlBindShaderBuffer(ssboB, 2);
  108. rlComputeShaderDispatch(GOL_WIDTH/16, GOL_WIDTH/16, 1);
  109. rlDisableShader();
  110. // ssboA <-> ssboB
  111. int temp = ssboA;
  112. ssboA = ssboB;
  113. ssboB = temp;
  114. }
  115. rlBindShaderBuffer(ssboA, 1);
  116. SetShaderValue(golRenderShader, resUniformLoc, &resolution, SHADER_UNIFORM_VEC2);
  117. //----------------------------------------------------------------------------------
  118. // Draw
  119. //----------------------------------------------------------------------------------
  120. BeginDrawing();
  121. ClearBackground(BLANK);
  122. BeginShaderMode(golRenderShader);
  123. DrawTexture(whiteTex, 0, 0, WHITE);
  124. EndShaderMode();
  125. DrawRectangleLines(GetMouseX() - brushSize/2, GetMouseY() - brushSize/2, brushSize, brushSize, RED);
  126. DrawText("Use Mouse wheel to increase/decrease brush size", 10, 10, 20, WHITE);
  127. DrawFPS(GetScreenWidth() - 100, 10);
  128. EndDrawing();
  129. //----------------------------------------------------------------------------------
  130. }
  131. // De-Initialization
  132. //--------------------------------------------------------------------------------------
  133. // Unload shader buffers objects.
  134. rlUnloadShaderBuffer(ssboA);
  135. rlUnloadShaderBuffer(ssboB);
  136. rlUnloadShaderBuffer(ssboTransfert);
  137. // Unload compute shader programs
  138. rlUnloadShaderProgram(golTransfertProgram);
  139. rlUnloadShaderProgram(golLogicProgram);
  140. UnloadTexture(whiteTex); // Unload white texture
  141. UnloadShader(golRenderShader); // Unload rendering fragment shader
  142. CloseWindow(); // Close window and OpenGL context
  143. //--------------------------------------------------------------------------------------
  144. return 0;
  145. }