/* * Gem-graph OpenGL experiments * * Desc: OpenGL utils header * * Copyright (C) 2023 Jean Sirmai * Copyright (C) 2023 Arien 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 . */ #include "../../include/base.h" #include "../../include/graphics.h" /* I'm standing on Earth (any planet or star or spinning spheroid, in fact) * and looking towards its North pole * * X - X = EAST - WEST = rouge - cyan * Y - Y = ZENITH - NADIR = vert - magenta * Z - Z = NORTH - SOUTH = bleu - jaune */ int draw_one_arrow_vertex (const int stack_id, int space_X_int, int space_Y_int, int space_Z_int, int weight, int site, int arrow_x, int arrow_y, int arrow_z) { float max = fmax(space_X_int, space_Y_int); max = fmax(max, space_Z_int); float i = arrow_x, j = arrow_y, k = arrow_z; float vx = (2 * i / space_X_int - 1) * space_X_int / max + (1 / max), vy = (2 * j / space_Y_int - 1) * space_Y_int / max + (1 / max), vz = (2 * k / space_Z_int - 1) * space_Z_int / max + (1 / max); graphics_draw_vertex(stack_id, vx, vy, vz); graphics_draw_color(stack_id, 0.4f, 0.4f, 0.4f); // réduit légèrement les longueurs des flèches // pour qu'elles s'arrêtent avant les faces des cubes GLfloat arrow_tip_padding = (1 / max) / 10; switch(site){ case EAST: graphics_draw_vertex (stack_id, vx - (site % 2 - 1) * (1 / max) + (site % 2 - 1) * arrow_tip_padding, vy, vz); graphics_draw_color (stack_id, 1.0f, 0.0f, 0.0f); break; case WEST: graphics_draw_vertex (stack_id, vx - (site % 2) * (1 / max) + (site % 2) * arrow_tip_padding, vy, vz); graphics_draw_color (stack_id, 0.0f, 1.0f, 1.0f); break; case ZENITH: graphics_draw_vertex (stack_id, vx, vy - (site % 2 - 1) * (1 / max) + (site % 2 - 1) * arrow_tip_padding, vz); graphics_draw_color(stack_id, 0.0f, 0.6f, 0.1f); break; case NADIR: graphics_draw_vertex (stack_id, vx, vy - (site % 2) * (1 / max) + (site % 2) * arrow_tip_padding, vz); graphics_draw_color(stack_id, 0.6f, 0.1f, 0.7f); break; case SOUTH: graphics_draw_vertex (stack_id, vx, vy, vz - (site % 2 + 1) * (1 / max) + (site % 2 + 1) * arrow_tip_padding); graphics_draw_color(stack_id, 0.05f, 0.4f, 1.0f); break; case NORTH: graphics_draw_vertex (stack_id, vx, vy, vz - (site % 2 - 2) * (1 / max) + (site % 2 - 2) * arrow_tip_padding); graphics_draw_color(stack_id, 1.0f, 1.0f, 0.0f); break; default: break; } return 2*3; } int draw_one_arrow_line(const int stack_id, int offset_vertex) { graphics_draw_line (stack_id, offset_vertex + 0, offset_vertex + 1); return 2; } /* * Depends on set_arrow() * Exchanges current and required site values * when the address of the arrow to be set is already occupied */ static int rewrite_arrow (const int stack_id, int address, int load, int site, int x, int y, int z) { struct graphic_stack_t *stack = &graphic_stack[stack_id]; printf("WARNING in rewrite_arrow() <> address or address / 5 ? (et pourquoi ?)\n"); stack->arrows_ptr[address].load = load; return 1; } /* * Depends on set_arrow() * Creates the arrow to be set with the required load at the required address */ static inline int create_arrow (int stack_id, int arrows_nb, int space_X, int space_Y, int space_Z, int load, int site, int x, int y, int z) { struct graphic_stack_t *stack = &graphic_stack[stack_id]; void *newptr = g_realloc(stack->arrows_ptr, (arrows_nb + 1) * sizeof(struct arrow_t)); if (newptr) stack->arrows_ptr = newptr; else perror("In create arrow, can't allocate new arrow buffer !\n"); stack->arrows_ptr[arrows_nb].load = load; stack->arrows_ptr[arrows_nb].site = site; stack->arrows_ptr[arrows_nb].x = x; stack->arrows_ptr[arrows_nb].y = y; stack->arrows_ptr[arrows_nb].z = z; draw_one_arrow_vertex(stack_id, space_X, space_Y, space_Z, load, site, x, y, z); draw_one_arrow_line (stack_id, stack->buffer_vertex_size / 3 - 2); arrows_nb ++; return arrows_nb; } /* * Depends on set_arrow() * Erases the arrow at the required address */ static inline int erase_arrow (const int stack_id, int arrows_nb, int arrow_address_in_list, GLuint site, GLint x, GLint y, GLint z) { struct graphic_stack_t *stack = &graphic_stack[stack_id]; if (arrows_nb == 0) assert (stack->buffer_lines_size == stack->buffer_lines_0_arrow); if (arrows_nb == 0) { stack->buffer_lines_size = stack->buffer_lines_0_arrow; return 0; } assert (arrows_nb); arrows_nb --; if (arrow_address_in_list < arrows_nb) { stack->arrows_ptr[arrow_address_in_list].load = stack->arrows_ptr[arrows_nb].load; stack->arrows_ptr[arrow_address_in_list].site = stack->arrows_ptr[arrows_nb].site; stack->arrows_ptr[arrow_address_in_list].x = stack->arrows_ptr[arrows_nb].x; stack->arrows_ptr[arrow_address_in_list].y = stack->arrows_ptr[arrows_nb].y; stack->arrows_ptr[arrow_address_in_list].z = stack->arrows_ptr[arrows_nb].z; } for (long i = 0; i < 6; i++) stack->buffer_vertex_origin [stack->buffer_vertex_0_arrow + arrow_address_in_list * 6 + i] = stack->buffer_vertex_origin [stack->buffer_vertex_size - 6 + i]; for (long i = 0; i < 6; i++) stack->buffer_colors_origin [stack->buffer_colors_0_arrow + arrow_address_in_list * 6 + i] = stack->buffer_colors_origin [stack->buffer_colors_size - 6 + i]; stack->buffer_vertex_size -= 6; // <<< l'inverse de ce qui est fait dans : graphics_draw_vertex() stack->buffer_colors_size -= 6; // <<< l'inverse de ce qui est fait dans : graphics_draw_colors() stack->buffer_lines_size -= 2; // <<< l'inverse de ce qui est fait dans : graphics_draw_line() void *new_arrows_vertex_ptr = g_realloc(stack->buffer_vertex_origin, stack->buffer_vertex_size * sizeof(GLfloat)); if (new_arrows_vertex_ptr) stack->buffer_vertex_origin = new_arrows_vertex_ptr; else perror("In graphics.erase_arrow(), can't re_allocate for arrows vertex buffer.\n"); void *new_arrows_colors_ptr = g_realloc(stack->buffer_colors_origin, stack->buffer_colors_size * sizeof(GLfloat)); if (new_arrows_colors_ptr) stack->buffer_colors_origin = new_arrows_colors_ptr; else perror("In graphics.erase_arrow(), can't re_allocate for arrows colors buffer.\n"); /* Il ne faut pas réécrire ce qui suit: ces lignes dessinent maintenant à partir d'autres vertex */ /* void *new_arrows_lines_ptr = g_realloc(stack->buffer_lines_origin, stack->buffer_lines_size * sizeof(GLfloat)); */ /* if (new_arrows_lines_ptr) stack->buffer_lines_origin = new_arrows_lines_ptr; */ /* else perror("In graphics.erase_arrow(), can't re_allocate for arrows lines buffer.\n"); */ return arrows_nb; } /* * Creates or deletes an arrow or modify the load of an existing one * Acts both by writing the list of arrows : (struct arrow_t *arrows_ptr, int arrows_nb) * and by drawing in the global space * * @param arrows_ptr and arrows_nb before operation, * required load and address (site, x, y, z) * * IF there is no arrow at the required address, * AND IF the load is > 0, an arrow will be created. * * IF there is an arrow at the required address * AND IF the load is = 0, the existing arrow will be deleted. * * IF there is an arrow at the required address * AND IF the load is > 0, the load of the existing arrow will be modified. * * May not call any of these three functions IF : * - Current_weight of an arrow located at the requested address == requested_weight * - No arrow was found at the requested addres AND current_weight == requested_weight * * @return arrows_nb after operation */ int set_arrow (int stack_id, int arrows_nb, int space_X, int space_Y, int space_Z, int requested_weight, int site, int arrow_x, int arrow_y, int arrow_z) { struct graphic_stack_t *stack = &graphic_stack[stack_id]; int address = -1, current_weight = -1; for (int i = 0; i < arrows_nb; i++) if ((site == stack->arrows_ptr[i].site) && (arrow_x == stack->arrows_ptr[i].x) && (arrow_y == stack->arrows_ptr[i].y) && (arrow_z == stack->arrows_ptr[i].z)) { address = i; current_weight = stack->arrows_ptr[i].load; break; } assert (address <= arrows_nb); if (address == -1 && requested_weight > 0) return create_arrow (stack_id, arrows_nb, space_X, space_Y, space_Z, requested_weight, site, arrow_x, arrow_y, arrow_z); if (address >= 0 && requested_weight == 0) // address >= 0 if and only if arrows_nb > 0 return erase_arrow(stack_id, arrows_nb, address, site, arrow_x, arrow_y, arrow_z); if (address >= 0 && current_weight != requested_weight) { rewrite_arrow(stack_id, address, requested_weight, site, arrow_x, arrow_y, arrow_z); return arrows_nb; } return arrows_nb; }