mirror of
https://github.com/glfw/glfw.git
synced 2024-11-14 02:31:46 +00:00
d7e30b1c74
This removes all dependencies from the GLFW test programs on the Vulkan SDK. It also removes support for linking the GLFW shared library (dynamic library, DLL) against the Vulkan loader static library.
462 lines
12 KiB
C
462 lines
12 KiB
C
/*****************************************************************************
|
|
* 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>
|
|
#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);
|
|
}
|
|
|