Feature: Can now render to images in ./frames

;
This commit is contained in:
Afonso Clerigo Mendes de Sousa 2025-11-14 18:20:05 +00:00
parent ad2591b33b
commit 7716a115c8
34 changed files with 2087 additions and 133 deletions

BIN
RASTER

Binary file not shown.

BIN
frames/frame_0000.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

BIN
frames/frame_0001.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0002.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0003.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0004.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0005.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0006.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0007.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0008.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0009.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0010.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0011.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0012.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0013.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0014.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0015.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0016.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0017.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0018.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0019.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0020.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0021.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0022.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0023.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
frames/frame_0024.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

BIN
frames/frame_0025.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

BIN
frames/frame_0026.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

BIN
frames/frame_0027.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

BIN
frames/frame_0028.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

1724
include/stb_image_write.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,7 @@
#version 410 core #version 410 core
layout(location = 0) in vec3 aPos; // Vertex position layout(location = 0) in vec3 aPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main() { void main() {
gl_Position = projection * view * model * vec4(aPos, 1.0); gl_Position = vec4(aPos, 1.0);
} }

View File

@ -1,44 +1,101 @@
#include <fstream>
#include <iostream> #include <iostream>
#include <sstream>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <string>
#include <vector>
// glad and GLFW // OpenGL
#include <glad/glad.h> #include <glad/glad.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
// glm math // GLM
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
// HPP files // Custom headers
#include "shader.h" #include "shader.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#define VERTEX_FILE "./shaders/vertex.glsl" #define VERTEX_FILE "./shaders/vertex.glsl"
#define FRAGMENT_FILE "./shaders/fragment.glsl" #define FRAGMENT_FILE "./shaders/fragment.glsl"
#define COMPUTE_FILE "./shaders/compute.glsl"
const float SCR_WIDTH = 1200.0f; const int WIDTH = 3840;
const float SCR_HEIGHT = 1200.0f; const int HEIGHT = 2160;
const float DURATION = 120.0f; // 2 minutes
const int FPS = 30;
const std::string OUTPUT_FOLDER = "./frames";
int main(void) { // ------------------ Offscreen Frame Renderer ------------------
void renderFrame(GLuint shaderProgram, GLuint VAO, GLuint resLoc, GLuint timeLoc, GLuint scaleLoc, GLuint mouseLoc, float time, const std::string &filename) {
static GLuint fbo = 0;
static GLuint texture = 0;
glUniform1f(scaleLoc, 1.0f); // or whatever scale you want
glUniform2f(mouseLoc, 0.0f, 0.0f);
// First frame setup
if (fbo == 0) {
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WIDTH, HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cerr << "Framebuffer not complete!\n";
exit(-1);
}
}
// Bind FBO
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glViewport(0, 0, WIDTH, HEIGHT);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
// Render procedural quad
glUseProgram(shaderProgram);
glUniform2f(resLoc, float(WIDTH), float(HEIGHT));
glUniform1f(timeLoc, time);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// Read pixels
std::vector<unsigned char> pixels(WIDTH * HEIGHT * 3);
glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels.data());
// Flip vertically
for (int y = 0; y < HEIGHT / 2; ++y) {
int opp = HEIGHT - y - 1;
for (int x = 0; x < WIDTH * 3; ++x)
std::swap(pixels[y * WIDTH * 3 + x], pixels[opp * WIDTH * 3 + x]);
}
stbi_write_png(filename.c_str(), WIDTH, HEIGHT, 3, pixels.data(), WIDTH * 3);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
// ------------------ Main ------------------
int main() {
// Initialize GLFW // Initialize GLFW
if (!glfwInit()) if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW\n";
return -1; return -1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // REQUIRED on macOS glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_SAMPLES, 8); // 8x MSAA glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // hidden
GLFWwindow *window = glfwCreateWindow((int)SCR_WIDTH, (int)SCR_HEIGHT, "RASTER", nullptr, nullptr); GLFWwindow *window = glfwCreateWindow(1, 1, "", nullptr, nullptr);
if (!window) {
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
@ -46,20 +103,10 @@ int main(void) {
return -1; return -1;
} }
glViewport(0, 0, (int)SCR_WIDTH, (int)SCR_HEIGHT);
// DEBUG
std::cout << "OpenGL Version: " << glGetString(GL_VERSION) << std::endl; std::cout << "OpenGL Version: " << glGetString(GL_VERSION) << std::endl;
// ERROR: macOS does not support compute shaders in OpenGL < 4.3. // ------------------ VAO + VBO ------------------
// GLuint computeProgram = createComputeProgram(COMPUTE_FILE); float vertices[] = {-1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f};
// ----- Vertex Data -----
// Cube
// Positions
float vertices[] = {// positions
-1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f};
unsigned int indices[] = {0, 1, 2, 2, 3, 0}; unsigned int indices[] = {0, 1, 2, 2, 3, 0};
GLuint VAO, VBO, EBO; GLuint VAO, VBO, EBO;
@ -68,124 +115,50 @@ int main(void) {
glGenBuffers(1, &EBO); glGenBuffers(1, &EBO);
glBindVertexArray(VAO); glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// position - VERTEX SHADER
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
// color - FRAGMENT SHADER // ------------------ Shader ------------------
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// glBindVertexArray(0);
// Load shaders
GLuint shaderProgram = createShaderProgram(VERTEX_FILE, FRAGMENT_FILE); GLuint shaderProgram = createShaderProgram(VERTEX_FILE, FRAGMENT_FILE);
// Check if shader program was created successfully
if (shaderProgram == 0) { if (shaderProgram == 0) {
std::cerr << "Failed to create shader programs.\n"; std::cerr << "Failed to create shader.\n";
return -1; return -1;
} }
// Caulculate model, view, projection matrices GLuint resLoc = glGetUniformLocation(shaderProgram, "u_resolution");
glm::mat4 model = glm::mat4(1.0f); GLuint timeLoc = glGetUniformLocation(shaderProgram, "u_time");
glm::mat4 view = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -1.0f));
glm::mat4 projection = glm::perspective(glm::radians(45.0f), (SCR_WIDTH / SCR_HEIGHT) * 2, 0.1f, 100.0f);
GLuint modelLoc = (unsigned int)glGetUniformLocation(shaderProgram, "model"); GLuint scaleLoc = glGetUniformLocation(shaderProgram, "u_scale");
GLuint viewLoc = (unsigned int)glGetUniformLocation(shaderProgram, "view"); GLuint mouseLoc = glGetUniformLocation(shaderProgram, "u_mouse");
GLuint projLoc = (unsigned int)glGetUniformLocation(shaderProgram, "projection");
glUseProgram(shaderProgram); // In renderFrame(), add:
glUniformMatrix4fv((int)modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv((int)viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv((int)projLoc, 1, GL_FALSE, glm::value_ptr(projection));
GLint resLoc = glGetUniformLocation(shaderProgram, "u_resolution"); // ------------------ Render Loop ------------------
glUniform2f(resLoc, SCR_WIDTH, SCR_HEIGHT); // hardcode for now int totalFrames = int(DURATION * FPS);
for (int i = 0; i < totalFrames; ++i) {
float t = i / float(FPS);
char filename[256];
sprintf(filename, "%s/frame_%04d.png", OUTPUT_FOLDER.c_str(), i);
GLint timeLoc = glGetUniformLocation(shaderProgram, "u_time"); renderFrame(shaderProgram, VAO, resLoc, timeLoc, scaleLoc, mouseLoc, t, filename);
GLint scaleLoc = glGetUniformLocation(shaderProgram, "u_scale"); std::cout << "\rRendered frame " << i + 1 << "/" << totalFrames << std::flush;
GLint mouseLoc = glGetUniformLocation(shaderProgram, "u_mouse");
glEnable(GL_MULTISAMPLE);
float scale = 1.0f;
int frameCount = 0;
float mousePos[2] = {0.0f, 0.0f};
// FPS tracking
double lastTime = glfwGetTime(); // when we last printed FPS
double fps = 0.0;
// Render loop
while (!glfwWindowShouldClose(window)) {
float timeValue = (float)glfwGetTime();
double xpos, ypos;
// Get mouse positions
glfwGetCursorPos(window, &xpos, &ypos);
mousePos[0] = (float)xpos;
mousePos[1] = (float)(SCR_HEIGHT - ypos); // Invert y-axis for OpenGL coordinates
// Input
glfwPollEvents();
// Scroll to zoom in/out
if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) {
scale += 0.01f;
if (scale > 10.0f)
scale = 10.0f; // Max zoom
}
if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) {
scale -= 0.01f;
if (scale < 0.1f)
scale = 0.1f; // Min zoom
}
// --- FPS Counter ---
double currentTime = glfwGetTime();
double delta = currentTime - lastTime;
if (delta >= 1.0) { // print every ~1 second
fps = double(frameCount) / delta;
std::cout << "FPS: " << fps << " Time: " << timeValue << " Scale: " << scale << " Mouse: (" << mousePos[0] << ", " << mousePos[1] << ")" << std::endl;
frameCount = 0;
lastTime = currentTime;
}
glUniform1f(timeLoc, timeValue);
glUniform1f(scaleLoc, scale);
glUniform2f(mouseLoc, mousePos[0], mousePos[1]);
frameCount++;
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glUseProgram(shaderProgram);
glfwSwapBuffers(window);
} }
std::cout << "\nDone! Stitch frames into video with ffmpeg:\n";
std::cout << "ffmpeg -framerate 30 -i ./frames/frame_%04d.png -c:v libx264 -pix_fmt yuv420p noise_video.mp4\n";
// ------------------ Cleanup ------------------
glDeleteVertexArrays(1, &VAO); glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO); glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO); glDeleteBuffers(1, &EBO);
glDeleteProgram(shaderProgram); glDeleteProgram(shaderProgram);
glfwDestroyWindow(window); glfwDestroyWindow(window);
glfwTerminate(); glfwTerminate();
return 0; return 0;
} }

