Platformer in OpenGL
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.

460 lines
12 KiB

5 years ago
  1. /*****************************************************************************
  2. * Wave Simulation in OpenGL
  3. * (C) 2002 Jakob Thomsen
  4. * http://home.in.tum.de/~thomsen
  5. * Modified for GLFW by Sylvain Hellegouarch - sh@programmationworld.com
  6. * Modified for variable frame rate by Marcus Geelnard
  7. * 2003-Jan-31: Minor cleanups and speedups / MG
  8. * 2010-10-24: Formatting and cleanup - Camilla Berglund
  9. *****************************************************************************/
  10. #if defined(_MSC_VER)
  11. // Make MS math.h define M_PI
  12. #define _USE_MATH_DEFINES
  13. #endif
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <math.h>
  17. #include <glad/glad.h>
  18. #include <GLFW/glfw3.h>
  19. #include <linmath.h>
  20. // Maximum delta T to allow for differential calculations
  21. #define MAX_DELTA_T 0.01
  22. // Animation speed (10.0 looks good)
  23. #define ANIMATION_SPEED 10.0
  24. GLfloat alpha = 210.f, beta = -70.f;
  25. GLfloat zoom = 2.f;
  26. double cursorX;
  27. double cursorY;
  28. struct Vertex
  29. {
  30. GLfloat x, y, z;
  31. GLfloat r, g, b;
  32. };
  33. #define GRIDW 50
  34. #define GRIDH 50
  35. #define VERTEXNUM (GRIDW*GRIDH)
  36. #define QUADW (GRIDW - 1)
  37. #define QUADH (GRIDH - 1)
  38. #define QUADNUM (QUADW*QUADH)
  39. GLuint quad[4 * QUADNUM];
  40. struct Vertex vertex[VERTEXNUM];
  41. /* The grid will look like this:
  42. *
  43. * 3 4 5
  44. * *---*---*
  45. * | | |
  46. * | 0 | 1 |
  47. * | | |
  48. * *---*---*
  49. * 0 1 2
  50. */
  51. //========================================================================
  52. // Initialize grid geometry
  53. //========================================================================
  54. void init_vertices(void)
  55. {
  56. int x, y, p;
  57. // Place the vertices in a grid
  58. for (y = 0; y < GRIDH; y++)
  59. {
  60. for (x = 0; x < GRIDW; x++)
  61. {
  62. p = y * GRIDW + x;
  63. vertex[p].x = (GLfloat) (x - GRIDW / 2) / (GLfloat) (GRIDW / 2);
  64. vertex[p].y = (GLfloat) (y - GRIDH / 2) / (GLfloat) (GRIDH / 2);
  65. vertex[p].z = 0;
  66. if ((x % 4 < 2) ^ (y % 4 < 2))
  67. vertex[p].r = 0.0;
  68. else
  69. vertex[p].r = 1.0;
  70. vertex[p].g = (GLfloat) y / (GLfloat) GRIDH;
  71. vertex[p].b = 1.f - ((GLfloat) x / (GLfloat) GRIDW + (GLfloat) y / (GLfloat) GRIDH) / 2.f;
  72. }
  73. }
  74. for (y = 0; y < QUADH; y++)
  75. {
  76. for (x = 0; x < QUADW; x++)
  77. {
  78. p = 4 * (y * QUADW + x);
  79. quad[p + 0] = y * GRIDW + x; // Some point
  80. quad[p + 1] = y * GRIDW + x + 1; // Neighbor at the right side
  81. quad[p + 2] = (y + 1) * GRIDW + x + 1; // Upper right neighbor
  82. quad[p + 3] = (y + 1) * GRIDW + x; // Upper neighbor
  83. }
  84. }
  85. }
  86. double dt;
  87. double p[GRIDW][GRIDH];
  88. double vx[GRIDW][GRIDH], vy[GRIDW][GRIDH];
  89. double ax[GRIDW][GRIDH], ay[GRIDW][GRIDH];
  90. //========================================================================
  91. // Initialize grid
  92. //========================================================================
  93. void init_grid(void)
  94. {
  95. int x, y;
  96. double dx, dy, d;
  97. for (y = 0; y < GRIDH; y++)
  98. {
  99. for (x = 0; x < GRIDW; x++)
  100. {
  101. dx = (double) (x - GRIDW / 2);
  102. dy = (double) (y - GRIDH / 2);
  103. d = sqrt(dx * dx + dy * dy);
  104. if (d < 0.1 * (double) (GRIDW / 2))
  105. {
  106. d = d * 10.0;
  107. p[x][y] = -cos(d * (M_PI / (double)(GRIDW * 4))) * 100.0;
  108. }
  109. else
  110. p[x][y] = 0.0;
  111. vx[x][y] = 0.0;
  112. vy[x][y] = 0.0;
  113. }
  114. }
  115. }
  116. //========================================================================
  117. // Draw scene
  118. //========================================================================
  119. void draw_scene(GLFWwindow* window)
  120. {
  121. // Clear the color and depth buffers
  122. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  123. // We don't want to modify the projection matrix
  124. glMatrixMode(GL_MODELVIEW);
  125. glLoadIdentity();
  126. // Move back
  127. glTranslatef(0.0, 0.0, -zoom);
  128. // Rotate the view
  129. glRotatef(beta, 1.0, 0.0, 0.0);
  130. glRotatef(alpha, 0.0, 0.0, 1.0);
  131. glDrawElements(GL_QUADS, 4 * QUADNUM, GL_UNSIGNED_INT, quad);
  132. glfwSwapBuffers(window);
  133. }
  134. //========================================================================
  135. // Initialize Miscellaneous OpenGL state
  136. //========================================================================
  137. void init_opengl(void)
  138. {
  139. // Use Gouraud (smooth) shading
  140. glShadeModel(GL_SMOOTH);
  141. // Switch on the z-buffer
  142. glEnable(GL_DEPTH_TEST);
  143. glEnableClientState(GL_VERTEX_ARRAY);
  144. glEnableClientState(GL_COLOR_ARRAY);
  145. glVertexPointer(3, GL_FLOAT, sizeof(struct Vertex), vertex);
  146. glColorPointer(3, GL_FLOAT, sizeof(struct Vertex), &vertex[0].r); // Pointer to the first color
  147. glPointSize(2.0);
  148. // Background color is black
  149. glClearColor(0, 0, 0, 0);
  150. }
  151. //========================================================================
  152. // Modify the height of each vertex according to the pressure
  153. //========================================================================
  154. void adjust_grid(void)
  155. {
  156. int pos;
  157. int x, y;
  158. for (y = 0; y < GRIDH; y++)
  159. {
  160. for (x = 0; x < GRIDW; x++)
  161. {
  162. pos = y * GRIDW + x;
  163. vertex[pos].z = (float) (p[x][y] * (1.0 / 50.0));
  164. }
  165. }
  166. }
  167. //========================================================================
  168. // Calculate wave propagation
  169. //========================================================================
  170. void calc_grid(void)
  171. {
  172. int x, y, x2, y2;
  173. double time_step = dt * ANIMATION_SPEED;
  174. // Compute accelerations
  175. for (x = 0; x < GRIDW; x++)
  176. {
  177. x2 = (x + 1) % GRIDW;
  178. for(y = 0; y < GRIDH; y++)
  179. ax[x][y] = p[x][y] - p[x2][y];
  180. }
  181. for (y = 0; y < GRIDH; y++)
  182. {
  183. y2 = (y + 1) % GRIDH;
  184. for(x = 0; x < GRIDW; x++)
  185. ay[x][y] = p[x][y] - p[x][y2];
  186. }
  187. // Compute speeds
  188. for (x = 0; x < GRIDW; x++)
  189. {
  190. for (y = 0; y < GRIDH; y++)
  191. {
  192. vx[x][y] = vx[x][y] + ax[x][y] * time_step;
  193. vy[x][y] = vy[x][y] + ay[x][y] * time_step;
  194. }
  195. }
  196. // Compute pressure
  197. for (x = 1; x < GRIDW; x++)
  198. {
  199. x2 = x - 1;
  200. for (y = 1; y < GRIDH; y++)
  201. {
  202. y2 = y - 1;
  203. p[x][y] = p[x][y] + (vx[x2][y] - vx[x][y] + vy[x][y2] - vy[x][y]) * time_step;
  204. }
  205. }
  206. }
  207. //========================================================================
  208. // Print errors
  209. //========================================================================
  210. static void error_callback(int error, const char* description)
  211. {
  212. fprintf(stderr, "Error: %s\n", description);
  213. }
  214. //========================================================================
  215. // Handle key strokes
  216. //========================================================================
  217. void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
  218. {
  219. if (action != GLFW_PRESS)
  220. return;
  221. switch (key)
  222. {
  223. case GLFW_KEY_ESCAPE:
  224. glfwSetWindowShouldClose(window, GLFW_TRUE);
  225. break;
  226. case GLFW_KEY_SPACE:
  227. init_grid();
  228. break;
  229. case GLFW_KEY_LEFT:
  230. alpha += 5;
  231. break;
  232. case GLFW_KEY_RIGHT:
  233. alpha -= 5;
  234. break;
  235. case GLFW_KEY_UP:
  236. beta -= 5;
  237. break;
  238. case GLFW_KEY_DOWN:
  239. beta += 5;
  240. break;
  241. case GLFW_KEY_PAGE_UP:
  242. zoom -= 0.25f;
  243. if (zoom < 0.f)
  244. zoom = 0.f;
  245. break;
  246. case GLFW_KEY_PAGE_DOWN:
  247. zoom += 0.25f;
  248. break;
  249. default:
  250. break;
  251. }
  252. }
  253. //========================================================================
  254. // Callback function for mouse button events
  255. //========================================================================
  256. void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
  257. {
  258. if (button != GLFW_MOUSE_BUTTON_LEFT)
  259. return;
  260. if (action == GLFW_PRESS)
  261. {
  262. glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
  263. glfwGetCursorPos(window, &cursorX, &cursorY);
  264. }
  265. else
  266. glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
  267. }
  268. //========================================================================
  269. // Callback function for cursor motion events
  270. //========================================================================
  271. void cursor_position_callback(GLFWwindow* window, double x, double y)
  272. {
  273. if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
  274. {
  275. alpha += (GLfloat) (x - cursorX) / 10.f;
  276. beta += (GLfloat) (y - cursorY) / 10.f;
  277. cursorX = x;
  278. cursorY = y;
  279. }
  280. }
  281. //========================================================================
  282. // Callback function for scroll events
  283. //========================================================================
  284. void scroll_callback(GLFWwindow* window, double x, double y)
  285. {
  286. zoom += (float) y / 4.f;
  287. if (zoom < 0)
  288. zoom = 0;
  289. }
  290. //========================================================================
  291. // Callback function for framebuffer resize events
  292. //========================================================================
  293. void framebuffer_size_callback(GLFWwindow* window, int width, int height)
  294. {
  295. float ratio = 1.f;
  296. mat4x4 projection;
  297. if (height > 0)
  298. ratio = (float) width / (float) height;
  299. // Setup viewport
  300. glViewport(0, 0, width, height);
  301. // Change to the projection matrix and set our viewing volume
  302. glMatrixMode(GL_PROJECTION);
  303. mat4x4_perspective(projection,
  304. 60.f * (float) M_PI / 180.f,
  305. ratio,
  306. 1.f, 1024.f);
  307. glLoadMatrixf((const GLfloat*) projection);
  308. }
  309. //========================================================================
  310. // main
  311. //========================================================================
  312. int main(int argc, char* argv[])
  313. {
  314. GLFWwindow* window;
  315. double t, dt_total, t_old;
  316. int width, height;
  317. glfwSetErrorCallback(error_callback);
  318. if (!glfwInit())
  319. exit(EXIT_FAILURE);
  320. window = glfwCreateWindow(640, 480, "Wave Simulation", NULL, NULL);
  321. if (!window)
  322. {
  323. glfwTerminate();
  324. exit(EXIT_FAILURE);
  325. }
  326. glfwSetKeyCallback(window, key_callback);
  327. glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
  328. glfwSetMouseButtonCallback(window, mouse_button_callback);
  329. glfwSetCursorPosCallback(window, cursor_position_callback);
  330. glfwSetScrollCallback(window, scroll_callback);
  331. glfwMakeContextCurrent(window);
  332. gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
  333. glfwSwapInterval(1);
  334. glfwGetFramebufferSize(window, &width, &height);
  335. framebuffer_size_callback(window, width, height);
  336. // Initialize OpenGL
  337. init_opengl();
  338. // Initialize simulation
  339. init_vertices();
  340. init_grid();
  341. adjust_grid();
  342. // Initialize timer
  343. t_old = glfwGetTime() - 0.01;
  344. while (!glfwWindowShouldClose(window))
  345. {
  346. t = glfwGetTime();
  347. dt_total = t - t_old;
  348. t_old = t;
  349. // Safety - iterate if dt_total is too large
  350. while (dt_total > 0.f)
  351. {
  352. // Select iteration time step
  353. dt = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total;
  354. dt_total -= dt;
  355. // Calculate wave propagation
  356. calc_grid();
  357. }
  358. // Compute height of each vertex
  359. adjust_grid();
  360. // Draw wave grid to OpenGL display
  361. draw_scene(window);
  362. glfwPollEvents();
  363. }
  364. exit(EXIT_SUCCESS);
  365. }