You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

262 rivejä
8.1 KiB

  1. /*******************************************************************************************
  2. *
  3. * raylib [shaders] example - Simple shader mask
  4. *
  5. * This example has been created using raylib 2.5 (www.raylib.com)
  6. * raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details)
  7. *
  8. * Example contributed by Chris Camacho (@codifies - http://bedroomcoders.co.uk/)
  9. * and reviewed by Ramon Santamaria (@raysan5)
  10. *
  11. * Copyright (c) 2019 Chris Camacho (@codifies) and Ramon Santamaria (@raysan5)
  12. *
  13. ********************************************************************************************
  14. *
  15. * The shader makes alpha holes in the forground to give the apearance of a top
  16. * down look at a spotlight casting a pool of light...
  17. *
  18. * The right hand side of the screen there is just enough light to see whats
  19. * going on without the spot light, great for a stealth type game where you
  20. * have to avoid the spotlights.
  21. *
  22. * The left hand side of the screen is in pitch dark except for where the spotlights are.
  23. *
  24. * Although this example doesn't scale like the letterbox example, you could integrate
  25. * the two techniques, but by scaling the actual colour of the render texture rather
  26. * than using alpha as a mask.
  27. *
  28. ********************************************************************************************/
  29. #include "raylib.h"
  30. #include "raymath.h"
  31. #include <stddef.h>
  32. #include <stdint.h>
  33. #if defined(PLATFORM_DESKTOP)
  34. #define GLSL_VERSION 330
  35. #else // PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB
  36. #define GLSL_VERSION 100
  37. #endif
  38. #define MAXSPOT 3 // NB must be the same as define in shader
  39. #define numStars 400
  40. // Spot data
  41. typedef struct {
  42. Vector2 pos;
  43. Vector2 vel;
  44. float inner;
  45. float radius;
  46. // Shader locations
  47. unsigned int posLoc;
  48. unsigned int innerLoc;
  49. unsigned int radiusLoc;
  50. } Spot;
  51. // Stars in the star field have a position and velocity
  52. typedef struct Star {
  53. Vector2 pos;
  54. Vector2 vel;
  55. } Star;
  56. void UpdateStar(Star *s);
  57. void ResetStar(Star *s);
  58. int main(void)
  59. {
  60. // Initialization
  61. //--------------------------------------------------------------------------------------
  62. const int screenWidth = 800;
  63. const int screenHeight = 450;
  64. InitWindow(screenWidth, screenHeight, "raylib - shader spotlight");
  65. HideCursor();
  66. Texture texRay = LoadTexture("resources/raysan.png");
  67. Star stars[numStars] = { 0 };
  68. for (int n = 0; n < numStars; n++) ResetStar(&stars[n]);
  69. // Progress all the stars on, so they don't all start in the centre
  70. for (int m = 0; m < screenWidth/2.0; m++)
  71. {
  72. for (int n = 0; n < numStars; n++) UpdateStar(&stars[n]);
  73. }
  74. int frameCounter = 0;
  75. // Use default vert shader
  76. Shader spotShader = LoadShader(0, TextFormat("resources/shaders/glsl%i/spotlight.fs", GLSL_VERSION));
  77. // Get the locations of spots in the shader
  78. Spot spots[MAXSPOT];
  79. /*
  80. unsigned int posLoc;
  81. unsigned int innerLoc;
  82. unsigned int radiusLoc;
  83. */
  84. for (int i = 0; i < MAXSPOT; i++)
  85. {
  86. char posName[32] = "spots[x].pos\0";
  87. char innerName[32] = "spots[x].inner\0";
  88. char radiusName[32] = "spots[x].radius\0";
  89. posName[6] = '0' + i;
  90. innerName[6] = '0' + i;
  91. radiusName[6] = '0' + i;
  92. spots[i].posLoc = GetShaderLocation(spotShader, posName);
  93. spots[i].innerLoc = GetShaderLocation(spotShader, innerName);
  94. spots[i].radiusLoc = GetShaderLocation(spotShader, radiusName);
  95. }
  96. // tell the shader how wide the screen is so we can have
  97. // a pitch black half and a dimly lit half.
  98. {
  99. unsigned int wLoc = GetShaderLocation(spotShader, "screenWidth");
  100. float sw = (float)GetScreenWidth();
  101. SetShaderValue(spotShader, wLoc, &sw, UNIFORM_FLOAT);
  102. }
  103. // randomise the locations and velocities of the spotlights
  104. // and initialise the shader locations
  105. for (int i = 0; i < MAXSPOT; i++)
  106. {
  107. spots[i].pos.x = GetRandomValue(64, screenWidth - 64);
  108. spots[i].pos.y = GetRandomValue(64, screenHeight - 64);
  109. spots[i].vel = (Vector2){ 0, 0 };
  110. while ((fabs(spots[i].vel.x) + fabs(spots[i].vel.y)) < 2)
  111. {
  112. spots[i].vel.x = GetRandomValue(-40, 40)/10.0;
  113. spots[i].vel.y = GetRandomValue(-40, 40)/10.0;
  114. }
  115. spots[i].inner = 28 * (i + 1);
  116. spots[i].radius = 48 * (i + 1);
  117. SetShaderValue(spotShader, spots[i].posLoc, &spots[i].pos.x, UNIFORM_VEC2);
  118. SetShaderValue(spotShader, spots[i].innerLoc, &spots[i].inner, UNIFORM_FLOAT);
  119. SetShaderValue(spotShader, spots[i].radiusLoc, &spots[i].radius, UNIFORM_FLOAT);
  120. }
  121. SetTargetFPS(60); // Set to run at 60 frames-per-second
  122. //--------------------------------------------------------------------------------------
  123. // Main game loop
  124. while (!WindowShouldClose()) // Detect window close button or ESC key
  125. {
  126. // Update
  127. //----------------------------------------------------------------------------------
  128. frameCounter++;
  129. // Move the stars, resetting them if the go offscreen
  130. for (int n = 0; n < numStars; n++) UpdateStar(&stars[n]);
  131. // Update the spots, send them to the shader
  132. for (int i = 0; i < MAXSPOT; i++)
  133. {
  134. if ( i == 0 ) {
  135. Vector2 mp = GetMousePosition();
  136. spots[i].pos.x = mp.x;
  137. spots[i].pos.y = screenHeight - mp.y;
  138. } else {
  139. spots[i].pos.x += spots[i].vel.x;
  140. spots[i].pos.y += spots[i].vel.y;
  141. if (spots[i].pos.x < 64) spots[i].vel.x = -spots[i].vel.x;
  142. if (spots[i].pos.x > screenWidth - 64) spots[i].vel.x = -spots[i].vel.x;
  143. if (spots[i].pos.y < 64) spots[i].vel.y = -spots[i].vel.y;
  144. if (spots[i].pos.y > screenHeight - 64) spots[i].vel.y = -spots[i].vel.y;
  145. }
  146. SetShaderValue(spotShader, spots[i].posLoc, &spots[i].pos.x, UNIFORM_VEC2);
  147. }
  148. // Draw
  149. //----------------------------------------------------------------------------------
  150. BeginDrawing();
  151. ClearBackground(DARKBLUE);
  152. // Draw stars and bobs
  153. for (int n = 0; n < numStars; n++)
  154. {
  155. // Single pixel is just too small these days!
  156. DrawRectangle(stars[n].pos.x, stars[n].pos.y, 2, 2, WHITE);
  157. }
  158. for (int i = 0; i < 16; i++)
  159. {
  160. DrawTexture(texRay,
  161. (screenWidth/2.0) + cos((frameCounter + i*8)/51.45f)*(screenWidth/2.2) - 32,
  162. (screenHeight/2.0) + sin((frameCounter + i*8)/17.87f)*(screenHeight/4.2),
  163. WHITE);
  164. }
  165. // Draw spot lights
  166. BeginShaderMode(spotShader);
  167. // instead of a blank rectangle you could render here
  168. // a render texture of the full screen used to do screen
  169. // scaling (slight adjustment to shader would be required
  170. // to actually pay attention to the colour!)
  171. DrawRectangle(0,0,screenWidth,screenHeight,WHITE);
  172. EndShaderMode();
  173. DrawFPS(10, 10);
  174. DrawText("Move the mouse!", 10, 30, 20, GREEN);
  175. DrawText("Pitch Black", screenWidth * .2, screenHeight / 2, 20, GREEN);
  176. DrawText("Dark", screenWidth * .66, screenHeight / 2, 20, GREEN);
  177. EndDrawing();
  178. //----------------------------------------------------------------------------------
  179. }
  180. // De-Initialization
  181. //--------------------------------------------------------------------------------------
  182. UnloadTexture(texRay);
  183. CloseWindow(); // Close window and OpenGL context
  184. //--------------------------------------------------------------------------------------
  185. return 0;
  186. }
  187. void ResetStar(Star *s)
  188. {
  189. s->pos = (Vector2){ GetScreenWidth()/2.0f, GetScreenHeight()/2.0f };
  190. do
  191. {
  192. s->vel.x = (float)GetRandomValue(-1000, 1000)/100.0f;
  193. s->vel.y = (float)GetRandomValue(-1000, 1000)/100.0f;
  194. } while (!(fabs(s->vel.x) + fabs(s->vel.y) > 1));
  195. s->pos = Vector2Add(s->pos, Vector2Multiply(s->vel, (Vector2){ 8, 8 }));
  196. }
  197. void UpdateStar(Star *s)
  198. {
  199. s->pos = Vector2Add(s->pos, s->vel);
  200. if (s->pos.x < 0 || s->pos.x > GetScreenWidth() ||
  201. s->pos.y < 0 || s->pos.y > GetScreenHeight())
  202. {
  203. ResetStar(s);
  204. }
  205. }