Skip to content

Commit a850499

Browse files
committed
Change how the menu is drawn and add video export with opencv.
1 parent ef74ade commit a850499

File tree

5 files changed

+189
-53
lines changed

5 files changed

+189
-53
lines changed

Makefile

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
CC := gcc
22
CXX := g++
3-
CFLAGS := -std=c11 -Werror -g -Iinclude -MMD
4-
CXXFLAGS := -std=c++17 -Werror -g -Iinclude -MMD -fopenmp
5-
LDFLAGS := -lglfw -lX11 -lpthread -lXrandr -lXi -ldl -lfftw3 -fopenmp -lxcb
3+
CFLAGS := -std=c11 -Werror -g -Iinclude -I/usr/local/include/opencv4 -MMD -O3 -march=native
4+
CXXFLAGS := -std=c++17 -Werror -g -Iinclude -I/usr/local/include/opencv4 -MMD -fopenmp -O3 -march=native
5+
LDFLAGS := -L/usr/local/lib/ -lglfw -lX11 -lpthread -lXrandr -lXi -ldl -lfftw3 -fopenmp -lxcb -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_videoio
66
BIN_DIR := bin
77
SRC_DIR := src
88
OBJ_DIR := obj

include/App.hpp

+9
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
#pragma once
22

3+
#include <Grid.hpp>
4+
#include <glad/glad.h>
5+
#include <GLFW/glfw3.h>
6+
37
class App {
48
public:
9+
Grid* grid;
510
void run();
611
private:
12+
GLFWwindow* window;
13+
714
bool paused = false;
15+
16+
void drawMenuBar();
817
};

include/Grid.hpp

+6-10
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
#include <vector>
44
#include <glad/glad.h>
55
#include <GLFW/glfw3.h>
6-
76
#include <Shader.hpp>
8-
97
#include <string>
108

