GTK4_GG_hack/gg/arrows.c

286 lines
11 KiB
C

/*
* Gem-graph OpenGL experiments
*
* Desc: OpenGL utils header
*
* Copyright (C) 2023 Jean Sirmai <jean@a-lec.org>
* Copyright (C) 2023 Arien Bourmault <neox@a-lec.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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;
}