286 lines
11 KiB
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;
|
||
|
}
|
||
|
|