119
class Grid {
@@ -17,13 +15,15 @@ class Grid {
1715
unsigned int texture;
1816

1917
void normalize();
20-
2118
float* getData();
2219

20+
void quantizeFrame(const std::vector<unsigned char>& frame,
21+
std::vector<unsigned char>& colorArray,
22+
std::vector<unsigned int>& indexedImage);
23+
2324
protected:
2425
unsigned int width, height;
2526
std::vector<std::vector<double>> data;
26-
2727
int generation = 0;
2828

2929
public:
@@ -37,22 +37,18 @@ class Grid {
3737
void setHeight(unsigned int height);
3838
unsigned int getWidth() const;
3939
unsigned int getHeight() const;
40-
4140
virtual void parse(std::string pattern) = 0;
4241
virtual std::string toString() const = 0;
43-
4442
void reset();
4543
void randomize();
46-
4744
void randomizePatches();
48-
4945
std::vector<double>& operator[](unsigned int row);
5046
const std::vector<double>& operator[](unsigned int row) const;
51-
5247
void set(unsigned int x, unsigned int y, double value);
5348
double get(unsigned int x, unsigned int y) const;
5449

5550
int randomPatches;
5651
int randomPatchSize;
57-
};
5852

53+
void exportToVideo(const std::string& filename, int frameCount, int fps);
54+
};

src/App.cpp

+112-40
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ void App::run() {
4848
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
4949
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
5050

51-
GLFWwindow* window = glfwCreateWindow(1280, 720, "Lenia++", nullptr, nullptr);
51+
window = glfwCreateWindow(1280, 720, "Lenia++", nullptr, nullptr);
5252
if (!window) {
5353
std::cerr << "Failed to create window" << std::endl;
5454
glfwTerminate();
@@ -82,6 +82,8 @@ void App::run() {
8282

8383
lenia.parse("R=18;k=quad4(1,1/3);d=quad4(0.25,0.03)*0.1;cells=0,0,0,0,0,0,0,0,0,0,0,0,0.033424,0.419191,0.575492,0.605072,0.586909,0.409731,0,0,0/0,0,0,0,0,0,0,0,0,0.534431,0.71555,0.866719,0.954007,0.984165,0.978722,0.928526,0.83627,0.7551,0.703546,0.173241,0/0,0,0,0,0,0,0.3104,0.72981,0.803238,0.899622,0.980859,1,1,1,1,1,0.998296,0.877506,0.762396,0.705294,0.043431/0,0,0,0.331086,0.566097,0.86687,0.947779,0.992357,1,0.453233,0.36684,0.287955,0.185868,0.505089,0.575288,0.883505,1,1,0.890394,0.753339,0.441117/0,0,0.569776,0.844285,0.916773,1,1,1,0.294423,0.233356,0.19393,0.141131,0.055147,0,0.054776,0.159762,0.525324,1,1,0.842837,0.558735/0,0.373808,0.854214,0.900566,1,1,1,0.276,0.064531,0.106697,0.138736,0.140799,0.078627,0,0,0.016817,0.110743,0.666998,1,0.939588,0.546418/0,0.771822,0.873032,0.9588,1,0.948526,0.218024,0,0,0.079984,0.230533,0.326668,0.371327,0.621721,0.163791,0,0,0.305775,1,0.987251,0.743893/0.011195,0.858954,0.888521,0.995015,1,0.399933,0.041176,0,0,0.187902,0.444269,0.25343,0.354694,1,1,0,0,0.026414,1,0.99929,0.7418/0.086702,0.858515,0.898522,1,1,0.246327,0.017256,0,0.068599,0.836474,0.326515,0.094562,0.153829,0.430216,1,0.101059,0.017198,0.072865,0.608108,0.98997,0.691148/0.0137,0.851115,0.898572,1,1,0.313138,0.009582,0,0.214462,0.881106,0.280836,0.088129,0.060751,0.144847,0.735773,0.213928,0.064466,0.128274,0.358116,0.968505,0.59327/0,0.588157,0.87189,0.992236,1,0.709643,0.061128,0,0.081501,0.49421,0.082618,0.100734,0.124441,0.188233,0.678219,0.197909,0.092894,0.17204,0.401122,0.916357,0.382958/0,0.138097,0.606145,0.93976,1,1,0.090806,0.049936,0.120229,0.320113,0.576967,0.269626,0.627299,1,0.505278,0.109584,0.095644,0.218831,0.459262,0.841603,0/0,0,0.016688,0.837126,0.977401,1,0.337857,0.185401,0.144064,0.181348,0.289209,0.683256,1,0.970144,0.026589,0.026312,0.092497,0.282652,1,0.75307,0/0,0,0,0,0.807353,0.960297,1,0.330342,0.202457,0.12698,0.067806,0.009687,0.019599,0.019518,0,0,0.110157,1,0.980233,0.660666,0/0,0,0,0,0,0.723638,0.928295,0.505763,0.322371,0.155058,0.032689,0,0,0,0.034073,0.280279,1,1,0.899999,0,0/0,0,0,0,0,0,0.660266,0.928433,1,0.504147,0.099747,0.136311,0.069731,0.113926,0.331142,0.941586,1,0.975989,0.762454,0,0/0,0,0,0,0,0,0,0.66721,0.946846,1,1,1,0.823441,0.949414,1,1,0.97419,0.824723,0.185633,0,0/0,0,0,0,0,0,0,0,0.605209,0.925066,1,1,1,1,0.981979,0.898481,0.79604,0.620238,0,0,0/0,0,0,0,0,0,0,0,0,0.081142,0.811809,0.871226,0.874467,0.833333,0.776943,0.725314,0.695153,0.271033,0,0,0/0,0,0,0,0,0,0,0,0,0,0,0.384868,0.653007,0.709609,0.688523,0.53173,0.142483,0,0,0,0");
8484

85+
grid = &lenia;
86+
8587
Framebuffer framebuffer(1280, 720);
8688

8789
double lastTime = glfwGetTime();
@@ -114,9 +116,12 @@ void App::run() {
114116
glClear(GL_COLOR_BUFFER_BIT);
115117

116118
ImGui::NewFrame();
119+
120+
drawMenuBar();
121+
117122
ImGui::Begin("Spork Viewer", nullptr, ImGuiWindowFlags_NoResize);
118123

119-
ImGui::SetWindowSize(ImVec2(lenia.getWidth() * 3, lenia.getHeight() * 3));
124+
ImGui::SetWindowSize(ImVec2(grid->getWidth() * 3, grid->getHeight() * 3));
120125

121126
const float width = ImGui::GetContentRegionAvail().x;
122127
const float height = ImGui::GetContentRegionAvail().y;
@@ -138,63 +143,130 @@ void App::run() {
138143

139144
ImGui::End();
140145

141-
ImGui::Begin("Controls", nullptr);
142-
if (ImGui::Button("Pause")) {
143-
paused = !paused;
144-
}
145-
146-
if (ImGui::Button("Reset")) {
147-
lenia.reset();
148-
}
149-
if (ImGui::Button("Randomize")) {
150-
lenia.randomize();
151-
}
152-
153-
if (ImGui::Button("Step")) {
154-
lenia.update();
155-
}
156-
157-
// show if its paused
158-
if (paused) {
159-
ImGui::Text("Paused");
160-
}
161-
162-
if (ImGui::CollapsingHeader("Randomizer")) {
163-
ImGui::SliderInt("Patches", &lenia.randomPatches, 1, 10);
164-
ImGui::SliderInt("Patch Size", &lenia.randomPatchSize, 1, 30);
165-
if (ImGui::Button("Randomize Patches")) {
166-
lenia.randomizePatches();
167-
}
168-
}
169-
170-
ImGui::End();
171-
172-
lenia.drawImGui();
146+
grid->drawImGui();
173147

174148
ImGui::Render();
175149

176150
framebuffer.bind();
177151
framebuffer.clear();
178152

179-
lenia.draw();
153+
grid->draw();
180154

181155
framebuffer.unbind();
182156

183157
if (!paused) {
184-
lenia.update();
185-
lenia.updateStats(true);
158+
grid->update();
159+
grid->updateStats(true);
186160
}
187161

188162
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
189163
glfwSwapBuffers(window);
190-
191-
// slow down the simulation
192-
// std::this_thread::sleep_for(std::chrono::milliseconds(16));
193164
}
194165

195166
ImGui_ImplOpenGL3_Shutdown();
196167
ImGui_ImplGlfw_Shutdown();
197168
ImPlot::DestroyContext();
198169
ImGui::DestroyContext();
199170
glfwTerminate();
171+
}
172+
173+
void App::drawMenuBar() {
174+
std::string menuAction = "";
175+
if (ImGui::BeginMainMenuBar()) {
176+
if (ImGui::BeginMenu("File")) {
177+
if (ImGui::MenuItem("Save")) {
178+
menuAction = "save";
179+
}
180+
181+
if (ImGui::MenuItem("Quit")) {
182+
glfwSetWindowShouldClose(window, true);
183+
}
184+
185+
ImGui::EndMenu();
186+
}
187+
188+
if (ImGui::BeginMenu("Edit")) {
189+
if (ImGui::MenuItem("Reset")) {
190+
grid->reset();
191+
}
192+
193+
if (ImGui::MenuItem("Randomize")) {
194+
grid->randomize();
195+
}
196+
197+
if (ImGui::MenuItem("Randomize Patches")) {
198+
grid->randomizePatches();
199+
}
200+
201+
if (ImGui::MenuItem("Edit Random Patches")) {
202+
menuAction = "editRandomPatches";
203+
}
204+
205+
ImGui::EndMenu();
206+
}
207+
208+
if (ImGui::BeginMenu("View")) {
209+
if (ImGui::MenuItem("Pause")) {
210+
paused = !paused;
211+
}
212+
213+
ImGui::EndMenu();
214+
}
215+
216+
if (ImGui::BeginMenu("Simulation")) {
217+
if (ImGui::MenuItem("Step")) {
218+
grid->update();
219+
}
220+
221+
ImGui::EndMenu();
222+
}
223+
224+
ImGui::EndMainMenuBar();
225+
}
226+
227+
if (menuAction == "save") {
228+
ImGui::OpenPopup("Save Video");
229+
paused = true;
230+
}
231+
232+
if (menuAction == "editRandomPatches") {
233+
ImGui::OpenPopup("Edit Random Patches");
234+
paused = true;
235+
}
236+
237+
if (ImGui::BeginPopupModal("Edit Random Patches", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
238+
ImGui::SliderInt("Patches", &grid->randomPatches, 1, 10);
239+
ImGui::SliderInt("Patch Size", &grid->randomPatchSize, 1, 30);
240+
241+
if (ImGui::Button("Close")) {
242+
paused = false;
243+
ImGui::CloseCurrentPopup();
244+
}
245+
246+
ImGui::EndPopup();
247+
}
248+
249+
if (ImGui::BeginPopupModal("Save Video", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
250+
static char filename[128] = "out.mp4";
251+
static int frameCount = 120;
252+
static int fps = 60;
253+
254+
ImGui::InputText("Filename", filename, 128);
255+
ImGui::InputInt("Frame Count", &frameCount);
256+
ImGui::InputInt("FPS", &fps);
257+
258+
if (ImGui::Button("Save")) {
259+
grid->exportToVideo(filename, frameCount, fps);
260+
paused = false;
261+
ImGui::CloseCurrentPopup();
262+
}
263+
264+
ImGui::SameLine();
265+
if (ImGui::Button("Cancel")) {
266+
paused = false;
267+
ImGui::CloseCurrentPopup();
268+
}
269+
270+
ImGui::EndPopup();
271+
}
200272
}

src/Grid.cpp

+59
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44
#include <cmath>
55
#include <cstring>
66

7+
#include <map>
8+
#include <algorithm>
9+
#include <iostream>
10+
11+
#include <opencv2/opencv.hpp>
12+
13+
#include <Framebuffer.hpp>
14+
715
Grid::Grid(unsigned int width, unsigned int height) : width(width), height(height), shader("grid") {
816
float vertices[] = {
917
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
@@ -147,3 +155,54 @@ void Grid::randomizePatches() {
147155
}
148156
}
149157
}
158+
159+
void Grid::exportToVideo(const std::string& filename, int frameCount, int fps) {
160+
// Create VideoWriter object
161+
cv::VideoWriter videoWriter(filename, cv::VideoWriter::fourcc('a', 'v', 'c', '1'), fps, cv::Size(512, 512), true);
162+
163+
if (!videoWriter.isOpened()) {
164+
std::cerr << "Error opening video file for write." << std::endl;
165+
return;
166+
}
167+
168+
Framebuffer framebuffer(512, 512);
169+
170+
// Ensure framebuffer is bound before capturing
171+
framebuffer.bind();
172+
framebuffer.resize(512, 512);
173+
glViewport(0, 0, 512, 512);
174+
175+
// Draw and capture each frame
176+
for (int frame = 0; frame < frameCount; ++frame) {
177+
framebuffer.clear();
178+
179+
// Draw the grid
180+
draw();
181+
182+
// Read pixels from the framebuffer
183+
std::vector<unsigned char> pixels(512 * 512 * 3); // RGB
184+
glReadPixels(0, 0, 512, 512, GL_RGB, GL_UNSIGNED_BYTE, pixels.data());
185+
186+
// Convert to OpenCV matrix
187+
cv::Mat image(512, 512, CV_8UC3, pixels.data());
188+
cv::Mat flippedImage;
189+
cv::flip(image, flippedImage, 0); // Flip the image vertically
190+
191+
cv::Mat bgrImage;
192+
cv::cvtColor(flippedImage, bgrImage, cv::COLOR_RGBA2BGR);
193+
194+
195+
// Write the frame to the video
196+
videoWriter.write(bgrImage);
197+
198+
// Update the grid
199+
update();
200+
}
201+
202+
// Release the framebuffer
203+
framebuffer.unbind();
204+
205+
videoWriter.release();
206+
}
207+
208+

0 commit comments

Comments
 (0)