Compare commits
3 Commits
c2c11a6aba
...
2a0ed92cfc
Author | SHA1 | Date |
---|---|---|
Adrien Bourmault | 2a0ed92cfc | |
Adrien Bourmault | a000fcc414 | |
Adrien Bourmault | 56b8847f95 |
11
Makefile
11
Makefile
|
@ -1,4 +1,4 @@
|
||||||
.PHONY: run clean install all
|
.PHONY: run clean install all gl_test
|
||||||
.DELETE_ON_ERROR: $(BINDIR)/Getting_Started_with_GTK
|
.DELETE_ON_ERROR: $(BINDIR)/Getting_Started_with_GTK
|
||||||
.DEFAULT_GOAL: all
|
.DEFAULT_GOAL: all
|
||||||
|
|
||||||
|
@ -20,6 +20,15 @@ SOURCES = $(shell find $(SRCDIR) -type f -name "*.c")
|
||||||
OBJECTS = $(patsubst %.c,$(BUILDDIR)/%.o,$(SOURCES))
|
OBJECTS = $(patsubst %.c,$(BUILDDIR)/%.o,$(SOURCES))
|
||||||
DEPENDENCIES = $(patsubst %.c,$(BUILDDIR)/%.d,$(SOURCES))
|
DEPENDENCIES = $(patsubst %.c,$(BUILDDIR)/%.d,$(SOURCES))
|
||||||
|
|
||||||
|
sandbox: opengl_sandbox/main.c
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) $(WARNINGS) $(DEBUG)-o $@ $<
|
||||||
|
|
||||||
|
gl_run: sandbox
|
||||||
|
./$<
|
||||||
|
|
||||||
|
gl_clean:
|
||||||
|
rm sandbox
|
||||||
|
|
||||||
all: $(BINDIR)/gem-graph-client
|
all: $(BINDIR)/gem-graph-client
|
||||||
|
|
||||||
-include /etc/os-release
|
-include /etc/os-release
|
||||||
|
|
BIN
instanced_cubes
BIN
instanced_cubes
Binary file not shown.
|
@ -6,15 +6,17 @@
|
||||||
#include <gtk/gtk.h> // GTK types
|
#include <gtk/gtk.h> // GTK types
|
||||||
|
|
||||||
|
|
||||||
|
// General declaration zone ---------------------------------------------------
|
||||||
|
|
||||||
#define N_INSTANCE 5
|
#define N_INSTANCE 5
|
||||||
#define N_SPACE_SIZE 20
|
#define N_SPACE_SIZE 20
|
||||||
|
|
||||||
GtkWidget *window;
|
GtkWidget *window;
|
||||||
|
|
||||||
// OpenGL objects
|
// OpenGL objects
|
||||||
GLuint vao, vbo, ebo, instance_vbo, arrow_instance_vbo;
|
GLuint vao, arrow_vao;
|
||||||
GLuint arrow_vao, arrow_vbo, arrow_ebo;
|
GLuint vbo, arrow_vbo, cubes_instance_vbo, arrow_instance_vbo;
|
||||||
GLuint edge_ebo;
|
GLuint ebo, arrow_ebo, edge_ebo;
|
||||||
GLuint shader_program;
|
GLuint shader_program;
|
||||||
unsigned int num_instances = N_INSTANCE;
|
unsigned int num_instances = N_INSTANCE;
|
||||||
mat4 instance_matrices[N_INSTANCE];
|
mat4 instance_matrices[N_INSTANCE];
|
||||||
|
@ -34,12 +36,12 @@ static bool rotate;
|
||||||
// Projection and view matrices
|
// Projection and view matrices
|
||||||
mat4 projection, view;
|
mat4 projection, view;
|
||||||
|
|
||||||
|
// Function Prototypes zone ---------------------------------------------------
|
||||||
|
|
||||||
// Function Prototypes
|
|
||||||
GLuint create_shader_program ();
|
GLuint create_shader_program ();
|
||||||
void setup_buffers ();
|
void setup_cubes_buffers ();
|
||||||
void setup_arrow_buffers ();
|
void setup_arrow_buffers ();
|
||||||
void setup_instance_data ();
|
void setup_cube_instance_data ();
|
||||||
void setup_arrow_instance_data();
|
void setup_arrow_instance_data();
|
||||||
static void on_realize (GtkGLArea *area);
|
static void on_realize (GtkGLArea *area);
|
||||||
static gboolean on_render (GtkGLArea *area, GdkGLContext *context);
|
static gboolean on_render (GtkGLArea *area, GdkGLContext *context);
|
||||||
|
@ -47,7 +49,10 @@ static void on_activate (GtkApplication *app, gpointer user_data);
|
||||||
static gboolean on_mouse_scroll(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, gpointer user_data);
|
static gboolean on_mouse_scroll(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, gpointer user_data);
|
||||||
static gboolean on_mouse_move(GtkEventControllerMotion *controller, gdouble x, gdouble y, gpointer user_data);
|
static gboolean on_mouse_move(GtkEventControllerMotion *controller, gdouble x, gdouble y, gpointer user_data);
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
// Vertex and fragment shader source code
|
// Vertex and fragment shader source code
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
const char *vertex_shader_src = "#version 460 core\n"
|
const char *vertex_shader_src = "#version 460 core\n"
|
||||||
"layout (location = 0) in vec3 aPos;\n"
|
"layout (location = 0) in vec3 aPos;\n"
|
||||||
"layout (location = 2) in mat4 instanceMatrix;\n"
|
"layout (location = 2) in mat4 instanceMatrix;\n"
|
||||||
|
@ -64,7 +69,10 @@ const char *fragment_shader_src = "#version 460 core\n"
|
||||||
" finalColor = vec4(FragColor.rgb, 0.3); // Set alpha to 30%\n"
|
" finalColor = vec4(FragColor.rgb, 0.3); // Set alpha to 30%\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
||||||
// Cube vertices and indices
|
// ----------------------------------------------------------------------------
|
||||||
|
// Vertices and indices
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
GLfloat vertices[] = {
|
GLfloat vertices[] = {
|
||||||
-0.5f, -0.5f, -0.5f, // 0
|
-0.5f, -0.5f, -0.5f, // 0
|
||||||
0.5f, -0.5f, -0.5f, // 1
|
0.5f, -0.5f, -0.5f, // 1
|
||||||
|
@ -124,6 +132,10 @@ GLuint arrow_indices[] = {
|
||||||
0, 6 // Center to Back face
|
0, 6 // Center to Back face
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// MOUSE MANAGEMENT ZONE
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// Maps a 2D point on the screen to a 3D point on a virtual trackball (sphere)
|
// Maps a 2D point on the screen to a 3D point on a virtual trackball (sphere)
|
||||||
void trackball_map(float x, float y, int width, int height, vec3 out)
|
void trackball_map(float x, float y, int width, int height, vec3 out)
|
||||||
{
|
{
|
||||||
|
@ -192,7 +204,6 @@ static gboolean on_mouse_move(GtkEventControllerMotion *controller, gdouble x, g
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean on_mouse_scroll(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, gpointer user_data)
|
static gboolean on_mouse_scroll(GtkEventControllerScroll *controller, gdouble dx, gdouble dy, gpointer user_data)
|
||||||
{
|
{
|
||||||
if (dy > 0)
|
if (dy > 0)
|
||||||
|
@ -215,7 +226,294 @@ static gboolean on_mouse_scroll(GtkEventControllerScroll *controller, gdouble dx
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// OpenGL zone
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Create the shader program
|
||||||
|
GLuint create_shader_program ()
|
||||||
|
{
|
||||||
|
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
glShaderSource(vertex_shader, 1, &vertex_shader_src, NULL);
|
||||||
|
glCompileShader(vertex_shader);
|
||||||
|
|
||||||
|
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
glShaderSource(fragment_shader, 1, &fragment_shader_src, NULL);
|
||||||
|
glCompileShader(fragment_shader);
|
||||||
|
|
||||||
|
GLuint program = glCreateProgram();
|
||||||
|
glAttachShader(program, vertex_shader);
|
||||||
|
glAttachShader(program, fragment_shader);
|
||||||
|
glLinkProgram(program);
|
||||||
|
|
||||||
|
glDeleteShader(vertex_shader);
|
||||||
|
glDeleteShader(fragment_shader);
|
||||||
|
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup OpenGL buffers (VBO, VAO, EBO for cubes and edges)
|
||||||
|
void setup_cubes_buffers ()
|
||||||
|
{
|
||||||
|
glGenVertexArrays(1, &vao);
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
|
// Vertex buffer
|
||||||
|
glGenBuffers(1, &vbo);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
// Face Index buffer (EBO for cube faces)
|
||||||
|
glGenBuffers(1, &ebo);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
// Vertex attributes
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
|
// Edge Index buffer (EBO for cube edges)
|
||||||
|
glGenBuffers(1, &edge_ebo);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, edge_ebo);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(edge_indices), edge_indices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup instance data for cubes (random positions)
|
||||||
|
void setup_cube_instance_data ()
|
||||||
|
{
|
||||||
|
g_message("[%s] setting up cube instance data...",
|
||||||
|
__func__);
|
||||||
|
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
|
g_message("[%s] random seed initialized",
|
||||||
|
__func__);
|
||||||
|
|
||||||
|
glGenBuffers(1, &cubes_instance_vbo);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, cubes_instance_vbo);
|
||||||
|
|
||||||
|
g_message("[%s] cubes_instance_vbo buffer bound",
|
||||||
|
__func__);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < num_instances; i++) {
|
||||||
|
glm_mat4_identity(instance_matrices[i]);
|
||||||
|
|
||||||
|
// Randomize positions
|
||||||
|
vec3 position = {
|
||||||
|
(float)(rand() % N_SPACE_SIZE) - 10.0f, // Random x from -10 to 10
|
||||||
|
(float)(rand() % N_SPACE_SIZE) - 10.0f, // Random y from -10 to 10
|
||||||
|
(float)(rand() % N_SPACE_SIZE) - 10.0f // Random z from -10 to 10
|
||||||
|
};
|
||||||
|
|
||||||
|
glm_translate(instance_matrices[i], position);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_message("[%s] generated %d cube instances",
|
||||||
|
__func__,
|
||||||
|
num_instances);
|
||||||
|
|
||||||
|
// Pass the instance matrices to the instance VBO
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, num_instances * sizeof(mat4), instance_matrices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
g_message("[%s] instance matrices passed to VBO",
|
||||||
|
__func__);
|
||||||
|
|
||||||
|
// Setup vertex attribute for the model matrix (location = 2)
|
||||||
|
// Setup vertex attribute for the model matrix (location = 2)
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
glVertexAttribPointer(2 + i, 4, GL_FLOAT, GL_FALSE, sizeof(mat4), (void*)(sizeof(vec4) * i));
|
||||||
|
glEnableVertexAttribArray(2 + i);
|
||||||
|
glVertexAttribDivisor(2 + i, 1); // Tell OpenGL this is per-instance data
|
||||||
|
}
|
||||||
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
|
||||||
|
g_message("[%s] finalized model matrix vertex attribute ",
|
||||||
|
__func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_arrow_buffers()
|
||||||
|
{
|
||||||
|
glGenVertexArrays(1, &arrow_vao);
|
||||||
|
glBindVertexArray(arrow_vao);
|
||||||
|
|
||||||
|
// Vertex buffer for arrows
|
||||||
|
glGenBuffers(1, &arrow_vbo);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, arrow_vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(arrow_vertices), arrow_vertices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
// Index buffer for arrows
|
||||||
|
glGenBuffers(1, &arrow_ebo);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, arrow_ebo);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(arrow_indices), arrow_indices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
// Vertex attributes
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_arrow_instance_data()
|
||||||
|
{
|
||||||
|
// Define indices for the arrows (lines from center to cube faces)
|
||||||
|
GLuint arrow_indices[] = {
|
||||||
|
0, 1, // Arrow pointing to right face
|
||||||
|
0, 2, // Arrow pointing upwards
|
||||||
|
0, 3, // Arrow pointing to front face
|
||||||
|
0, 4, // Arrow pointing to left face
|
||||||
|
0, 5, // Arrow pointing downwards
|
||||||
|
0, 6 // Arrow pointing to back face
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate Vertex Buffer Object for arrows
|
||||||
|
glGenBuffers(1, &arrow_vbo);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, arrow_vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(arrow_vertices), arrow_vertices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
// Generate Element Buffer Object for arrows
|
||||||
|
glGenBuffers(1, &arrow_ebo);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, arrow_ebo);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(arrow_indices), arrow_indices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
// Define arrow vertex attributes
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
|
// Arrow instance matrices (positions) -- same as cubes
|
||||||
|
glGenBuffers(1, &arrow_instance_vbo);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, arrow_instance_vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, num_instances * sizeof(mat4), instance_matrices, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
// Define vertex attribute for arrow instance matrix
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
glVertexAttribPointer(2 + i, 4, GL_FLOAT, GL_FALSE, sizeof(mat4), (void*)(sizeof(vec4) * i));
|
||||||
|
glEnableVertexAttribArray(2 + i);
|
||||||
|
glVertexAttribDivisor(2 + i, 1); // Make this per-instance data
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// GTK / OpenGL zone
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// Called when GtkGLArea is realized (OpenGL context is created)
|
||||||
|
static void on_realize(GtkGLArea *area)
|
||||||
|
{
|
||||||
|
g_message("[%s] GLArea realization in progress...", __func__);
|
||||||
|
|
||||||
|
gtk_gl_area_make_current(GTK_GL_AREA(area));
|
||||||
|
|
||||||
|
g_message("[%s] GLArea made current", __func__);
|
||||||
|
|
||||||
|
if (gtk_gl_area_get_error(GTK_GL_AREA(area)) != NULL) return;
|
||||||
|
|
||||||
|
g_message("[%s] OpenGL context successfully created", __func__);
|
||||||
|
|
||||||
|
// Enable depth testing
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
|
|
||||||
|
// Initialize cglm projection and view matrices
|
||||||
|
glm_mat4_identity(projection);
|
||||||
|
glm_perspective(glm_rad(60.0f), 800.0f / 600.0f, 0.1f, 100.0f, projection);
|
||||||
|
|
||||||
|
glm_mat4_identity(view);
|
||||||
|
glm_lookat((vec3){0.0f, 0.0f, 20.0f}, (vec3){0.0f, 0.0f, 0.0f}, (vec3){0.0f, 1.0f, 0.0f}, view);
|
||||||
|
|
||||||
|
// Initialize rotation matrix
|
||||||
|
glm_mat4_identity(rotation_matrix); // Initialize to identity
|
||||||
|
|
||||||
|
// Create shader program and setup buffers
|
||||||
|
shader_program = create_shader_program();
|
||||||
|
setup_cubes_buffers();
|
||||||
|
setup_arrow_buffers();
|
||||||
|
setup_cube_instance_data();
|
||||||
|
setup_arrow_instance_data(); // Setup arrow data
|
||||||
|
|
||||||
|
// Set the background color
|
||||||
|
glClearColor(0.1f, 0.1f, 0.1f, 1.0f); // Dark gray background
|
||||||
|
glLineWidth(2.0f); // Increase the line width for cube edges
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Called on each frame to render the scene
|
||||||
|
static gboolean on_render(GtkGLArea *area, GdkGLContext *context)
|
||||||
|
{
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glDepthFunc(GL_LESS);
|
||||||
|
|
||||||
|
glUseProgram(shader_program);
|
||||||
|
|
||||||
|
// Pass projection and view matrices to the shader
|
||||||
|
GLint projectionLoc = glGetUniformLocation(shader_program, "projection");
|
||||||
|
GLint viewLoc = glGetUniformLocation(shader_program, "view");
|
||||||
|
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, (const GLfloat *)projection);
|
||||||
|
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, (const GLfloat *)view);
|
||||||
|
|
||||||
|
// Update instance matrices with the accumulated rotation matrix
|
||||||
|
if (rotate) {
|
||||||
|
for (unsigned int i = 0; i < num_instances; i++) {
|
||||||
|
mat4 model;
|
||||||
|
glm_mat4_copy(rotation_matrix, model); // Copy the accumulated rotation matrix
|
||||||
|
|
||||||
|
// Combine the rotation with the instance's individual matrix
|
||||||
|
glm_mul(model, instance_matrices[i], instance_matrices[i]);
|
||||||
|
}
|
||||||
|
rotate = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the instance matrix buffer with the modified instance matrices
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, cubes_instance_vbo);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, num_instances * sizeof(mat4), instance_matrices);
|
||||||
|
|
||||||
|
// Draw the cubes with the updated instance matrices
|
||||||
|
glUniform4f(glGetUniformLocation(shader_program, "FragColor"), 0.4f, 0.6f, 0.9f, 1.0f);
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||||
|
glDrawElementsInstanced(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0, num_instances);
|
||||||
|
|
||||||
|
// Draw the cube edges
|
||||||
|
glUniform4f(glGetUniformLocation(shader_program, "FragColor"), 1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, edge_ebo);
|
||||||
|
glDrawElementsInstanced(GL_LINES, 24, GL_UNSIGNED_INT, 0, num_instances);
|
||||||
|
|
||||||
|
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
// Set arrow color (e.g., red) and draw arrows
|
||||||
|
glUniform4f(glGetUniformLocation(shader_program, "FragColor"), 1.0f, 0.0f, 0.0f, 1.0f); // Red, opaque
|
||||||
|
|
||||||
|
// Bind the arrow VAO and use the same transformation matrices
|
||||||
|
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, (const GLfloat *)projection);
|
||||||
|
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, (const GLfloat *)view);
|
||||||
|
|
||||||
|
// Draw the arrows
|
||||||
|
glBindVertexArray(arrow_vao);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, arrow_ebo);
|
||||||
|
glDrawElementsInstanced(GL_LINES, 12, GL_UNSIGNED_INT, 0, num_instances);
|
||||||
|
|
||||||
|
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
// Reset the rotation matrix to prevent continuous accumulation
|
||||||
|
glm_mat4_identity(rotation_matrix);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// GTK ZONE
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// Called when GtkApplication is activated
|
// Called when GtkApplication is activated
|
||||||
static void on_activate (GtkApplication *app, gpointer user_data)
|
static void on_activate (GtkApplication *app, gpointer user_data)
|
||||||
|
@ -263,280 +561,6 @@ static void on_activate (GtkApplication *app, gpointer user_data)
|
||||||
__func__);
|
__func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when GtkGLArea is realized (OpenGL context is created)
|
|
||||||
static void on_realize(GtkGLArea *area)
|
|
||||||
{
|
|
||||||
g_message("[%s] GLArea realization in progress...", __func__);
|
|
||||||
|
|
||||||
gtk_gl_area_make_current(GTK_GL_AREA(area));
|
|
||||||
|
|
||||||
g_message("[%s] GLArea made current", __func__);
|
|
||||||
|
|
||||||
if (gtk_gl_area_get_error(GTK_GL_AREA(area)) != NULL) return;
|
|
||||||
|
|
||||||
g_message("[%s] OpenGL context successfully created", __func__);
|
|
||||||
|
|
||||||
// Enable depth testing
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
|
|
||||||
glDepthFunc(GL_LESS);
|
|
||||||
|
|
||||||
// Initialize cglm projection and view matrices
|
|
||||||
glm_mat4_identity(projection);
|
|
||||||
glm_perspective(glm_rad(60.0f), 800.0f / 600.0f, 0.1f, 100.0f, projection);
|
|
||||||
|
|
||||||
glm_mat4_identity(view);
|
|
||||||
glm_lookat((vec3){0.0f, 0.0f, 20.0f}, (vec3){0.0f, 0.0f, 0.0f}, (vec3){0.0f, 1.0f, 0.0f}, view);
|
|
||||||
|
|
||||||
// Initialize rotation matrix
|
|
||||||
glm_mat4_identity(rotation_matrix); // Initialize to identity
|
|
||||||
|
|
||||||
// Create shader program and setup buffers
|
|
||||||
shader_program = create_shader_program();
|
|
||||||
setup_buffers();
|
|
||||||
setup_arrow_buffers();
|
|
||||||
setup_instance_data();
|
|
||||||
setup_arrow_instance_data(); // Setup arrow data
|
|
||||||
|
|
||||||
// Set the background color
|
|
||||||
glClearColor(0.1f, 0.1f, 0.1f, 1.0f); // Dark gray background
|
|
||||||
glLineWidth(2.0f); // Increase the line width for cube edges
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Called on each frame to render the scene
|
|
||||||
static gboolean on_render(GtkGLArea *area, GdkGLContext *context)
|
|
||||||
{
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
glDepthFunc(GL_LESS);
|
|
||||||
|
|
||||||
glUseProgram(shader_program);
|
|
||||||
|
|
||||||
// Pass projection and view matrices to the shader
|
|
||||||
GLint projectionLoc = glGetUniformLocation(shader_program, "projection");
|
|
||||||
GLint viewLoc = glGetUniformLocation(shader_program, "view");
|
|
||||||
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, (const GLfloat *)projection);
|
|
||||||
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, (const GLfloat *)view);
|
|
||||||
|
|
||||||
// Update instance matrices with the accumulated rotation matrix
|
|
||||||
if (rotate) {
|
|
||||||
for (unsigned int i = 0; i < num_instances; i++) {
|
|
||||||
mat4 model;
|
|
||||||
glm_mat4_copy(rotation_matrix, model); // Copy the accumulated rotation matrix
|
|
||||||
|
|
||||||
// Combine the rotation with the instance's individual matrix
|
|
||||||
glm_mul(model, instance_matrices[i], instance_matrices[i]);
|
|
||||||
}
|
|
||||||
rotate = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the instance matrix buffer with the modified instance matrices
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, instance_vbo);
|
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, num_instances * sizeof(mat4), instance_matrices);
|
|
||||||
|
|
||||||
// Draw the cubes with the updated instance matrices
|
|
||||||
glUniform4f(glGetUniformLocation(shader_program, "FragColor"), 0.4f, 0.6f, 0.9f, 1.0f);
|
|
||||||
glBindVertexArray(vao);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
|
||||||
glDrawElementsInstanced(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0, num_instances);
|
|
||||||
|
|
||||||
// Draw the cube edges
|
|
||||||
glUniform4f(glGetUniformLocation(shader_program, "FragColor"), 1.0f, 1.0f, 1.0f, 1.0f);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, edge_ebo);
|
|
||||||
glDrawElementsInstanced(GL_LINES, 24, GL_UNSIGNED_INT, 0, num_instances);
|
|
||||||
|
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
|
|
||||||
// Set arrow color (e.g., red) and draw arrows
|
|
||||||
glUniform4f(glGetUniformLocation(shader_program, "FragColor"), 1.0f, 0.0f, 0.0f, 1.0f); // Red, opaque
|
|
||||||
glBindVertexArray(arrow_vao);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, arrow_ebo);
|
|
||||||
glDrawElementsInstanced(GL_LINES, 12, GL_UNSIGNED_INT, 0, num_instances);
|
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
|
||||||
glBindVertexArray(0);
|
|
||||||
|
|
||||||
// Reset the rotation matrix to prevent continuous accumulation
|
|
||||||
glm_mat4_identity(rotation_matrix);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the shader program
|
|
||||||
GLuint create_shader_program ()
|
|
||||||
{
|
|
||||||
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
|
|
||||||
glShaderSource(vertex_shader, 1, &vertex_shader_src, NULL);
|
|
||||||
glCompileShader(vertex_shader);
|
|
||||||
|
|
||||||
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
|
|
||||||
glShaderSource(fragment_shader, 1, &fragment_shader_src, NULL);
|
|
||||||
glCompileShader(fragment_shader);
|
|
||||||
|
|
||||||
GLuint program = glCreateProgram();
|
|
||||||
glAttachShader(program, vertex_shader);
|
|
||||||
glAttachShader(program, fragment_shader);
|
|
||||||
glLinkProgram(program);
|
|
||||||
|
|
||||||
glDeleteShader(vertex_shader);
|
|
||||||
glDeleteShader(fragment_shader);
|
|
||||||
|
|
||||||
return program;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup OpenGL buffers (VBO, VAO, EBO for cubes and edges)
|
|
||||||
void setup_buffers ()
|
|
||||||
{
|
|
||||||
glGenVertexArrays(1, &vao);
|
|
||||||
glBindVertexArray(vao);
|
|
||||||
|
|
||||||
// Vertex buffer
|
|
||||||
glGenBuffers(1, &vbo);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
// Face Index buffer (EBO for cube faces)
|
|
||||||
glGenBuffers(1, &ebo);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
// Vertex attributes
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
|
|
||||||
// Edge Index buffer (EBO for cube edges)
|
|
||||||
glGenBuffers(1, &edge_ebo);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, edge_ebo);
|
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(edge_indices), edge_indices, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
glBindVertexArray(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup_arrow_buffers() {
|
|
||||||
glGenVertexArrays(1, &arrow_vao);
|
|
||||||
glBindVertexArray(arrow_vao);
|
|
||||||
|
|
||||||
// Vertex buffer for arrows
|
|
||||||
glGenBuffers(1, &arrow_vbo);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, arrow_vbo);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(arrow_vertices), arrow_vertices, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
// Index buffer for arrows
|
|
||||||
glGenBuffers(1, &arrow_ebo);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, arrow_ebo);
|
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(arrow_indices), arrow_indices, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
// Vertex attributes
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
|
|
||||||
glBindVertexArray(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup instance data for cubes (random positions)
|
|
||||||
void setup_instance_data ()
|
|
||||||
{
|
|
||||||
g_message("[%s] setting up cube instance data...",
|
|
||||||
__func__);
|
|
||||||
|
|
||||||
srand(time(NULL));
|
|
||||||
|
|
||||||
g_message("[%s] random seed initialized",
|
|
||||||
__func__);
|
|
||||||
|
|
||||||
glGenBuffers(1, &instance_vbo);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, instance_vbo);
|
|
||||||
|
|
||||||
g_message("[%s] instance_vbo buffer bound",
|
|
||||||
__func__);
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < num_instances; i++) {
|
|
||||||
glm_mat4_identity(instance_matrices[i]);
|
|
||||||
|
|
||||||
// Randomize positions
|
|
||||||
vec3 position = {
|
|
||||||
(float)(rand() % N_SPACE_SIZE) - 10.0f, // Random x from -10 to 10
|
|
||||||
(float)(rand() % N_SPACE_SIZE) - 10.0f, // Random y from -10 to 10
|
|
||||||
(float)(rand() % N_SPACE_SIZE) - 10.0f // Random z from -10 to 10
|
|
||||||
};
|
|
||||||
|
|
||||||
glm_translate(instance_matrices[i], position);
|
|
||||||
}
|
|
||||||
g_message("[%s] generated %d cube instances",
|
|
||||||
__func__,
|
|
||||||
num_instances);
|
|
||||||
|
|
||||||
// Pass the instance matrices to the instance VBO
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, num_instances * sizeof(mat4), instance_matrices, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
g_message("[%s] instance matrices passed to VBO",
|
|
||||||
__func__);
|
|
||||||
|
|
||||||
// Setup vertex attribute for the model matrix (location = 2)
|
|
||||||
// Setup vertex attribute for the model matrix (location = 2)
|
|
||||||
glBindVertexArray(vao);
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
glVertexAttribPointer(2 + i, 4, GL_FLOAT, GL_FALSE, sizeof(mat4), (void*)(sizeof(vec4) * i));
|
|
||||||
glEnableVertexAttribArray(2 + i);
|
|
||||||
glVertexAttribDivisor(2 + i, 1); // Tell OpenGL this is per-instance data
|
|
||||||
}
|
|
||||||
glBindVertexArray(0);
|
|
||||||
|
|
||||||
|
|
||||||
g_message("[%s] finalized model matrix vertex attribute ",
|
|
||||||
__func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup_arrow_instance_data() {
|
|
||||||
// Define indices for the arrows (lines from center to cube faces)
|
|
||||||
GLuint arrow_indices[] = {
|
|
||||||
0, 1, // Arrow pointing to right face
|
|
||||||
0, 2, // Arrow pointing upwards
|
|
||||||
0, 3, // Arrow pointing to front face
|
|
||||||
0, 4, // Arrow pointing to left face
|
|
||||||
0, 5, // Arrow pointing downwards
|
|
||||||
0, 6 // Arrow pointing to back face
|
|
||||||
};
|
|
||||||
|
|
||||||
// Generate Vertex Array Object for arrows
|
|
||||||
glGenVertexArrays(1, &arrow_vao);
|
|
||||||
glBindVertexArray(arrow_vao);
|
|
||||||
|
|
||||||
// Generate Vertex Buffer Object for arrows
|
|
||||||
GLuint arrow_vbo;
|
|
||||||
glGenBuffers(1, &arrow_vbo);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, arrow_vbo);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(arrow_vertices), arrow_vertices, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
// Generate Element Buffer Object for arrows
|
|
||||||
GLuint arrow_ebo;
|
|
||||||
glGenBuffers(1, &arrow_ebo);
|
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, arrow_ebo);
|
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(arrow_indices), arrow_indices, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
// Define arrow vertex attributes
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
|
|
||||||
// Arrow instance matrices (positions) -- same as cubes
|
|
||||||
glGenBuffers(1, &arrow_instance_vbo);
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, arrow_instance_vbo);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, num_instances * sizeof(mat4), instance_matrices, GL_STATIC_DRAW);
|
|
||||||
|
|
||||||
// Define vertex attribute for arrow instance matrix
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
glVertexAttribPointer(2 + i, 4, GL_FLOAT, GL_FALSE, sizeof(mat4), (void*)(sizeof(vec4) * i));
|
|
||||||
glEnableVertexAttribArray(2 + i);
|
|
||||||
glVertexAttribDivisor(2 + i, 1); // Make this per-instance data
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindVertexArray(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Main Function
|
// Main Function
|
||||||
int main (int argc, char *argv[])
|
int main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -571,3 +595,4 @@ int main (int argc, char *argv[])
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue