diff --git a/include/base.h b/include/base.h index 493eca0..a05146e 100644 --- a/include/base.h +++ b/include/base.h @@ -23,6 +23,12 @@ */ #pragma once +#include +#include +#include +#include +#include +#include enum { @@ -32,3 +38,38 @@ enum N_AXIS }; + +/* + * Read a file from filename into a provided buffer + * + * @param filename, file name + * contents, target ptr + * + * @return void + */ +static inline bool read_file(char *filename, char **contents) +{ + int fd = open(filename, O_RDONLY); + + if(fd < 0) { + printf("Couldn't read file: %s\n",filename); + return false; + } + + int filesize = lseek(fd, 0, SEEK_END) +1 ; + *contents = malloc(sizeof(char) * filesize); + + if (errno) { + perror("Not enough memory to allocate file"); + return false; + } + + lseek(fd, 0, SEEK_SET); + read(fd,*contents,filesize); + + *contents[filesize-1]='\0'; + + close(fd); + + return true; +} diff --git a/include/graphics.h b/include/graphics.h index c324ef1..1737496 100644 --- a/include/graphics.h +++ b/include/graphics.h @@ -24,20 +24,48 @@ #pragma once #include +#include #include -void graphics_draw(void); +/* + * Structure describing a gl_area and its parameters, used to create a table + * of Gem-graph client current gl_areas + */ +struct gl_area_entry { + void *ptr; // ptr to GtkGLArea + GLuint vao; + GLuint position_buffer; + GLuint color_buffer; + GLuint program; + GLuint m; + GLuint v; + GLuint p; + GLuint indices_nb; +}; -void graphics_init_buffers( GLuint *vao_out, GLuint *buffer_out, - GLuint *color_buffer_out ); +/* + * Initializes a gl_area + * + * @param gl_area, ptr to the gl_area widget + * + * @return true if initialized + */ +bool graphics_init(void *gl_area); -void graphics_init_shaders( GLuint *program_out, GLuint *m_out, - GLuint *v_out, GLuint *p_out ); +/* + * Draws the current buffer to a gl_area + * + * @param gl_area, ptr to the gl_area widget + * + * @return void + */ +void graphics_draw(void *gl_area); -void graphics_debug_callback( GLenum source, GLenum type, GLuint id, - GLenum severity, GLsizei length, const GLchar *msg, - const void *data ); - -void graphics_init(void); - -void graphics_shutdown(void); +/* + * Shutdowns a gl_area + * + * @param gl_area, ptr to the gl_area widget + * + * @return true if success + */ +bool graphics_shutdown(void *gl_area); diff --git a/include/graphics_cube.h b/include/graphics_cube.h new file mode 100644 index 0000000..e0cb8a8 --- /dev/null +++ b/include/graphics_cube.h @@ -0,0 +1,78 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: OpenGL utils header + * + * Copyright (C) 2023 Arthur Menges + * Copyright (C) 2023 Adrien Bourmault + * + * This file is part of Gem-graph. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +/* -------------------------------------------------------------------------- */ + +// v4----- v5 +// /| /| +// v1------v0| +// | | | | +// | |v7---|-|v6 +// |/ |/ +// v2------v3 +// +static GLfloat vertex_base[] = { + 0.5, 0.5, 0.5, // v0 + -0.5, 0.5, 0.5, // v1 + -0.5,-0.5, 0.5, // v2 + 0.5,-0.5, 0.5, // v3 + 0.5, 0.5,-0.5, // v4 + -0.5, 0.5,-0.5, // v5 + -0.5,-0.5,-0.5, // v6 + 0.5,-0.5,-0.5, // v7 +}; + +static GLubyte indices[] = { + 0,1, + 1,2, + 2,3, + 3,0, + + 4,5, + 5,6, + 6,7, + 7,4, + + 0,4, + 1,5, + 2,6, + 3,7, +}; + + +static GLfloat color_base[] = { + 0.8, 0.8, 0.8, // blanc + 0.8, 0.8, 0.2, // jaune + 0.8, 0.2, 0.2, // rouge + 0.2, 0.2, 0.2, // noir + 0.2, 0.2, 0.2, // gris + 0.2, 0.8, 0.8, // cyan + 0.2, 0.8, 0.2, // vert + 0.8, 0.2, 0.8, // magenta +}; + +/* -------------------------------------------------------------------------- */ diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index 0bbe794..b35e4e6 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -22,391 +22,50 @@ * along with this program. If not, see . */ -#include #include #include +#include #include #include #include #include #include #include +#include #include "../../include/base.h" #include "../../include/ui.h" +#include "../../include/graphics.h" +#include "../../include/graphics_cube.h" #define VERTEX_SHADER_FILE "src/shaders/shader.vert" #define FRAG_SHADER_FILE "src/shaders/shader.frag" /* -------------------------------------------------------------------------- */ -static GLuint position_buffer; -static GLuint color_buffer; -static GLuint program; -static GLuint m_location; -static GLuint v_location; -static GLuint p_location; -static GLuint indices_nb; - -// v4----- v5 -// /| /| -// v1------v0| -// | | | | -// | |v7---|-|v6 -// |/ |/ -// v2------v3 -// -static GLfloat vertex_base[] = { - 0.5, 0.5, 0.5, // v0 - -0.5, 0.5, 0.5, // v1 - -0.5,-0.5, 0.5, // v2 - 0.5,-0.5, 0.5, // v3 - 0.5, 0.5,-0.5, // v4 - -0.5, 0.5,-0.5, // v5 - -0.5,-0.5,-0.5, // v6 - 0.5,-0.5,-0.5, // v7 -}; - -static GLubyte indices[] = { - 0,1, - 1,2, - 2,3, - 3,0, - - 4,5, - 5,6, - 6,7, - 7,4, - - 0,4, - 1,5, - 2,6, - 3,7, -}; - - -static GLfloat color_base[] = { - 0.8, 0.8, 0.8, // blanc - 0.8, 0.8, 0.2, // jaune - 0.8, 0.2, 0.2, // rouge - 0.2, 0.2, 0.2, // noir - 0.2, 0.2, 0.2, // gris - 0.2, 0.8, 0.8, // cyan - 0.2, 0.8, 0.2, // vert - 0.8, 0.2, 0.8, // magenta -}; +/* + * Dynamic array of ptr to dynamically allocated gl_area_entry + */ +static struct gl_area_entry **gl_area_array = NULL; /* -------------------------------------------------------------------------- */ -void graphics_debug_callback( GLenum source, GLenum type, GLuint id, GLenum severity, - GLsizei length, const GLchar *msg, const void *data ); - -static inline void compute_i(float *res) -{ - /* initialize to the identity matrix */ - res[0] = 1.f; res[4] = 0.f; res[8] = 0.f; res[12] = 0.f; - res[1] = 0.f; res[5] = 1.f; res[9] = 0.f; res[13] = 0.f; - res[2] = 0.f; res[6] = 0.f; res[10] = 1.f; res[14] = 0.f; - res[3] = 0.f; res[7] = 0.f; res[11] = 0.f; res[15] = 1.f; -} - -static inline void compute_mvp(float *res, float phi, float theta, float psi) -{ - float x = phi *(G_PI / 180.f); - float y = theta *(G_PI / 180.f); - float z = psi *(G_PI / 180.f); - float c1 = cosf(x), s1 = sinf(x); - float c2 = cosf(y), s2 = sinf(y); - float c3 = cosf(z), s3 = sinf(z); - float c3c2 = c3 * c2; - float s3c1 = s3 * c1; - float c3s2s1 = c3 * s2 * s1; - float s3s1 = s3 * s1; - float c3s2c1 = c3 * s2 * c1; - float s3c2 = s3 * c2; - float c3c1 = c3 * c1; - float s3s2s1 = s3 * s2 * s1; - float c3s1 = c3 * s1; - float s3s2c1 = s3 * s2 * c1; - float c2s1 = c2 * s1; - float c2c1 = c2 * c1; - - compute_i(res); - - /* apply all three rotations using the three matrices: - * - * ⎡ c3 s3 0 ⎤ ⎡ c2 0 -s2 ⎤ ⎡ 1 0 0 ⎤ - * ⎢ -s3 c3 0 ⎥ ⎢ 0 1 0 ⎥ ⎢ 0 c1 s1 ⎥ - * ⎣ 0 0 1 ⎦ ⎣ s2 0 c2 ⎦ ⎣ 0 -s1 c1 ⎦ - */ - res[0] = c3c2; res[4] = s3c1 + c3s2s1; res[8] = s3s1 - c3s2c1; res[12] = 0.f; - res[1] = -s3c2; res[5] = c3c1 - s3s2s1; res[9] = c3s1 + s3s2c1; res[13] = 0.f; - res[2] = s2; res[6] = -c2s1; res[10] = c2c1; res[14] = 0.f; - res[3] = 0.f; res[7] = 0.f; res[11] = 0.f; res[15] = 1.f; - -} - -/* Create and compile a shader */ -static GLuint create_shader(int type, const char *src) -{ - GLuint shader; - int status; - - shader = glCreateShader(type); - glShaderSource(shader, 1, &src, NULL); - glCompileShader(shader); - - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - if(status == GL_FALSE) { - int log_len; - char *buffer; - - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len); - - buffer = g_malloc(log_len + 1); - glGetShaderInfoLog(shader, log_len, NULL, buffer); - - g_warning("Compile failure in %s shader:\n%s", - type == GL_VERTEX_SHADER ? "vertex" : "fragment", - buffer); - - g_free(buffer); - - glDeleteShader(shader); - - return 0; - } - - return shader; -} - -static inline char *read_shader_file(char *filename) -{ - int fd = open(filename, O_RDONLY); - - if(fd < 0) { - printf("Couldn't read shader: %s\n",filename); - return NULL; - } - - int shader_size = lseek(fd, 0, SEEK_END) +1 ; - char *shader_contents = malloc(sizeof(char) * shader_size); - - lseek(fd, 0, SEEK_SET); - read(fd,shader_contents,shader_size); - - shader_contents[shader_size-1]='\0'; - - //printf("Shader %s content is :\n%s\n", filename, shader_contents); - - close(fd); - - return shader_contents; -} - -/* -------------------------------------------------------------------------- */ - -void graphics_draw(void) -{ - float m[16]; - float v[16]; - float p[16]; - - - /* Compute the model view projection matrix using the - * rotation angles specified through the GtkRange widgets - */ - compute_mvp(p, - rotation_angles[X_AXIS], - rotation_angles[Y_AXIS], - rotation_angles[Z_AXIS]); - compute_i(m); - compute_i(v); - - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - /* Use our shaders */ - glUseProgram(program); - - /* Update the "mvp" matrix we use in the shader */ - glUniformMatrix4fv(m_location, 1, GL_FALSE, &m[0]); - glUniformMatrix4fv(v_location, 1, GL_FALSE, &v[0]); - glUniformMatrix4fv(p_location, 1, GL_FALSE, &p[0]); - - /* Use the vertices in our buffer */ - glEnableVertexAttribArray(0); - glBindBuffer(GL_ARRAY_BUFFER, position_buffer); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0,(void*)0); - - // couleurs - glEnableVertexAttribArray(1); - glBindBuffer(GL_ARRAY_BUFFER, color_buffer); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0,(void*)0); - - glEnable(GL_DEPTH_TEST); - - glDrawElements(GL_LINES, indices_nb, GL_UNSIGNED_BYTE, indices); - - /* We finished using the buffers and program */ - glDisableVertexAttribArray(0); - glDisableVertexAttribArray(1); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glUseProgram(0); - - glFlush(); -} - - -/* Initialize the GL buffers */ -void graphics_init_buffers( GLuint *vao_out, GLuint *buffer_out, - GLuint *color_buffer_out) -{ - GLuint vao, vertex_buffer, color_buffer; - - indices_nb = sizeof(indices) / sizeof(indices[0]); - - int vertex_nb = indices_nb * 3; - - - printf("Initialization of buffers with %u indices (=%u vertex)\n", - indices_nb, - vertex_nb); - - printf("Real vertex number is %lu long\n", - sizeof(vertex_base) / sizeof(vertex_base[0])); - - // We only use one VAO, so we always keep it bound - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - - // vertices - glGenBuffers(1, &vertex_buffer); - glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_base), vertex_base, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - // colors - glGenBuffers(1, &color_buffer); - glBindBuffer(GL_ARRAY_BUFFER, color_buffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(color_base), color_base, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - if(vao_out != NULL) - *vao_out = vao; - - if(buffer_out != NULL) - *buffer_out = vertex_buffer; - - if(color_buffer_out != NULL) - *color_buffer_out = color_buffer; -} - - - -/* Initialize the shaders and link them into a program */ -void graphics_init_shaders( GLuint *program_out, GLuint *m_out, - GLuint *v_out, GLuint *p_out) -{ - GLuint vertex, fragment; - GLuint program = 0; - GLuint m = 0; - GLuint v = 0; - GLuint p = 0; - int status; - - vertex = create_shader(GL_VERTEX_SHADER, read_shader_file(VERTEX_SHADER_FILE)); - - if(vertex == 0) { - *program_out = 0; - return; - } - - fragment = create_shader(GL_FRAGMENT_SHADER, read_shader_file(FRAG_SHADER_FILE)); - - if(fragment == 0) { - glDeleteShader(vertex); - *program_out = 0; - return; - } - - program = glCreateProgram(); - glAttachShader(program, vertex); - glAttachShader(program, fragment); - - glLinkProgram(program); - - glGetProgramiv(program, GL_LINK_STATUS, &status); - - if(status == GL_FALSE) { - int log_len; - char *buffer; - - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_len); - - buffer = g_malloc(log_len + 1); - glGetProgramInfoLog(program, log_len, NULL, buffer); - - g_warning("Linking failure:\n%s", buffer); - - g_free(buffer); - - glDeleteProgram(program); - program = 0; - - goto out; - } - - /* Get the location of the "mvp" uniform */ - m = glGetUniformLocation(program, "model_matrix"); - v = glGetUniformLocation(program, "view_matrix"); - p = glGetUniformLocation(program, "projection_matrix"); - - glDetachShader(program, vertex); - glDetachShader(program, fragment); - -out: - glDeleteShader(vertex); - glDeleteShader(fragment); - - if(program_out != NULL) - *program_out = program; - - if(m_out != NULL) - *m_out = m; - - if(v_out != NULL) - *v_out = v; - - if(p_out != NULL) - *p_out = p; -} - -void graphics_init(void) -{ - glEnable(GL_DEBUG_OUTPUT); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glEnable(GL_MULTISAMPLE); - //glEnable(GL_POLYGON_SMOOTH); - //glEnable(GL_PROGRAM_POINT_SIZE); - - graphics_init_buffers(NULL, &position_buffer, &color_buffer); - graphics_init_shaders(&program, &m_location, &v_location, &p_location); - glDebugMessageCallback(graphics_debug_callback, NULL); -} - -void graphics_shutdown(void) -{ - glDeleteBuffers(1, &position_buffer); - glDeleteBuffers(1, &color_buffer); - glDeleteProgram(program); -} - - -/* -------------------------------------------------------------------------- */ - -void graphics_debug_callback( GLenum source, GLenum type, GLuint id, GLenum severity, - GLsizei length, const GLchar *msg, const void *data ) +/* + * Prints verbose human-readable debug messages + * + * @param source, XXX + * type, XXX + * id, XXX + * severity, XXX + * length, XXX + * msg, XXX + * data, XXX + * + * @return void + */ +static void graphics_debug_callback(GLenum source, GLenum type, GLuint id, + GLenum severity, GLsizei length, + const GLchar *msg, const void *data) { const char *errsource; const char *errtype; @@ -507,3 +166,478 @@ void graphics_debug_callback( GLenum source, GLenum type, GLuint id, GLenum seve errseverity, string, errtype, errsource, msg); } +/* + * Initializes an identity matrix + * + * @param res, target ptr + * + * @return void + */ +static inline void compute_i(float *res) +{ + /* initialize to the identity matrix */ + res[0] = 1.f; res[4] = 0.f; res[8] = 0.f; res[12] = 0.f; + res[1] = 0.f; res[5] = 1.f; res[9] = 0.f; res[13] = 0.f; + res[2] = 0.f; res[6] = 0.f; res[10] = 1.f; res[14] = 0.f; + res[3] = 0.f; res[7] = 0.f; res[11] = 0.f; res[15] = 1.f; +} + +/* + * Computes the projection matrix + * + * @param res, target ptr + * phi, XXX + * theta, XXX + * psi, XXX + * + * @return void + */ +static inline void compute_mvp(float *res, float phi, float theta, float psi) +{ + float x = phi *(G_PI / 180.f); + float y = theta *(G_PI / 180.f); + float z = psi *(G_PI / 180.f); + float c1 = cosf(x), s1 = sinf(x); + float c2 = cosf(y), s2 = sinf(y); + float c3 = cosf(z), s3 = sinf(z); + float c3c2 = c3 * c2; + float s3c1 = s3 * c1; + float c3s2s1 = c3 * s2 * s1; + float s3s1 = s3 * s1; + float c3s2c1 = c3 * s2 * c1; + float s3c2 = s3 * c2; + float c3c1 = c3 * c1; + float s3s2s1 = s3 * s2 * s1; + float c3s1 = c3 * s1; + float s3s2c1 = s3 * s2 * c1; + float c2s1 = c2 * s1; + float c2c1 = c2 * c1; + + compute_i(res); + + /* apply all three rotations using the three matrices: + * + * ⎡ c3 s3 0 ⎤ ⎡ c2 0 -s2 ⎤ ⎡ 1 0 0 ⎤ + * ⎢ -s3 c3 0 ⎥ ⎢ 0 1 0 ⎥ ⎢ 0 c1 s1 ⎥ + * ⎣ 0 0 1 ⎦ ⎣ s2 0 c2 ⎦ ⎣ 0 -s1 c1 ⎦ + */ + res[0] = c3c2; res[4] = s3c1 + c3s2s1; res[8] = s3s1 - c3s2c1; res[12] = 0.f; + res[1] = -s3c2; res[5] = c3c1 - s3s2s1; res[9] = c3s1 + s3s2c1; res[13] = 0.f; + res[2] = s2; res[6] = -c2s1; res[10] = c2c1; res[14] = 0.f; + res[3] = 0.f; res[7] = 0.f; res[11] = 0.f; res[15] = 1.f; +} + +/* + * Created and compile a shader + * + * @param type, shader type + * src, source code of shader + * + * @return shader id + */ +static inline GLuint create_shader(int type, const char *src) +{ + GLuint shader; + int status; + + shader = glCreateShader(type); + glShaderSource(shader, 1, &src, NULL); + glCompileShader(shader); + + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if(status == GL_FALSE) { + int log_len; + char *buffer; + + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len); + + buffer = g_malloc(log_len + 1); + glGetShaderInfoLog(shader, log_len, NULL, buffer); + + g_warning("Compile failure in %s shader:\n%s", + type == GL_VERTEX_SHADER ? "vertex" : "fragment", + buffer); + + g_free(buffer); + + glDeleteShader(shader); + + return 0; + } + + return shader; +} + +/* + * Find gl_area_entry from a gl_area ptr + * + * @param gl_area, ptr to the gl_area widget + * + * + * @return entry ptr + */ +static inline struct gl_area_entry *find_entry_from_ptr(void *ptr) +{ + struct gl_area_entry **cur; + + // Check uninitialized and quit + if (gl_area_array == NULL) return NULL; + + // Seek in array + cur = gl_area_array; + while(*cur) { + if ((*cur)->ptr == ptr) return *cur; + cur++; + } + + // Nothing found + return NULL; +} + +/* + * Find the gl_area_entry size + * + * @param void + * + * @return size of array + */ +static inline short gl_area_size(void) +{ + struct gl_area_entry **cur; + short size; + + // Check uninitialized and quit + if (gl_area_array == NULL) return 0; + + cur = gl_area_array; + while(*cur) { + cur++; + size++; + } + + return size; +} + +/* + * Initializes the shaders of a gl_area and link them to a program + * + * @param gl_area, ptr to the gl_area widget + * + * + * @return true if initialized + */ +static bool graphics_init_shaders(void *gl_area) +{ + char *file_content; + struct gl_area_entry *entry; + int status; + GLuint vertex, fragment; + GLuint program = 0; + GLuint m = 0; + GLuint v = 0; + GLuint p = 0; + + entry = find_entry_from_ptr(gl_area); + + if (entry == NULL) { + errno = EFAULT; + perror("gl_area_array entry not found"); + return false; + } + + // Load vertex shader file + if (read_file(VERTEX_SHADER_FILE, &file_content) == false) + return false; + vertex = create_shader(GL_VERTEX_SHADER, file_content); + free(file_content); + + if(vertex == 0) { + entry->program = 0; + return false; + } + + // Load fragment shader file + if (read_file(VERTEX_SHADER_FILE, &file_content) == false) + return false; + fragment = create_shader(GL_FRAGMENT_SHADER, file_content); + free(file_content); + + if(fragment == 0) { + glDeleteShader(vertex); + entry->program = 0; + return false; + } + + // Link shaders to program + program = glCreateProgram(); + glAttachShader(program, vertex); + glAttachShader(program, fragment); + + glLinkProgram(program); + + glGetProgramiv(program, GL_LINK_STATUS, &status); + + if(status == GL_FALSE) { + int log_len; + char *buffer; + + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_len); + + buffer = malloc(log_len + 1); + glGetProgramInfoLog(program, log_len, NULL, buffer); + + g_warning("Linking failure:\n%s", buffer); + + free(buffer); + + glDeleteProgram(program); + program = 0; + + goto out; + } + + /* Get the location of the "mvp" uniform */ + m = glGetUniformLocation(program, "model_matrix"); + v = glGetUniformLocation(program, "view_matrix"); + p = glGetUniformLocation(program, "projection_matrix"); + + glDetachShader(program, vertex); + glDetachShader(program, fragment); + +out: + glDeleteShader(vertex); + glDeleteShader(fragment); + + entry->program = program; + entry->m = m; + entry->v = v; + entry->p = p; + + return true; +} + +/* + * Initializes the buffer of a gl_area + * + * @param gl_area, ptr to the gl_area widget + * + * Note : indices[] is defined in graphics_cube.h + * + * @return void + */ +static void graphics_init_buffers(void *gl_area) +{ + GLuint vao, vertex_buffer, color_buffer; + struct gl_area_entry *entry; + int vertex_nb; + + entry = find_entry_from_ptr(gl_area); + entry->indices_nb = sizeof(indices) / sizeof(indices[0]); + vertex_nb = entry->indices_nb * 3; + printf("Initialization of buffers with %u indices (=%u vertex)\n", + entry->indices_nb, + vertex_nb); + printf("Real vertex number is %lu long\n", + sizeof(vertex_base) / sizeof(vertex_base[0])); + + // We only use one VAO, so we always keep it bound + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + // vertices + glGenBuffers(1, &vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_base), vertex_base, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // colors + glGenBuffers(1, &color_buffer); + glBindBuffer(GL_ARRAY_BUFFER, color_buffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(color_base), color_base, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + if(entry != NULL) { + entry->vao = vao; + entry->position_buffer = vertex_buffer; + entry->color_buffer = color_buffer; + } +} + +/* -------------------------------------------------------------------------- */ + +/* + * Initializes a gl_area + * + * @param gl_area, ptr to the gl_area widget + * + * @return true if initialized + */ +bool graphics_init(void *gl_area) +{ + short array_size; + + glEnable(GL_DEBUG_OUTPUT); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + glEnable(GL_MULTISAMPLE); + + // Check if not already initialized + if (find_entry_from_ptr(gl_area)) { + errno = EEXIST; + perror("gl_area_array already exists"); + return false; + } + + // Get actual array size + array_size = gl_area_size(); + + // If it does not exist, allocs it + if (gl_area_array == NULL) { + gl_area_array = calloc(2, sizeof(struct gl_area_entry *)); + + // check if an error occured during allocation + if (errno) { + perror("Not enough memory to allocate gl_area_array"); + return false; + } + + // If it does exist, reallocs it + } else { + gl_area_array = realloc(gl_area_array, + (array_size + 1) + * sizeof(struct gl_area_entry *)); + if (errno) { + perror("Not enough memory to allocate gl_area_array"); + return false; + } + } + + // Alloc new entry + gl_area_array[array_size] = calloc(1, sizeof(struct gl_area_entry)); + + if (errno) { + perror("Not enough memory to allocate gl_area_array entry"); + return false; + } + + gl_area_array[array_size]->ptr = gl_area; + + graphics_init_buffers(gl_area); + graphics_init_shaders(gl_area); + glDebugMessageCallback(graphics_debug_callback, NULL); + + return true; +} + +/* + * Draws the current buffer to a gl_area + * + * @param gl_area, ptr to the gl_area widget + * + * @return void + */ +void graphics_draw(void *gl_area) +{ + float m[16]; + float v[16]; + float p[16]; + struct gl_area_entry *entry; + + entry = find_entry_from_ptr(gl_area); + + if (entry == NULL) { + errno = EFAULT; + perror("gl_area_array entry not found"); + return; + } + + + /* Compute the model view projection matrix using the + * rotation angles specified through the GtkRange widgets + */ + compute_mvp(p, + rotation_angles[X_AXIS], + rotation_angles[Y_AXIS], + rotation_angles[Z_AXIS]); + compute_i(m); + compute_i(v); + + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + /* Use our shaders */ + glUseProgram(entry->program); + + /* Update the "mvp" matrix we use in the shader */ + glUniformMatrix4fv(entry->m, 1, GL_FALSE, &m[0]); + glUniformMatrix4fv(entry->v, 1, GL_FALSE, &v[0]); + glUniformMatrix4fv(entry->p, 1, GL_FALSE, &p[0]); + + /* Use the vertices in our buffer */ + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, entry->position_buffer); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0,(void*)0); + + // couleurs + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, entry->color_buffer); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0,(void*)0); + + glEnable(GL_DEPTH_TEST); + + glDrawElements(GL_LINES, entry->indices_nb, GL_UNSIGNED_BYTE, indices); + + /* We finished using the buffers and program */ + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glUseProgram(0); + + glFlush(); +} + +/* + * Shutdowns a gl_area + * + * @param gl_area, ptr to the gl_area widget + * + * @return true if success + */ +bool graphics_shutdown(void *gl_area) +{ + struct gl_area_entry *entry; + + entry = find_entry_from_ptr(gl_area); + + if (entry == NULL) { + errno = EFAULT; + perror("gl_area_array entry not found"); + return false; + } + + glDeleteBuffers(1, &entry->position_buffer); + glDeleteBuffers(1, &entry->color_buffer); + glDeleteProgram(entry->program); + + // Liberate + free(entry); + + if (errno) { + perror("Impossible to free the gl_area_array entry"); + return false; + } + + entry = NULL; + + gl_area_array = realloc(gl_area_array, + (gl_area_size()) + * sizeof(struct gl_area_entry *)); + if (errno) { + perror("Impossible to shrink gl_area_array"); + return false; + } + + return true; +} + +/* -------------------------------------------------------------------------- */ + diff --git a/src/ui/events.c b/src/ui/events.c index ca79755..14b3f03 100644 --- a/src/ui/events.c +++ b/src/ui/events.c @@ -28,6 +28,8 @@ #include "../../include/graphics.h" #include "../../include/ui.h" + + void on_about_action(GSimpleAction *action, GVariant *parameter, gpointer user_data) @@ -187,11 +189,14 @@ void on_toast_close_action(GSimpleAction *action, /* -------------------------------------------------------------------------- */ /* - * General events + * Graphical/view related events */ void on_axis_value_change(GtkAdjustment *adjustment, gpointer data) { + + // XXX set selon l'id de la GLArea + int axis = GPOINTER_TO_INT(data); g_assert(axis >= 0 && axis < N_AXIS); @@ -200,17 +205,17 @@ void on_axis_value_change(GtkAdjustment *adjustment, gpointer data) rotation_angles[axis] = gtk_adjustment_get_value(adjustment); /* Update the contents of the GL drawing area */ - gtk_widget_queue_draw(gl_area); + gtk_widget_queue_draw(gl_area); // XXX selon l'id de la GLArea } -gboolean on_render(GtkGLArea * area, GdkGLContext * context) +gboolean on_render(GtkGLArea *area, GdkGLContext *context) { if(gtk_gl_area_get_error(area) != NULL) - return FALSE; + return false; - graphics_draw(); + graphics_draw((void*)&area); - return TRUE; + return true; } @@ -222,7 +227,7 @@ void on_realize(GtkWidget *widget) if(gtk_gl_area_get_error(GTK_GL_AREA(widget)) != NULL) return; - graphics_init(); + graphics_init((void*)&widget); } /* We should tear down the state when unrealizing */ @@ -233,7 +238,7 @@ void on_unrealize(GtkWidget *widget) if(gtk_gl_area_get_error(GTK_GL_AREA(widget)) != NULL) return; - graphics_shutdown(); + graphics_shutdown((void*)&widget); } void on_close_window(GtkWidget *widget) @@ -241,6 +246,9 @@ void on_close_window(GtkWidget *widget) /* Reset the state */ gl_area = NULL; + + //XXX unset selon l'id de la GLArea + rotation_angles[X_AXIS] = 0.0; rotation_angles[Y_AXIS] = 0.0; rotation_angles[Z_AXIS] = 0.0; @@ -255,7 +263,7 @@ void on_openfile_response(GtkNativeDialog *native, int response, GemGraphClientWindow *self) { - g_autoptr (GFile) file; + g_autoptr(GFile) file; GtkFileChooser *chooser; if (response == GTK_RESPONSE_ACCEPT) { @@ -269,7 +277,7 @@ void on_openfile_response(GtkNativeDialog *native, self); } - g_object_unref (native); + g_object_unref(native); } void on_openfile_response_complete(GObject *source_object, diff --git a/src/ui/gemgraph.ui b/src/ui/gemgraph.ui index ff54b41..08ef9a8 100644 --- a/src/ui/gemgraph.ui +++ b/src/ui/gemgraph.ui @@ -70,38 +70,6 @@ - - - runlib_condition - Conditions - True - - - center - <b>label_runlib_condition</b> - True - 50 - 50 - - - - - - - runlib_rules - Rules - True - - - center - <b>label_runlib_rules</b> - True - 50 - 50 - - - - runlib_objects @@ -110,7 +78,39 @@ center - <b>label_runlib_objects</b> + <b>runlib_objects</b> + True + 50 + 50 + + + + + + + runlib_conditions_and_rules + Rules & Conds + True + + + center + <b>runlib_conditions_and_rules</b> + True + 50 + 50 + + + + + + + runlib_states + Savedstates + True + + + center + <b>runlib_states</b> True 50 50