173 lines
5.3 KiB
C
173 lines
5.3 KiB
C
// main.c
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "gl_utils.h"
|
|
#include "sand_sim.h"
|
|
#define GRID_W 2048
|
|
#define GRID_H 2048
|
|
static int g_fbWidth = 800;
|
|
static int g_fbHeight = 800;
|
|
static double g_cursorX = 0.0;
|
|
static double g_cursorY = 0.0;
|
|
SandSim sim;
|
|
|
|
static void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) {
|
|
(void)window;
|
|
g_cursorX = xpos;
|
|
g_cursorY = ypos;
|
|
}
|
|
|
|
static void render_sand(SandSim* sim,
|
|
GLuint program,
|
|
GLuint vao,
|
|
int fbW,
|
|
int fbH,
|
|
float brushX,
|
|
float brushY,
|
|
float brushRadius) {
|
|
glUseProgram(program);
|
|
|
|
GLint uResLoc = glGetUniformLocation(program, "u_resolution");
|
|
GLint uGridLoc = glGetUniformLocation(program, "u_gridSize");
|
|
GLint uStateLoc = glGetUniformLocation(program, "u_state");
|
|
GLint uBrushPosLoc = glGetUniformLocation(program, "u_brushPos");
|
|
GLint uBrushRadLoc = glGetUniformLocation(program, "u_brushRadius");
|
|
GLint uShowBrushLoc = glGetUniformLocation(program, "u_showBrush");
|
|
|
|
if (uResLoc >= 0) {
|
|
glUniform2f(uResLoc, (float)fbW, (float)fbH);
|
|
}
|
|
if (uGridLoc >= 0) {
|
|
glUniform2i(uGridLoc, sim->gridW, sim->gridH);
|
|
}
|
|
if (uStateLoc >= 0) {
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, sim->tex_curr);
|
|
glUniform1i(uStateLoc, 0);
|
|
}
|
|
|
|
if (uBrushPosLoc >= 0) {
|
|
glUniform2f(uBrushPosLoc, brushX, brushY);
|
|
}
|
|
if (uBrushRadLoc >= 0) {
|
|
glUniform1f(uBrushRadLoc, brushRadius);
|
|
}
|
|
if (uShowBrushLoc >= 0) {
|
|
glUniform1i(uShowBrushLoc, 1); // always show for now
|
|
}
|
|
|
|
glBindVertexArray(vao);
|
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
|
}
|
|
|
|
int main(void) {
|
|
GLFWwindow* window = init_glfw_glad("Falling Sand - Fullscreen Quad", g_fbWidth, g_fbHeight);
|
|
if (!window) {
|
|
return EXIT_FAILURE;
|
|
}
|
|
glfwSetCursorPosCallback(window, cursor_pos_callback);
|
|
glfwGetFramebufferSize(window, &g_fbWidth, &g_fbHeight);
|
|
glViewport(0, 0, g_fbWidth, g_fbHeight);
|
|
printf("Renderer: %s\n", (const char*)glGetString(GL_RENDERER));
|
|
printf("OpenGL: %s\n", (const char*)glGetString(GL_VERSION));
|
|
printf("GLSL: %s\n", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
|
|
|
|
// --- Create fullscreen triangle geometry (VAO + VBO) ---
|
|
float vertices[] = {
|
|
// x, y
|
|
-1.0f, -1.0f,
|
|
3.0f, -1.0f,
|
|
-1.0f, 3.0f};
|
|
|
|
GLuint vao = 0, vbo = 0;
|
|
glGenVertexArrays(1, &vao);
|
|
glGenBuffers(1, &vbo);
|
|
|
|
glBindVertexArray(vao);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
|
|
|
// layout(location = 0) in vec2 aPos;
|
|
glEnableVertexAttribArray(0);
|
|
glVertexAttribPointer(
|
|
0,
|
|
2,
|
|
GL_FLOAT,
|
|
GL_FALSE,
|
|
2 * sizeof(float),
|
|
(void*)0);
|
|
|
|
glBindVertexArray(0);
|
|
if (!sand_init(&sim, GRID_W, GRID_H, "shaders/sand_step.comp")) {
|
|
fprintf(stderr, "Failed to initialize sand sim\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
// --- Create shader program ---
|
|
GLuint program = create_program_from_files(
|
|
"shaders/fullscreen.vert",
|
|
"shaders/sand_display.frag");
|
|
|
|
glUseProgram(program);
|
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
double sim_dt = 1.0 / 360.0;
|
|
double currentTime = glfwGetTime();
|
|
double accumulator = 0.0;
|
|
float brushX = 0.0f;
|
|
float brushY = 0.0f;
|
|
|
|
// --- Main loop ---
|
|
while (!glfwWindowShouldClose(window)) {
|
|
double newTime = glfwGetTime();
|
|
double frameTime = newTime - currentTime;
|
|
currentTime = newTime;
|
|
if (frameTime > 0.25) frameTime = 0.25;
|
|
accumulator += frameTime;
|
|
|
|
while (accumulator >= sim_dt) {
|
|
sand_step_gpu(&sim); // one discrete CA step on the GPU
|
|
sand_relax_gpu(&sim);
|
|
accumulator -= sim_dt;
|
|
}
|
|
int paintMode = 0;
|
|
glfwPollEvents();
|
|
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) {
|
|
paintMode = 1;
|
|
} else if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) {
|
|
paintMode = -1;
|
|
}
|
|
// Re-query framebuffer size each frame (cheap and simple)
|
|
int fbw, fbh;
|
|
glfwGetFramebufferSize(window, &fbw, &fbh);
|
|
if (fbw != g_fbWidth || fbh != g_fbHeight) {
|
|
g_fbWidth = fbw;
|
|
g_fbHeight = fbh;
|
|
glViewport(0, 0, g_fbWidth, g_fbHeight);
|
|
}
|
|
if (g_fbWidth > 0 && g_fbHeight > 0) {
|
|
float uvx = (float)g_cursorX / (float)g_fbWidth;
|
|
float uvy = (float)g_cursorY / (float)g_fbHeight;
|
|
brushX = uvx * (float)sim.gridW;
|
|
brushY = uvy * (float)sim.gridH;
|
|
}
|
|
float brushRadius = 60.0f;
|
|
sand_paint_gpu(&sim, brushX, brushY, brushRadius, paintMode);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
render_sand(&sim, program, vao, g_fbWidth, g_fbHeight, brushX, brushY, brushRadius);
|
|
|
|
glfwSwapBuffers(window);
|
|
}
|
|
|
|
// --- Cleanup ---
|
|
glDeleteProgram(program);
|
|
glDeleteBuffers(1, &vbo);
|
|
glDeleteVertexArrays(1, &vao);
|
|
|
|
glfwDestroyWindow(window);
|
|
glfwTerminate();
|
|
return EXIT_SUCCESS;
|
|
}
|