/* * Gem-graph OpenGL experiments * * Desc: GL functions * * Copyright (C) 2023 Arthur Menges * Copyright (C) 2023 Adrien Bourmault * Copyright (C) 2023 Jean Sirmai * * 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 . */ #include #include #include "../../include/base.h" #include "../../include/ui.h" #include "../../include/parsing.h" #include "../../include/graphics.h" #define TEST 0 struct graphic_stack_t *graphic_stack = NULL; size_t graphic_stack_size = 0; int *free_stack_slot = NULL; size_t free_stack_slot_size = 0; /* * 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; const char *errseverity; const GLubyte *string; GLenum code; switch (source) { case GL_DEBUG_SOURCE_API: errsource = "API"; break; case GL_DEBUG_SOURCE_WINDOW_SYSTEM: errsource = "WINDOW SYSTEM"; break; case GL_DEBUG_SOURCE_SHADER_COMPILER: errsource = "SHADER COMPILER"; break; case GL_DEBUG_SOURCE_THIRD_PARTY: errsource = "THIRD PARTY"; break; case GL_DEBUG_SOURCE_APPLICATION: errsource = "APPLICATION"; break; case GL_DEBUG_SOURCE_OTHER: errsource = "UNKNOWN"; break; default: errsource = "UNKNOWN"; break; } switch (type) { case GL_DEBUG_TYPE_ERROR: errtype = "ERROR"; break; case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: errtype = "DEPRECATED BEHAVIOR";break; case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: errtype = "UNDEFINED BEHAVIOR"; break; case GL_DEBUG_TYPE_PORTABILITY: errtype = "PORTABILITY"; break; case GL_DEBUG_TYPE_PERFORMANCE: errtype = "PERFORMANCE"; break; case GL_DEBUG_TYPE_OTHER: errtype = "OTHER"; break; case GL_DEBUG_TYPE_MARKER: errtype = "MARKER"; break; default: errtype = "UNKNOWN"; break; } switch (severity) { case GL_DEBUG_SEVERITY_HIGH: errseverity = "CRITICAL"; break; case GL_DEBUG_SEVERITY_MEDIUM: errseverity = "ERROR"; break; case GL_DEBUG_SEVERITY_LOW: errseverity = "WARNING"; break; case GL_DEBUG_SEVERITY_NOTIFICATION: errseverity = "INFO"; break; default: errseverity = "UNKNOWN"; break; } code = glGetError(); string = gluErrorString(code); g_printerr("[%s] %s (%s) from %s: %s\n", errseverity, string, errtype, errsource, msg); } /* -------------------------------------------------------------------------- */ /* * Initializes graphical stack * * @param gl_area, ptr to the gl_area widget * * @return id if initialized */ int graphics_init(void *error_buffer) { int cur_id = 0; struct graphic_stack_t *stack; /* g_printerr("[debug] graphics_init()\n"); */ if (graphic_stack == NULL) { graphic_stack = g_malloc0(sizeof(struct graphic_stack_t)); graphic_stack_size = 1; /* g_printerr("[debug] graphics_init(): init graphic_stack @ %p\n", graphic_stack); */ } else { // Check if there are free slots if (free_stack_slot_size) { // We get the last free slot registered cur_id = free_stack_slot[free_stack_slot_size-1]; // Unregister it (ofc) free_stack_slot = g_realloc(free_stack_slot, free_stack_slot_size-- * sizeof(int)); } else { cur_id = graphic_stack_size; graphic_stack = g_realloc(graphic_stack, ++graphic_stack_size * sizeof(struct graphic_stack_t)); } } memset(&graphic_stack[cur_id], 0, sizeof(struct graphic_stack_t)); /* g_printerr("[debug] graphics_init() : graphic_stack (@0x%p) has %ld elements\n", */ /* graphic_stack, */ /* graphic_stack_size); */ stack = &graphic_stack[cur_id]; stack->id = cur_id; glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glEnable(GL_MULTISAMPLE); if (!graphics_init_shaders(cur_id)) return -1; //print_stack(cur_id); graphics_init_buffers(cur_id); glDebugMessageCallback(graphics_debug_callback, NULL); //print_stack(cur_id); return cur_id; } /* * Shutdowns a gl_area * * @param gl_area, ptr to the gl_area widget * * @return true if success */ bool graphics_shutdown(const int id, void *error_buffer) { struct graphic_stack_t *stack; if (id >= graphic_stack_size || graphic_stack_size == 0 || graphic_stack == NULL) return false; stack = &graphic_stack[id]; //XXX free(stack->arrows_ptr); stack->arrows_ptr = NULL; stack->arrows_nb = 0; glDeleteBuffers(1, &stack->position_buffer); glDeleteBuffers(1, &stack->color_buffer); glDeleteProgram(stack->program); g_free(stack->buffer_vertex_origin); g_free(stack->buffer_colors_origin); g_free(stack->buffer_lines_origin); g_free(stack->buffer_plans_origin); if (graphic_stack_size == 1) { free(graphic_stack); graphic_stack = NULL; graphic_stack_size = 0; } else { memset(&graphic_stack[id], 0, sizeof(struct graphic_stack_t)); free_stack_slot = g_realloc(free_stack_slot, ++free_stack_slot_size * sizeof(int)); free_stack_slot[free_stack_slot_size-1] = id; } return true; } /* TODO * #pragma omp parallel schedule(static, 12) * void __attribute__((optimize("no-unroll-loops"))) main_test_graphics (void) {} * // assert : space dimensions (x,y,z) > 0 // assert : arrows localization within space and sites // assert : no more than one arrow per address // notify : weights are replaced, NOT added (could be !) * * Init space and arrows (= initial state) * and allows ulterior creations, suppressions or modifications of the arrows[] array * * draws the space() * triggers set_arrows() that modifies the list () and draws arrows * * Initialisation du générateur pseudo-aléatoire * Attention, les vertex centraux de chaque unité d'espace (cube) * peuvent être redondants (max 6) */ void graphics_model_setup (const int stack_id) { /*------------------------------------------------------------------------*/ /* I N I T I A L D A T A S P E C I F I C A T I O N */ /*------------------------------------------------------------------------*/ struct graphic_stack_t *stack = &graphic_stack[stack_id]; char dimension; long space_X; long space_Y; long space_Z; long announced_arrows_nb; int density_max; char multiplicity; dimension = model_get_dim(); g_print("[GRAPH DEBUG] dim = %d\n", dimension); space_X = 1; space_Y = 1; space_Z = 1; switch(dimension) { case 3: space_Z = model_get_dim_value("z"); case 2: space_Y = model_get_dim_value("y"); // even in 1D, we must be able to see a grid if (!space_Y) space_Y = 1; case 1: space_X = model_get_dim_value("x"); if (!space_X) space_X = 1; default: break; } g_print("[GRAPH DEBUG] x = %ld\n", space_X); g_print("[GRAPH DEBUG] y = %ld\n", space_Y); g_print("[GRAPH DEBUG] z = %ld\n", space_Z); density_max = space_X * space_Y * space_Z; stack->arrows_nb = 0; multiplicity = model_get_multiplicity(); g_print("[GRAPH DEBUG] site_multiplicity = %ld\n", multiplicity); /*------------------------------------------------------------------------*/ /* S P A C E D R A W I N G */ /*------------------------------------------------------------------------*/ draw_space_ridges_vertex (stack_id, stack->buffer_vertex_size, space_X, space_Y, space_Z); draw_space_ridges_lines (stack_id); draw_grids_on_space_faces_vertex (stack_id, space_X, space_Y, space_Z); draw_grids_on_space_faces_lines (stack_id, stack->buffer_lines_size, space_X, space_Y, space_Z); stack->buffer_vertex_0_arrow = stack->buffer_vertex_size; stack->buffer_colors_0_arrow = stack->buffer_colors_size; stack->buffer_lines_0_arrow = stack->buffer_lines_size; /*------------------------------------------------------------------------*/ /* A R R O W S D R A W I N G */ /*------------------------------------------------------------------------*/ char state_id[30] = {0}; struct arrow_t arrow = {0}; assert(model_get_next_state(&state_id)); g_print("[GRAPH DEBUG] first state is = %s\n", state_id); announced_arrows_nb = model_get_state_arrows_count(state_id); g_print("[GRAPH DEBUG] announced_arrows_nb is = %ld\n", announced_arrows_nb); while (model_get_next_arrow(&arrow, &state_id, dimension)) { g_print("[GRAPH DEBUG] cur arrow has x = %d\n", arrow.x); stack->arrows_nb = set_arrow (stack_id, stack->arrows_nb, space_X, space_Y, space_Z, arrow.load, // load arrow.site, // site arrow.x, // x arrow.y, // y arrow.z); // z } if (stack->arrows_nb != announced_arrows_nb) g_printerr("ARGH : all the arrows have not been parsed !\n"); }