wave.c 12 KB

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