123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- /*****************************************************************************
- * Wave Simulation in OpenGL
- * (C) 2002 Jakob Thomsen
- * http://home.in.tum.de/~thomsen
- * Modified for GLFW by Sylvain Hellegouarch - sh@programmationworld.com
- * Modified for variable frame rate by Marcus Geelnard
- * 2003-Jan-31: Minor cleanups and speedups / MG
- * 2010-10-24: Formatting and cleanup - Camilla Löwy
- *****************************************************************************/
- #if defined(_MSC_VER)
- // Make MS math.h define M_PI
- #define _USE_MATH_DEFINES
- #endif
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include <glad/gl.h>
- #define GLFW_INCLUDE_NONE
- #include <GLFW/glfw3.h>
- #include <linmath.h>
- // Maximum delta T to allow for differential calculations
- #define MAX_DELTA_T 0.01
- // Animation speed (10.0 looks good)
- #define ANIMATION_SPEED 10.0
- GLfloat alpha = 210.f, beta = -70.f;
- GLfloat zoom = 2.f;
- double cursorX;
- double cursorY;
- struct Vertex
- {
- GLfloat x, y, z;
- GLfloat r, g, b;
- };
- #define GRIDW 50
- #define GRIDH 50
- #define VERTEXNUM (GRIDW*GRIDH)
- #define QUADW (GRIDW - 1)
- #define QUADH (GRIDH - 1)
- #define QUADNUM (QUADW*QUADH)
- GLuint quad[4 * QUADNUM];
- struct Vertex vertex[VERTEXNUM];
- /* The grid will look like this:
- *
- * 3 4 5
- * *---*---*
- * | | |
- * | 0 | 1 |
- * | | |
- * *---*---*
- * 0 1 2
- */
- //========================================================================
- // Initialize grid geometry
- //========================================================================
- void init_vertices(void)
- {
- int x, y, p;
- // Place the vertices in a grid
- for (y = 0; y < GRIDH; y++)
- {
- for (x = 0; x < GRIDW; x++)
- {
- p = y * GRIDW + x;
- vertex[p].x = (GLfloat) (x - GRIDW / 2) / (GLfloat) (GRIDW / 2);
- vertex[p].y = (GLfloat) (y - GRIDH / 2) / (GLfloat) (GRIDH / 2);
- vertex[p].z = 0;
- if ((x % 4 < 2) ^ (y % 4 < 2))
- vertex[p].r = 0.0;
- else
- vertex[p].r = 1.0;
- vertex[p].g = (GLfloat) y / (GLfloat) GRIDH;
- vertex[p].b = 1.f - ((GLfloat) x / (GLfloat) GRIDW + (GLfloat) y / (GLfloat) GRIDH) / 2.f;
- }
- }
- for (y = 0; y < QUADH; y++)
- {
- for (x = 0; x < QUADW; x++)
- {
- p = 4 * (y * QUADW + x);
- quad[p + 0] = y * GRIDW + x; // Some point
- quad[p + 1] = y * GRIDW + x + 1; // Neighbor at the right side
- quad[p + 2] = (y + 1) * GRIDW + x + 1; // Upper right neighbor
- quad[p + 3] = (y + 1) * GRIDW + x; // Upper neighbor
- }
- }
- }
- double dt;
- double p[GRIDW][GRIDH];
- double vx[GRIDW][GRIDH], vy[GRIDW][GRIDH];
- double ax[GRIDW][GRIDH], ay[GRIDW][GRIDH];
- //========================================================================
- // Initialize grid
- //========================================================================
- void init_grid(void)
- {
- int x, y;
- double dx, dy, d;
- for (y = 0; y < GRIDH; y++)
- {
- for (x = 0; x < GRIDW; x++)
- {
- dx = (double) (x - GRIDW / 2);
- dy = (double) (y - GRIDH / 2);
- d = sqrt(dx * dx + dy * dy);
- if (d < 0.1 * (double) (GRIDW / 2))
- {
- d = d * 10.0;
- p[x][y] = -cos(d * (M_PI / (double)(GRIDW * 4))) * 100.0;
- }
- else
- p[x][y] = 0.0;
- vx[x][y] = 0.0;
- vy[x][y] = 0.0;
- }
- }
- }
- //========================================================================
- // Draw scene
- //========================================================================
- void draw_scene(GLFWwindow* window)
- {
- // Clear the color and depth buffers
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- // We don't want to modify the projection matrix
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- // Move back
- glTranslatef(0.0, 0.0, -zoom);
- // Rotate the view
- glRotatef(beta, 1.0, 0.0, 0.0);
- glRotatef(alpha, 0.0, 0.0, 1.0);
- glDrawElements(GL_QUADS, 4 * QUADNUM, GL_UNSIGNED_INT, quad);
- glfwSwapBuffers(window);
- }
- //========================================================================
- // Initialize Miscellaneous OpenGL state
- //========================================================================
- void init_opengl(void)
- {
- // Use Gouraud (smooth) shading
- glShadeModel(GL_SMOOTH);
- // Switch on the z-buffer
- glEnable(GL_DEPTH_TEST);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
- glVertexPointer(3, GL_FLOAT, sizeof(struct Vertex), vertex);
- glColorPointer(3, GL_FLOAT, sizeof(struct Vertex), &vertex[0].r); // Pointer to the first color
- glPointSize(2.0);
- // Background color is black
- glClearColor(0, 0, 0, 0);
- }
- //========================================================================
- // Modify the height of each vertex according to the pressure
- //========================================================================
- void adjust_grid(void)
- {
- int pos;
- int x, y;
- for (y = 0; y < GRIDH; y++)
- {
- for (x = 0; x < GRIDW; x++)
- {
- pos = y * GRIDW + x;
- vertex[pos].z = (float) (p[x][y] * (1.0 / 50.0));
- }
- }
- }
- //========================================================================
- // Calculate wave propagation
- //========================================================================
- void calc_grid(void)
- {
- int x, y, x2, y2;
- double time_step = dt * ANIMATION_SPEED;
- // Compute accelerations
- for (x = 0; x < GRIDW; x++)
- {
- x2 = (x + 1) % GRIDW;
- for(y = 0; y < GRIDH; y++)
- ax[x][y] = p[x][y] - p[x2][y];
- }
- for (y = 0; y < GRIDH; y++)
- {
- y2 = (y + 1) % GRIDH;
- for(x = 0; x < GRIDW; x++)
- ay[x][y] = p[x][y] - p[x][y2];
- }
- // Compute speeds
- for (x = 0; x < GRIDW; x++)
- {
- for (y = 0; y < GRIDH; y++)
- {
- vx[x][y] = vx[x][y] + ax[x][y] * time_step;
- vy[x][y] = vy[x][y] + ay[x][y] * time_step;
- }
- }
- // Compute pressure
- for (x = 1; x < GRIDW; x++)
- {
- x2 = x - 1;
- for (y = 1; y < GRIDH; y++)
- {
- y2 = y - 1;
- p[x][y] = p[x][y] + (vx[x2][y] - vx[x][y] + vy[x][y2] - vy[x][y]) * time_step;
- }
- }
- }
- //========================================================================
- // Print errors
- //========================================================================
- static void error_callback(int error, const char* description)
- {
- fprintf(stderr, "Error: %s\n", description);
- }
- //========================================================================
- // Handle key strokes
- //========================================================================
- void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
- {
- if (action != GLFW_PRESS)
- return;
- switch (key)
- {
- case GLFW_KEY_ESCAPE:
- glfwSetWindowShouldClose(window, GLFW_TRUE);
- break;
- case GLFW_KEY_SPACE:
- init_grid();
- break;
- case GLFW_KEY_LEFT:
- alpha += 5;
- break;
- case GLFW_KEY_RIGHT:
- alpha -= 5;
- break;
- case GLFW_KEY_UP:
- beta -= 5;
- break;
- case GLFW_KEY_DOWN:
- beta += 5;
- break;
- case GLFW_KEY_PAGE_UP:
- zoom -= 0.25f;
- if (zoom < 0.f)
- zoom = 0.f;
- break;
- case GLFW_KEY_PAGE_DOWN:
- zoom += 0.25f;
- break;
- default:
- break;
- }
- }
- //========================================================================
- // Callback function for mouse button events
- //========================================================================
- void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
- {
- if (button != GLFW_MOUSE_BUTTON_LEFT)
- return;
- if (action == GLFW_PRESS)
- {
- glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
- glfwGetCursorPos(window, &cursorX, &cursorY);
- }
- else
- glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
- }
- //========================================================================
- // Callback function for cursor motion events
- //========================================================================
- void cursor_position_callback(GLFWwindow* window, double x, double y)
- {
- if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED)
- {
- alpha += (GLfloat) (x - cursorX) / 10.f;
- beta += (GLfloat) (y - cursorY) / 10.f;
- cursorX = x;
- cursorY = y;
- }
- }
- //========================================================================
- // Callback function for scroll events
- //========================================================================
- void scroll_callback(GLFWwindow* window, double x, double y)
- {
- zoom += (float) y / 4.f;
- if (zoom < 0)
- zoom = 0;
- }
- //========================================================================
- // Callback function for framebuffer resize events
- //========================================================================
- void framebuffer_size_callback(GLFWwindow* window, int width, int height)
- {
- float ratio = 1.f;
- mat4x4 projection;
- if (height > 0)
- ratio = (float) width / (float) height;
- // Setup viewport
- glViewport(0, 0, width, height);
- // Change to the projection matrix and set our viewing volume
- glMatrixMode(GL_PROJECTION);
- mat4x4_perspective(projection,
- 60.f * (float) M_PI / 180.f,
- ratio,
- 1.f, 1024.f);
- glLoadMatrixf((const GLfloat*) projection);
- }
- //========================================================================
- // main
- //========================================================================
- int main(int argc, char* argv[])
- {
- GLFWwindow* window;
- double t, dt_total, t_old;
- int width, height;
- glfwSetErrorCallback(error_callback);
- if (!glfwInit())
- exit(EXIT_FAILURE);
- window = glfwCreateWindow(640, 480, "Wave Simulation", NULL, NULL);
- if (!window)
- {
- glfwTerminate();
- exit(EXIT_FAILURE);
- }
- glfwSetKeyCallback(window, key_callback);
- glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
- glfwSetMouseButtonCallback(window, mouse_button_callback);
- glfwSetCursorPosCallback(window, cursor_position_callback);
- glfwSetScrollCallback(window, scroll_callback);
- glfwMakeContextCurrent(window);
- gladLoadGL(glfwGetProcAddress);
- glfwSwapInterval(1);
- glfwGetFramebufferSize(window, &width, &height);
- framebuffer_size_callback(window, width, height);
- // Initialize OpenGL
- init_opengl();
- // Initialize simulation
- init_vertices();
- init_grid();
- adjust_grid();
- // Initialize timer
- t_old = glfwGetTime() - 0.01;
- while (!glfwWindowShouldClose(window))
- {
- t = glfwGetTime();
- dt_total = t - t_old;
- t_old = t;
- // Safety - iterate if dt_total is too large
- while (dt_total > 0.f)
- {
- // Select iteration time step
- dt = dt_total > MAX_DELTA_T ? MAX_DELTA_T : dt_total;
- dt_total -= dt;
- // Calculate wave propagation
- calc_grid();
- }
- // Compute height of each vertex
- adjust_grid();
- // Draw wave grid to OpenGL display
- draw_scene(window);
- glfwPollEvents();
- }
- glfwTerminate();
- exit(EXIT_SUCCESS);
- }
|