263
source/main.cpp.old Normal file
View File

@ -0,0 +1,263 @@
#include <fstream>
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <stdlib.h>
// glad and GLFW
#include <GLFW/glfw3.h>
#include <glad/glad.h>
// glm math
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
// HPP files
#include "shader.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#define VERTEX_FILE "./shaders/vertex.glsl"
#define FRAGMENT_FILE "./shaders/fragment.glsl"
#define COMPUTE_FILE "./shaders/compute.glsl"
const float SCR_WIDTH = 1200.0f;
const float SCR_HEIGHT = 1200.0f;
void renderProceduralVideo(GLuint shaderProgram, GLuint VAO, GLuint resLoc, GLuint timeLoc, int width, int height, float duration, int fps, const std::string &folder) {
int totalFrames = static_cast<int>(duration * fps);
for (int i = 0; i < totalFrames; ++i) {
float t = i / float(fps); // time in seconds
glUniform1f(timeLoc, t);
glUniform2f(resLoc, width, height);
// Setup off-screen FBO
GLuint fbo, texture;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cerr << "Framebuffer not complete!\n";
return;
}
glViewport(0, 0, width, height);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
std::vector<unsigned char> pixels(width * height * 3);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels.data());
// Flip vertically
for (int y = 0; y < height / 2; ++y) {
int opposite = height - y - 1;
for (int x = 0; x < width * 3; ++x)
std::swap(pixels[y * width * 3 + x], pixels[opposite * width * 3 + x]);
}
char buffer[256];
sprintf(buffer, "%s/frame_%04d.png", folder.c_str(), i);
stbi_write_png(buffer, width, height, 3, pixels.data(), width * 3);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &fbo);
glDeleteTextures(1, &texture);
std::cout << "\rRendering frame " << i + 1 << "/" << totalFrames << std::flush;
}
std::cout << "\nDone rendering video frames!\n";
}
// Call this function with your shader program, VAO, and desired size
void renderProceduralToPNG(GLuint shaderProgram, GLuint VAO, int width, int height, const char *filename) {
// Setup off-screen framebuffer
GLuint fbo, texture;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cerr << "Framebuffer not complete!\n";
return;
}
// Save old viewport
GLint oldViewport[4];
glGetIntegerv(GL_VIEWPORT, oldViewport);
glViewport(0, 0, width, height);
// Clear and render
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// Read pixels
std::vector<unsigned char> pixels(width * height * 3);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels.data());
// Flip vertically
for (int y = 0; y < height / 2; ++y) {
int opposite = height - y - 1;
for (int x = 0; x < width * 3; ++x) {
std::swap(pixels[y * width * 3 + x], pixels[opposite * width * 3 + x]);
}
}
stbi_write_png(filename, width, height, 3, pixels.data(), width * 3);
// Cleanup
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &fbo);
glDeleteTextures(1, &texture);
// Restore old viewport
glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
}
int main(void) {
// Initialize GLFW
if (!glfwInit())
return -1;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // REQUIRED on macOS
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_SAMPLES, 8); // 8x MSAA
GLFWwindow *window = glfwCreateWindow((int)SCR_WIDTH, (int)SCR_HEIGHT, "RASTER", nullptr, nullptr);
if (!window) {
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
std::cerr << "Failed to initialize GLAD\n";
return -1;
}
glViewport(0, 0, (int)SCR_WIDTH, (int)SCR_HEIGHT);
// DEBUG
std::cout << "OpenGL Version: " << glGetString(GL_VERSION) << std::endl;
// ERROR: macOS does not support compute shaders in OpenGL < 4.3.
// GLuint computeProgram = createComputeProgram(COMPUTE_FILE);
// ----- Vertex Data -----
// Cube
// Positions
float vertices[] = {// positions
-1.0f, -1.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f};
unsigned int indices[] = {0, 1, 2, 2, 3, 0};
GLuint VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// position - VERTEX SHADER
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
glEnableVertexAttribArray(0);
// color - FRAGMENT SHADER
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// glBindVertexArray(0);
// Load shaders
GLuint shaderProgram = createShaderProgram(VERTEX_FILE, FRAGMENT_FILE);
// Check if shader program was created successfully
if (shaderProgram == 0) {
std::cerr << "Failed to create shader programs.\n";
return -1;
}
// Caulculate model, view, projection matrices
glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -1.0f));
glm::mat4 projection = glm::perspective(glm::radians(45.0f), (SCR_WIDTH / SCR_HEIGHT) * 2, 0.1f, 100.0f);
GLuint modelLoc = (unsigned int)glGetUniformLocation(shaderProgram, "model");
GLuint viewLoc = (unsigned int)glGetUniformLocation(shaderProgram, "view");
GLuint projLoc = (unsigned int)glGetUniformLocation(shaderProgram, "projection");
glUseProgram(shaderProgram);
glUniformMatrix4fv((int)modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv((int)viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv((int)projLoc, 1, GL_FALSE, glm::value_ptr(projection));
GLint resLoc = glGetUniformLocation(shaderProgram, "u_resolution");
glUniform2f(resLoc, 3840, 2160); // hardcode for now
GLint timeLoc = glGetUniformLocation(shaderProgram, "u_time");
glEnable(GL_MULTISAMPLE);
float scale = 1.0f;
int frameCount = 0;
// Render loop
float timeValue = (float)glfwGetTime();
// --- FPS Counter ---
double currentTime = glfwGetTime();
glUniform1f(timeLoc, timeValue);
frameCount++;
std::string outputFolder = "./frames";
int width = 3840;
int height = 2160;
float duration = 120.0f; // seconds
int fps = 30;
renderProceduralVideo(shaderProgram, VAO, resLoc, timeLoc, width, height, duration, fps, outputFolder);
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glDeleteProgram(shaderProgram);
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}