GtkLevelBar < ?
This commit is contained in:
parent
feb8fd2ecf
commit
39cf432f6a
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph OpenGL experiments
|
||||||
|
*
|
||||||
|
* Desc: User interface functions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Arthur Menges <arthur.menges@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Adrien 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/ui.h"
|
||||||
|
|
||||||
|
struct _GemGraphClientApplication
|
||||||
|
{
|
||||||
|
GtkApplication parent_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (GemGraphClientApplication,
|
||||||
|
gem_graph_client_application,
|
||||||
|
GTK_TYPE_APPLICATION)
|
||||||
|
|
||||||
|
|
||||||
|
static GemGraphClientApplication *application;
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void ui_enable_action(const char *name) {
|
||||||
|
g_simple_action_set_enabled(
|
||||||
|
(GSimpleAction *)g_action_map_lookup_action(
|
||||||
|
G_ACTION_MAP(application),
|
||||||
|
name),
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_disable_action(const char *name) {
|
||||||
|
g_simple_action_set_enabled(
|
||||||
|
(GSimpleAction *)g_action_map_lookup_action(
|
||||||
|
G_ACTION_MAP(application),
|
||||||
|
name),
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Window actual presentation on screen
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void gem_graph_client_application_activate(GApplication *app)
|
||||||
|
{
|
||||||
|
GtkWindow *window;
|
||||||
|
|
||||||
|
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(app));
|
||||||
|
|
||||||
|
window = gtk_application_get_active_window(GTK_APPLICATION (app));
|
||||||
|
if (window == NULL)
|
||||||
|
window = g_object_new(GEM_GRAPH_CLIENT_TYPE_WINDOW,
|
||||||
|
"application", app,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
ui_set_stack(HOME_MODE);
|
||||||
|
|
||||||
|
gtk_window_present(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Action records are registered here
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void gem_graph_client_application_init(GemGraphClientApplication *self)
|
||||||
|
{
|
||||||
|
g_action_map_add_action_entries(G_ACTION_MAP(self),
|
||||||
|
app_actions,
|
||||||
|
G_N_ELEMENTS(app_actions),
|
||||||
|
self);
|
||||||
|
|
||||||
|
// Setup shortcuts
|
||||||
|
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
|
||||||
|
"app.quit",
|
||||||
|
(const char *[]) { "<primary>q", NULL });
|
||||||
|
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
|
||||||
|
"app.editmode",
|
||||||
|
(const char *[]) { "<primary>e", NULL });
|
||||||
|
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
|
||||||
|
"app.runmode",
|
||||||
|
(const char *[]) { "<primary>r", NULL });
|
||||||
|
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
|
||||||
|
"app.presentmode",
|
||||||
|
(const char *[]) { "<primary>p", NULL });
|
||||||
|
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
|
||||||
|
"app.savefile",
|
||||||
|
(const char *[]) { "<primary>s", NULL });
|
||||||
|
|
||||||
|
application = self;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Disable unneeded/inoperant actions
|
||||||
|
//
|
||||||
|
ui_disable_action("savefile");
|
||||||
|
ui_disable_action("closefile");
|
||||||
|
ui_disable_action("editmode");
|
||||||
|
ui_disable_action("runmode");
|
||||||
|
ui_disable_action("presentmode");
|
||||||
|
ui_disable_action("togglesidebar");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_send_notification(const char *message)
|
||||||
|
{
|
||||||
|
g_print("NOTIFICATION: %s\n", message);
|
||||||
|
|
||||||
|
g_application_send_notification(G_APPLICATION(application),
|
||||||
|
"notification",
|
||||||
|
g_notification_new(message)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static void gem_graph_client_application_class_init(
|
||||||
|
GemGraphClientApplicationClass *klass)
|
||||||
|
{
|
||||||
|
GApplicationClass *app_class = G_APPLICATION_CLASS(klass);
|
||||||
|
|
||||||
|
app_class->activate = gem_graph_client_application_activate;
|
||||||
|
}
|
||||||
|
|
||||||
|
GemGraphClientApplication *gem_graph_client_application_new(
|
||||||
|
const char *application_id,
|
||||||
|
GApplicationFlags flags)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(application_id != NULL, NULL);
|
||||||
|
|
||||||
|
return g_object_new(GEM_GRAPH_CLIENT_TYPE_APPLICATION,
|
||||||
|
"application-id", application_id,
|
||||||
|
"flags", flags,
|
||||||
|
NULL);
|
||||||
|
}
|
|
@ -0,0 +1,236 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph OpenGL experiments
|
||||||
|
*
|
||||||
|
* Desc: User interface functions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Arthur Menges <arthur.menges@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Adrien 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 <unistd.h>
|
||||||
|
#include <gtk-4.0/gtk/gtk.h>
|
||||||
|
#include <glib-2.0/glib.h>
|
||||||
|
|
||||||
|
#include "../../include/base.h"
|
||||||
|
#include "../../include/ui.h"
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static GemGraphClientWindow *window;
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
struct _GemGraphClientWindow
|
||||||
|
{
|
||||||
|
GtkApplicationWindow parent_instance;
|
||||||
|
|
||||||
|
/* Template widgets */
|
||||||
|
GtkHeaderBar *main_titlebar;
|
||||||
|
GtkStack *main_stack;
|
||||||
|
GtkStack *side_stack;
|
||||||
|
GtkPaned *main_paned;
|
||||||
|
GtkMenuButton *main_button_mode;
|
||||||
|
GtkToggleButton *main_button_sidebar;
|
||||||
|
GtkRevealer *toast_revealer;
|
||||||
|
GtkToggleButton *toast_close_button;
|
||||||
|
GtkLabel *toast_text;
|
||||||
|
GtkBox *control_zone;
|
||||||
|
GtkBox *run_glarea_box;
|
||||||
|
GtkBox *edition_glarea_box;
|
||||||
|
GtkBox *presentation_glarea_box;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_FINAL_TYPE (GemGraphClientWindow,
|
||||||
|
gem_graph_client_window,
|
||||||
|
GTK_TYPE_APPLICATION_WINDOW)
|
||||||
|
|
||||||
|
static void gem_graph_client_window_class_init(GemGraphClientWindowClass *klass)
|
||||||
|
{
|
||||||
|
gchar *contents;
|
||||||
|
gsize len;
|
||||||
|
GError *err;
|
||||||
|
GBytes *bytes;
|
||||||
|
|
||||||
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
|
||||||
|
|
||||||
|
if (g_file_get_contents("src/ui/gemgraph.ui", &contents, &len, &err) == FALSE)
|
||||||
|
g_error("error reading gemgraph.ui: %s", err->message);
|
||||||
|
|
||||||
|
bytes = g_bytes_new_take(contents, len);
|
||||||
|
gtk_widget_class_set_template(GTK_WIDGET_CLASS(klass), bytes);
|
||||||
|
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
main_titlebar);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
main_stack);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
side_stack);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
main_paned);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
main_button_mode);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
main_button_sidebar);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
toast_revealer);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
toast_close_button);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
toast_text);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
control_zone);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
run_glarea_box);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
edition_glarea_box);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
presentation_glarea_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gem_graph_client_window_init(GemGraphClientWindow *self)
|
||||||
|
{
|
||||||
|
gtk_widget_init_template(GTK_WIDGET(self));
|
||||||
|
window = self;
|
||||||
|
|
||||||
|
// Launch with sidebar off
|
||||||
|
ui_toggle_sidebar();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void ui_set_stack(int mode)
|
||||||
|
{
|
||||||
|
//g_printerr("[debug] ui_set_stack()\n");
|
||||||
|
|
||||||
|
if (window->main_stack == NULL) {
|
||||||
|
g_printerr("Can't find self->main_stack !\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (window->side_stack == NULL) {
|
||||||
|
g_printerr("Can't find self->side_stack !\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch on the first letter of the mode, because switch is soooo simple :)
|
||||||
|
switch(mode) {
|
||||||
|
case EDIT_MODE:
|
||||||
|
gtk_stack_set_visible_child_full(window->main_stack,
|
||||||
|
"edition",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_stack_set_visible_child_full(window->side_stack,
|
||||||
|
"edition",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_menu_button_set_icon_name(window->main_button_mode,
|
||||||
|
"document-edit-symbolic");
|
||||||
|
ui_setup_glarea(EDIT_MODE, GTK_WIDGET(window->edition_glarea_box));
|
||||||
|
break;
|
||||||
|
case RUN_MODE:
|
||||||
|
gtk_stack_set_visible_child_full(window->main_stack,
|
||||||
|
"run",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_stack_set_visible_child_full(window->side_stack,
|
||||||
|
"run",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_menu_button_set_icon_name(window->main_button_mode,
|
||||||
|
"system-run-symbolic");
|
||||||
|
ui_setup_glarea(RUN_MODE, GTK_WIDGET(window->run_glarea_box));
|
||||||
|
break;
|
||||||
|
case PRESENTATION_MODE:
|
||||||
|
gtk_stack_set_visible_child_full(window->main_stack,
|
||||||
|
"presentation",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_stack_set_visible_child_full(window->side_stack,
|
||||||
|
"presentation",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_menu_button_set_icon_name(window->main_button_mode,
|
||||||
|
"x-office-presentation-symbolic");
|
||||||
|
ui_setup_glarea(PRESENTATION_MODE,
|
||||||
|
GTK_WIDGET(window->presentation_glarea_box));
|
||||||
|
break;
|
||||||
|
case HOME_MODE:
|
||||||
|
gtk_stack_set_visible_child_full(window->main_stack,
|
||||||
|
"home",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_stack_set_visible_child_full(window->side_stack,
|
||||||
|
"home",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_paned_set_position(window->main_paned, 0);
|
||||||
|
gtk_menu_button_set_icon_name(window->main_button_mode,
|
||||||
|
"user-home-symbolic");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_send_internal_notification(const char *message)
|
||||||
|
{
|
||||||
|
if (window->toast_revealer == NULL) {
|
||||||
|
g_printerr("Can't find self->toast_overlay !\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->toast_text == NULL) {
|
||||||
|
g_printerr("Can't find self->toast_overlay !\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_label_set_label(window->toast_text, message);
|
||||||
|
gtk_revealer_set_reveal_child(window->toast_revealer, true);
|
||||||
|
g_printerr("%s\n", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_close_internal_notification(void)
|
||||||
|
{
|
||||||
|
if (window->toast_revealer == NULL) {
|
||||||
|
g_printerr("Can't find self->toast_overlay !\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->toast_text == NULL) {
|
||||||
|
g_printerr("Can't find self->toast_overlay !\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_revealer_set_reveal_child(window->toast_revealer, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ui_toggle_sidebar(void)
|
||||||
|
{
|
||||||
|
int position = gtk_paned_get_position(window->main_paned);
|
||||||
|
|
||||||
|
if (position != 0) {
|
||||||
|
gtk_paned_set_position(window->main_paned, 0);
|
||||||
|
} else {
|
||||||
|
gtk_paned_set_position(window->main_paned, 400);
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 174 KiB |
|
@ -0,0 +1,323 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph OpenGL experiments
|
||||||
|
*
|
||||||
|
* Desc: User interface functions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Adrien 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 <unistd.h>
|
||||||
|
#include <gtk-4.0/gtk/gtk.h>
|
||||||
|
#include <glib-2.0/glib.h>
|
||||||
|
|
||||||
|
#include "../../include/base.h"
|
||||||
|
#include "../../include/ui.h"
|
||||||
|
#include "../../include/graphics.h"
|
||||||
|
|
||||||
|
struct stack_index_t {
|
||||||
|
long stack_id;
|
||||||
|
void *container_widget;
|
||||||
|
void *gl_area;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct stack_index_t *stack_index = NULL;
|
||||||
|
size_t stack_index_size = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for stack entry and returns stack_id
|
||||||
|
*
|
||||||
|
* @params container_widget, generally the GtkBox that contains the GLArea
|
||||||
|
*
|
||||||
|
* @returns stack_id
|
||||||
|
*/
|
||||||
|
long ui_get_graphic_stack(void *container_widget)
|
||||||
|
{
|
||||||
|
// look for stack_index entry
|
||||||
|
for (int i = 0; i < stack_index_size; i++) {
|
||||||
|
if (stack_index[i].container_widget == (void *)container_widget) {
|
||||||
|
return stack_index[i].stack_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for stack entry and returns stack_id
|
||||||
|
*
|
||||||
|
* @params container_widget, generally the GtkBox that contains the GLArea
|
||||||
|
*
|
||||||
|
* @returns stack_id
|
||||||
|
*/
|
||||||
|
long ui_is_graphic_stack_ready(void *container_widget)
|
||||||
|
{
|
||||||
|
// look for stack_index entry
|
||||||
|
for (int i = 0; i < stack_index_size; i++) {
|
||||||
|
if (stack_index[i].container_widget == (void *)container_widget) {
|
||||||
|
return stack_index[i].stack_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for stack entry and initializes OpenGL for it
|
||||||
|
*
|
||||||
|
* @params container_widget, generally the GtkBox that contains the GLArea
|
||||||
|
*
|
||||||
|
* @returns bool, true if success
|
||||||
|
*/
|
||||||
|
bool ui_init_graphic_stack(void *container_widget, GError *error_buffer)
|
||||||
|
{
|
||||||
|
//g_printerr("[debug] ui_init_graphic_stack()\n");
|
||||||
|
|
||||||
|
//g_printerr("[debug] ui_init_graphic_stack() : target is %p\n", container_widget);
|
||||||
|
|
||||||
|
// look for stack_index entry
|
||||||
|
for (int i = 0; i < stack_index_size; i++) {
|
||||||
|
//g_printerr("[debug] ui_init_graphic_stack() : i is %d\n", i);
|
||||||
|
//g_printerr("[debug] ui_init_graphic_stack() : target would be %p\n",
|
||||||
|
//stack_index[i].container_widget);
|
||||||
|
if (stack_index[i].container_widget == (void *)container_widget) {
|
||||||
|
stack_index[i].stack_id = graphics_init(&error_buffer);
|
||||||
|
//g_printerr("[debug] ui_init_graphic_stack() : stack_id is %d\n",
|
||||||
|
//stack_index[i].stack_id);
|
||||||
|
if (stack_index[i].stack_id >= 0)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for stack entry and shutdowns OpenGL for it
|
||||||
|
*
|
||||||
|
* @params container_widget, generally the GtkBox that contains the GLArea
|
||||||
|
*
|
||||||
|
* @returns bool, true if success
|
||||||
|
*/
|
||||||
|
bool ui_shutdown_graphic_stack(void *container_widget, GError *error_buffer)
|
||||||
|
{
|
||||||
|
// look for stack_index entry
|
||||||
|
for (int i = 0; i < stack_index_size; i++) {
|
||||||
|
if (stack_index[i].container_widget == (void *)container_widget) {
|
||||||
|
if (graphics_shutdown(stack_index[i].stack_id,
|
||||||
|
&error_buffer) == false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
stack_index[i].stack_id = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ui_clean_stack_index(void)
|
||||||
|
{
|
||||||
|
// look for stack_index entry
|
||||||
|
for (int i = 0; i < stack_index_size; i++) {
|
||||||
|
stack_index[i].stack_id = 0;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for stack entry and triggers OpenGL for drawing
|
||||||
|
*
|
||||||
|
* @params container_widget, generally the GtkBox that contains the GLArea
|
||||||
|
*
|
||||||
|
* @returns bool, true if success
|
||||||
|
*/
|
||||||
|
bool ui_render_stack(GtkWidget *container_widget)
|
||||||
|
{
|
||||||
|
// look for stack_index entry
|
||||||
|
for (int i = 0; i < stack_index_size; i++) {
|
||||||
|
if (stack_index[i].container_widget == (void *)container_widget) {
|
||||||
|
graphics_draw(stack_index[i].stack_id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for stack entry and triggers OpenGL for drawing
|
||||||
|
*
|
||||||
|
* @params container_widget, generally the GtkBox that contains the GLArea
|
||||||
|
*
|
||||||
|
* @returns bool, true if success
|
||||||
|
*/
|
||||||
|
bool ui_update_axis_stack(GtkWidget *container_widget, int axis, int value)
|
||||||
|
{
|
||||||
|
// look for stack_index entry
|
||||||
|
for (int i = 0; i < stack_index_size; i++) {
|
||||||
|
if (stack_index[i].container_widget == (void *)container_widget) {
|
||||||
|
graphic_stack[stack_index[i].stack_id].rotation_angles[axis] = value;
|
||||||
|
gtk_widget_queue_draw((GtkWidget*)(stack_index[i].gl_area));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for every stack entry and shutdowns OpenGL for it
|
||||||
|
*
|
||||||
|
* @params void
|
||||||
|
*
|
||||||
|
* @returns bool, true if success
|
||||||
|
*/
|
||||||
|
void ui_shutdown_all_graphic_stacks(void)
|
||||||
|
{
|
||||||
|
// look for stack_index entry
|
||||||
|
for (int i = 0; i < stack_index_size; i++) {
|
||||||
|
graphics_shutdown(stack_index[i].stack_id, NULL);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creates a slider widget
|
||||||
|
*
|
||||||
|
* @params axis, meaning which axis we're building (for label)
|
||||||
|
*
|
||||||
|
* @returns GtkWidget*, pointer to the new widget
|
||||||
|
*/
|
||||||
|
GtkWidget *create_axis_slider(int axis)
|
||||||
|
{
|
||||||
|
GtkWidget *box, *label, *slider;
|
||||||
|
GtkAdjustment *adj;
|
||||||
|
const char *text;
|
||||||
|
|
||||||
|
box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||||
|
|
||||||
|
switch (axis) {
|
||||||
|
case X_AXIS:
|
||||||
|
text = "X";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Y_AXIS:
|
||||||
|
text = "Y";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Z_AXIS:
|
||||||
|
text = "Z";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
label = gtk_label_new(text);
|
||||||
|
gtk_box_append(GTK_BOX(box), label);
|
||||||
|
gtk_widget_show(label);
|
||||||
|
|
||||||
|
adj = gtk_adjustment_new(0.0, 0.0, 360.0, 1.0, 12.0, 0.0);
|
||||||
|
g_signal_connect(adj, "value-changed",
|
||||||
|
G_CALLBACK(on_axis_value_change),
|
||||||
|
(gpointer) label);
|
||||||
|
slider = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, adj);
|
||||||
|
gtk_box_append(GTK_BOX(box), slider);
|
||||||
|
gtk_widget_set_hexpand(slider, TRUE);
|
||||||
|
gtk_widget_show(slider);
|
||||||
|
|
||||||
|
gtk_widget_show(box);
|
||||||
|
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creates GLArea and indexes it
|
||||||
|
*
|
||||||
|
* @params target_mode, meaning which ui_stack we're on
|
||||||
|
* target_widget, meaning the box that will host the GLArea
|
||||||
|
*
|
||||||
|
* @returns bool, true if success
|
||||||
|
*/
|
||||||
|
bool ui_setup_glarea(int target_mode, GtkWidget *target_widget)
|
||||||
|
{
|
||||||
|
GtkWidget *gl_area;
|
||||||
|
|
||||||
|
////g_printerr("[debug] ui_setup_glarea()\n");
|
||||||
|
|
||||||
|
assert(target_widget);
|
||||||
|
|
||||||
|
////g_printerr("[debug] ui_setup_glarea() : target is %p\n", target_widget);
|
||||||
|
|
||||||
|
if (stack_index == NULL) {
|
||||||
|
stack_index = g_malloc(sizeof(struct stack_index_t));
|
||||||
|
stack_index_size = 1;
|
||||||
|
} else {
|
||||||
|
// look for stack_index entry
|
||||||
|
for (int i = 0; i < stack_index_size; i++) {
|
||||||
|
if (stack_index[i].container_widget == (void *)target_widget) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// create entry
|
||||||
|
stack_index =
|
||||||
|
g_realloc(stack_index,
|
||||||
|
++stack_index_size * sizeof(struct stack_index_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_area = GTK_WIDGET(gtk_gl_area_new());
|
||||||
|
assert(gl_area);
|
||||||
|
|
||||||
|
//gtk_widget_set_size_request(gl_area, 1000, 1000);
|
||||||
|
gtk_gl_area_set_auto_render(GTK_GL_AREA(gl_area), true);
|
||||||
|
gtk_widget_set_hexpand(gl_area, TRUE);
|
||||||
|
gtk_widget_set_vexpand(gl_area, TRUE);
|
||||||
|
//gtk_widget_set_halign(gl_area, GTK_ALIGN_CENTER);
|
||||||
|
//gtk_widget_set_valign(gl_area, GTK_ALIGN_CENTER);
|
||||||
|
|
||||||
|
// The main "draw" call for GtkGLArea
|
||||||
|
g_signal_connect(GTK_GL_AREA(gl_area),
|
||||||
|
"render",
|
||||||
|
G_CALLBACK(on_glarea_render), NULL);
|
||||||
|
|
||||||
|
g_signal_connect(gl_area,
|
||||||
|
"realize",
|
||||||
|
G_CALLBACK(on_glarea_realize), NULL);
|
||||||
|
|
||||||
|
g_signal_connect(gl_area,
|
||||||
|
"unrealize",
|
||||||
|
G_CALLBACK(on_glarea_unrealize), NULL);
|
||||||
|
|
||||||
|
stack_index[stack_index_size-1].container_widget =
|
||||||
|
(void*)target_widget;
|
||||||
|
|
||||||
|
stack_index[stack_index_size-1].gl_area = (void*)gl_area;
|
||||||
|
|
||||||
|
////g_printerr("[debug] ui_setup_glarea() : set target to %p\n", target_widget);
|
||||||
|
|
||||||
|
////g_printerr("[debug] ui_setup_glarea() : stack_index (@0x%p) had %ld elements\n",
|
||||||
|
//stack_index,
|
||||||
|
//stack_index_size);
|
||||||
|
|
||||||
|
gtk_box_append(GTK_BOX(target_widget), gl_area);
|
||||||
|
gtk_widget_show(GTK_WIDGET(gl_area));
|
||||||
|
|
||||||
|
// Create sliders
|
||||||
|
for(int i = 0; i < N_AXIS; i++)
|
||||||
|
gtk_box_append(GTK_BOX(target_widget), create_axis_slider(i));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph OpenGL experiments
|
||||||
|
*
|
||||||
|
* Desc: User interface functions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Arthur Menges <arthur.menges@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Adrien 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/ui.h"
|
||||||
|
|
||||||
|
struct _GemGraphClientApplication
|
||||||
|
{
|
||||||
|
GtkApplication parent_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (GemGraphClientApplication,
|
||||||
|
gem_graph_client_application,
|
||||||
|
GTK_TYPE_APPLICATION)
|
||||||
|
|
||||||
|
|
||||||
|
static GemGraphClientApplication *application;
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void ui_enable_action(const char *name) {
|
||||||
|
g_simple_action_set_enabled(
|
||||||
|
(GSimpleAction *)g_action_map_lookup_action(
|
||||||
|
G_ACTION_MAP(application),
|
||||||
|
name),
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_disable_action(const char *name) {
|
||||||
|
g_simple_action_set_enabled(
|
||||||
|
(GSimpleAction *)g_action_map_lookup_action(
|
||||||
|
G_ACTION_MAP(application),
|
||||||
|
name),
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Window actual presentation on screen
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void gem_graph_client_application_activate(GApplication *app)
|
||||||
|
{
|
||||||
|
GtkWindow *window;
|
||||||
|
|
||||||
|
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(app));
|
||||||
|
|
||||||
|
window = gtk_application_get_active_window(GTK_APPLICATION (app));
|
||||||
|
if (window == NULL)
|
||||||
|
window = g_object_new(GEM_GRAPH_CLIENT_TYPE_WINDOW,
|
||||||
|
"application", app,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
ui_set_stack(HOME_MODE);
|
||||||
|
|
||||||
|
gtk_window_present(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Action records are registered here
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void gem_graph_client_application_init(GemGraphClientApplication *self)
|
||||||
|
{
|
||||||
|
g_action_map_add_action_entries(G_ACTION_MAP(self),
|
||||||
|
app_actions,
|
||||||
|
G_N_ELEMENTS(app_actions),
|
||||||
|
self);
|
||||||
|
|
||||||
|
// Setup shortcuts
|
||||||
|
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
|
||||||
|
"app.quit",
|
||||||
|
(const char *[]) { "<primary>q", NULL });
|
||||||
|
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
|
||||||
|
"app.editmode",
|
||||||
|
(const char *[]) { "<primary>e", NULL });
|
||||||
|
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
|
||||||
|
"app.runmode",
|
||||||
|
(const char *[]) { "<primary>r", NULL });
|
||||||
|
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
|
||||||
|
"app.presentmode",
|
||||||
|
(const char *[]) { "<primary>p", NULL });
|
||||||
|
gtk_application_set_accels_for_action(GTK_APPLICATION(self),
|
||||||
|
"app.savefile",
|
||||||
|
(const char *[]) { "<primary>s", NULL });
|
||||||
|
|
||||||
|
application = self;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Disable unneeded/inoperant actions
|
||||||
|
//
|
||||||
|
ui_disable_action("savefile");
|
||||||
|
ui_disable_action("closefile");
|
||||||
|
ui_disable_action("editmode");
|
||||||
|
ui_disable_action("runmode");
|
||||||
|
ui_disable_action("presentmode");
|
||||||
|
ui_disable_action("togglesidebar");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_send_notification(const char *message)
|
||||||
|
{
|
||||||
|
g_print("NOTIFICATION: %s\n", message);
|
||||||
|
|
||||||
|
g_application_send_notification(G_APPLICATION(application),
|
||||||
|
"notification",
|
||||||
|
g_notification_new(message)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static void gem_graph_client_application_class_init(
|
||||||
|
GemGraphClientApplicationClass *klass)
|
||||||
|
{
|
||||||
|
GApplicationClass *app_class = G_APPLICATION_CLASS(klass);
|
||||||
|
|
||||||
|
app_class->activate = gem_graph_client_application_activate;
|
||||||
|
}
|
||||||
|
|
||||||
|
GemGraphClientApplication *gem_graph_client_application_new(
|
||||||
|
const char *application_id,
|
||||||
|
GApplicationFlags flags)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail(application_id != NULL, NULL);
|
||||||
|
|
||||||
|
return g_object_new(GEM_GRAPH_CLIENT_TYPE_APPLICATION,
|
||||||
|
"application-id", application_id,
|
||||||
|
"flags", flags,
|
||||||
|
NULL);
|
||||||
|
}
|
|
@ -0,0 +1,285 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph OpenGL experiments
|
||||||
|
*
|
||||||
|
* Desc: Base header
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Arthur Menges <arthur.menges@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Adrien 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <glib-2.0/glib.h>
|
||||||
|
//#define G_APPLICATION_DEFAULT_FLAGS 0
|
||||||
|
|
||||||
|
// Graphical axis
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
X_AXIS,
|
||||||
|
Y_AXIS,
|
||||||
|
Z_AXIS,
|
||||||
|
|
||||||
|
N_AXIS
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gem-graph modes
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
HOME_MODE,
|
||||||
|
RUN_MODE,
|
||||||
|
EDIT_MODE,
|
||||||
|
PRESENTATION_MODE,
|
||||||
|
|
||||||
|
N_MODE
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure describing an arrow
|
||||||
|
*/
|
||||||
|
struct arrow_t {
|
||||||
|
uint load;
|
||||||
|
uint site;
|
||||||
|
uint x;
|
||||||
|
uint y;
|
||||||
|
uint z;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read a file from filename into a provided buffer
|
||||||
|
*
|
||||||
|
* @param filename, file name
|
||||||
|
* contents, target ptr
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
static inline char *read_file(char *filename)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int filesize;
|
||||||
|
char *contents;
|
||||||
|
|
||||||
|
fd = open(filename, O_RDONLY);
|
||||||
|
if(fd < 0) {
|
||||||
|
printf("Couldn't read file: %s\n",filename);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
filesize = lseek(fd, 0, SEEK_END) + 1 ;
|
||||||
|
contents = g_malloc(filesize * sizeof(char));
|
||||||
|
assert (contents);
|
||||||
|
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
read(fd,contents,filesize);
|
||||||
|
|
||||||
|
contents[filesize-1] = '\0';
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define EAST 0 // + x rouge
|
||||||
|
#define WEST 1 // - x cyan
|
||||||
|
#define ZENITH 2 // + y vert
|
||||||
|
#define NADIR 3 // - y magenta
|
||||||
|
#define SOUTH 4 // + z bleu
|
||||||
|
#define NORTH 5 // - z jaune
|
|
@ -0,0 +1,295 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph OpenGL experiments
|
||||||
|
*
|
||||||
|
* Desc: GL functions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Adrien Bourmault <neox@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Jean Sirmai <jean@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 <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "../../include/graphics.h"
|
||||||
|
|
||||||
|
/* Prints the arrows[] array
|
||||||
|
*
|
||||||
|
* For each arrow the following parameters are displayed :
|
||||||
|
* - rank in the array
|
||||||
|
* - load (or weight)
|
||||||
|
* - coordinates in space (site, x, y, z)
|
||||||
|
*/
|
||||||
|
void print_arrows_array (struct arrow_t *arrows, int arrows_nb, int invoked_by)
|
||||||
|
{
|
||||||
|
printf(" [rank] load | site x y z (");
|
||||||
|
switch (invoked_by) {
|
||||||
|
case 0: printf("after deletion) arrows_nb : %d", arrows_nb); break;
|
||||||
|
case 1: printf("after creation) arrows_nb : %d", arrows_nb); break;
|
||||||
|
case 2: printf("after modification) arrows_nb : %d", arrows_nb); break;
|
||||||
|
case 3: printf("address >= 0 && current_weight == requested_weight)"); break;
|
||||||
|
case 4: printf("address == -1 && requested_weight == 0)"); break;
|
||||||
|
case 5: printf("print_user_choices)"); break;
|
||||||
|
case 6: printf("print_evolution)"); break;
|
||||||
|
case 7: printf("before deletion) arrows_nb : %d", arrows_nb); break;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < arrows_nb; i++)
|
||||||
|
printf("\n [%4d] = %2d | %2d, %2d, %2d, %2d", i, arrows[i].load,\
|
||||||
|
arrows[i].site, arrows[i].x, arrows[i].y, arrows[i].z);
|
||||||
|
if (arrows_nb == 0) printf("\n [NULL] ---- | ---- --- --- ---");
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Prints the initial user choices :
|
||||||
|
* - space dimension size and appearance (grids)
|
||||||
|
* - arrows[] array
|
||||||
|
* NB The space may be empty or saturated with arrows or any value in between
|
||||||
|
* Only one arrow per possible coordinates with a load max equal to ? TODO
|
||||||
|
*/
|
||||||
|
void print_user_choices(struct arrow_t *arrows, int max_arrows_nb, int arrows_nb,
|
||||||
|
int space_size_x, int space_size_y, int space_size_z,
|
||||||
|
int show_array, int show_space_design)
|
||||||
|
{
|
||||||
|
printf("model + user constraints :\tspace size x,y,z (%d,%d,%d)\tinitial (max) arrows nb : %d",\
|
||||||
|
space_size_x, space_size_y, space_size_z, max_arrows_nb);
|
||||||
|
|
||||||
|
if (show_space_design) printf(" (grilles alternées)");
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
if (show_array) print_arrows_array (arrows, arrows_nb, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prints the evolution after adding / removing arrows :
|
||||||
|
* - arrows[] array
|
||||||
|
* NB The space may be empty or saturated with arrows or any value in between
|
||||||
|
* Only one arrow per possible coordinates with a load max equal to ? TODO
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* print_evolution (arrows, added, mem, deleted, print_arrows_data);
|
||||||
|
*/
|
||||||
|
void print_evolution (struct arrow_t *arrows, int arrows_nb, int modified, int deleted, int show_array)
|
||||||
|
{
|
||||||
|
printf("evolution\t\t\t\t\t\t\tarrows nb > %6d\t (%d added / %d deleted) (modified : %d)\n",\
|
||||||
|
arrows_nb + modified - deleted * 2, modified - deleted, deleted, modified);
|
||||||
|
if (show_array) print_arrows_array (arrows, arrows_nb, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prints the arrows[] array
|
||||||
|
*
|
||||||
|
* For each arrow the following parameters are displayed :
|
||||||
|
* - rank in the array
|
||||||
|
* - weight (or load)
|
||||||
|
* - coordinates in space (site, x, y, z)
|
||||||
|
*/
|
||||||
|
void show_arrows_array_head(int one_batch_size, long nb_batches_specified, int verbose) {
|
||||||
|
printf("\n [rank] load | site x y z");
|
||||||
|
if (verbose) printf(" one batch size = %d nb_batches_specified = %ld",\
|
||||||
|
one_batch_size, nb_batches_specified);
|
||||||
|
}
|
||||||
|
void show_one_arrow_in_array(struct arrow_t *arrows, int i) {
|
||||||
|
printf("\n [%4d] = %2d | %2d, %2d, %2d, %2d",\
|
||||||
|
i, arrows[i].load, arrows[i].site, arrows[i].x, arrows[i].y, arrows[i].z);
|
||||||
|
}
|
||||||
|
void show_empty_arrows_array() {printf("\n [NULL] ---- | ---- --- --- ---");}
|
||||||
|
|
||||||
|
void show_arrows_array (struct arrow_t *arrows, int arrows_nb, int x, int y, int z)
|
||||||
|
{
|
||||||
|
show_arrows_array_head (0,0,0);
|
||||||
|
for (int i = 0; i < arrows_nb; i++)
|
||||||
|
show_one_arrow_in_array(arrows, i);
|
||||||
|
if (arrows_nb == 0) show_empty_arrows_array();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prints the initial user choices :
|
||||||
|
* - space dimension size and appearance (grids)
|
||||||
|
* - arrows[] array
|
||||||
|
* NB The space may be empty or saturated with arrows or any value in between
|
||||||
|
* To assert : Only one arrow per possible coordinates with a load max equal to ?
|
||||||
|
*/
|
||||||
|
void show_user_choices(long copy_nb_arrows_specified,
|
||||||
|
int space_size_x, int space_size_y, int space_size_z,
|
||||||
|
int prefer, int arbitrary, int one_batch_size)
|
||||||
|
{
|
||||||
|
printf("\nnb arrows specified = %ld", copy_nb_arrows_specified);
|
||||||
|
printf(" space size (x,y,z) = (%d,%d,%d)", space_size_x, space_size_y, space_size_z);
|
||||||
|
printf(" arbitrary = %d one_batch_size = %d", arbitrary, one_batch_size);
|
||||||
|
if (prefer == 0) printf(" prefer = %d <> show all grids", prefer);
|
||||||
|
if (prefer == 1) printf(" prefer = %d <> show no grid", prefer);
|
||||||
|
if (prefer > 1) printf(" show grids according rule (%d)", prefer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prints the result of the function set_arrow()
|
||||||
|
* and indicates the reasons of the choice (call) this function makes (see this function)
|
||||||
|
*/
|
||||||
|
#define TEST 0
|
||||||
|
void show_user_action(struct arrow_t *arrows, int arrows_nb, int address, int requested_weight,
|
||||||
|
int current_weight, int site, int x, int y, int z)
|
||||||
|
{
|
||||||
|
if (address == -1 && requested_weight > 0) { // *(arrows + i * 5 + 0)
|
||||||
|
printf("no such arrow found (%2d,%2d,%2d,%2d)", site, x, y, z); //arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4]);
|
||||||
|
if (! TEST) printf("\n "); else printf(" ");
|
||||||
|
printf("=> CREATE"); return;}
|
||||||
|
|
||||||
|
if (address >= 0 && requested_weight == 0) {
|
||||||
|
printf("arrow (%2d,%2d,%2d,%2d) found at address %2d; current_weight = %2d;", site, x, y, z, address, current_weight); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4], address/5, current_weight);
|
||||||
|
if (! TEST) printf("\n "); else printf(" ");
|
||||||
|
printf("=> ERASE"); return;}
|
||||||
|
|
||||||
|
if (address >= 0 && current_weight != requested_weight) {
|
||||||
|
printf("arrow (%2d,%2d,%2d,%2d) found at address %2d; current_weight = %2d;", site, x, y, z, address, current_weight); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4], address/5, current_weight);
|
||||||
|
if (! TEST) printf("\n "); else printf(" ");
|
||||||
|
printf("=> MODIFY"); return;}
|
||||||
|
|
||||||
|
if (address >= 0 && current_weight == requested_weight){
|
||||||
|
printf("arrow (%2d,%2d,%2d,%2d) found at address %2d;", site, x, y, z, address); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4], address/5);
|
||||||
|
if (! TEST) printf("\n "); else printf(" ");
|
||||||
|
printf("requested_weight == current_weight => END"); return;}
|
||||||
|
|
||||||
|
if (address == -1 && requested_weight == 0) {
|
||||||
|
printf("no such arrow found (%2d,%2d,%2d,%2d)", site, x, y, z); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4]);
|
||||||
|
if (! TEST) printf("\n "); else printf(" ");
|
||||||
|
printf("=> END"); return;}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prints vertex and lines buffers_states (sizes) at major one_batch_sizes and at the end of a session.
|
||||||
|
* Major one_batch_sizes are creation of grids and creation of arrows
|
||||||
|
* Arithmetic verification is provided at each one_batch_size
|
||||||
|
*/
|
||||||
|
void show_buffers_states(int space_X, int space_Y, int space_Z,
|
||||||
|
long nb_batches_specified, int one_batch_size,
|
||||||
|
int offset_after_grids, int buffer_vertex_size,
|
||||||
|
int buffer_lines_size_after_cubes, int buffer_lines_size)
|
||||||
|
{
|
||||||
|
int offset_after_arrows = buffer_vertex_size / 3, difference = offset_after_arrows - offset_after_grids;
|
||||||
|
|
||||||
|
printf("\n - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
|
||||||
|
|
||||||
|
printf("\n buffer_vertex_offset_after grids = %9d\t%9d = (x+1)*(y+1)*(z+1); <--> (x,y,z = %d,%d,%d)",\
|
||||||
|
offset_after_grids, (space_X + 1)*(space_Y + 1)*(space_Z + 1), space_X, space_Y, space_Z);
|
||||||
|
|
||||||
|
printf("\n buffer_vertex_offset_after arrows = %9d\t%9d = %d + %d; <--> %d = 12 x %d (%d cubes)",\
|
||||||
|
offset_after_arrows, offset_after_arrows, offset_after_grids,\
|
||||||
|
difference, difference, difference / 12, difference / 12);
|
||||||
|
|
||||||
|
printf("\n buffer_lines_offset after cubes = %9d\t%9d = 2 * (%dx%d + %dx%d + %dx%d); <--> 2 * (x*y + x*z + y*z)",\
|
||||||
|
buffer_lines_size_after_cubes, ((space_X+1) * (space_Y+1) + (space_X+1) * (space_Z+1) + (space_Y+1) * (space_Z+1)) * 2,
|
||||||
|
space_X+1, space_Y+1, space_X+1, space_Z+1, space_Y+1, space_Z+1);
|
||||||
|
|
||||||
|
printf("\n buffer_lines_offset after arrows = %9d\t%9d = %d + %d; <--> %d = 14 x %d (%d arrows drawned)",\
|
||||||
|
buffer_lines_size, buffer_lines_size, buffer_lines_size_after_cubes,\
|
||||||
|
buffer_lines_size - buffer_lines_size_after_cubes,\
|
||||||
|
buffer_lines_size - buffer_lines_size_after_cubes, (buffer_lines_size - buffer_lines_size_after_cubes) / 14,\
|
||||||
|
(buffer_lines_size - buffer_lines_size_after_cubes) / 14);
|
||||||
|
|
||||||
|
if (nb_batches_specified * one_batch_size == 0) printf("\n");
|
||||||
|
else printf("\n WARNING Arrows of the same address, whatever their weight, are drawn in superimposition. Check their list.");
|
||||||
|
|
||||||
|
printf("\n It happens that NOT all the specified arrows (%ld) = (%ld x %d) are drawned (%d) ! WHY ? (d = %ld)\n",\
|
||||||
|
nb_batches_specified * one_batch_size, nb_batches_specified, one_batch_size, (buffer_lines_size - buffer_lines_size_after_cubes) / 14,\
|
||||||
|
nb_batches_specified * one_batch_size - (buffer_lines_size - buffer_lines_size_after_cubes) / 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prints the result of the function set_arrow()
|
||||||
|
* and indicates the reasons of the choice (call) this function makes (see this function)
|
||||||
|
*/
|
||||||
|
void print_user_action(struct arrow_t *arrows, int arrows_nb, int address, int requested_weight,
|
||||||
|
int current_weight, int site, int x, int y, int z)
|
||||||
|
{
|
||||||
|
if (address == -1 && requested_weight > 0) { // *(arrows + i * 5 + 0)
|
||||||
|
printf("no such arrow found (%2d,%2d,%2d,%2d)", site, x, y, z); //arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4]);
|
||||||
|
if (! TEST) printf("\n "); else printf(" ");
|
||||||
|
printf("=> CREATE"); return;}
|
||||||
|
|
||||||
|
if (address >= 0 && requested_weight == 0) {
|
||||||
|
printf("arrow (%2d,%2d,%2d,%2d) found at address %2d; current_weight = %2d;", site, x, y, z, address, current_weight); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4], address/5, current_weight);
|
||||||
|
if (! TEST) printf("\n "); else printf(" ");
|
||||||
|
printf("=> ERASE"); return;}
|
||||||
|
|
||||||
|
if (address >= 0 && current_weight != requested_weight) {
|
||||||
|
printf("arrow (%2d,%2d,%2d,%2d) found at address %2d; current_weight = %2d;", site, x, y, z, address, current_weight); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4], address/5, current_weight);
|
||||||
|
if (! TEST) printf("\n "); else printf(" ");
|
||||||
|
printf("=> MODIFY"); return;}
|
||||||
|
|
||||||
|
if (address >= 0 && current_weight == requested_weight){
|
||||||
|
printf("arrow (%2d,%2d,%2d,%2d) found at address %2d;", site, x, y, z, address); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4], address/5);
|
||||||
|
if (! TEST) printf("\n "); else printf(" ");
|
||||||
|
printf("requested_weight == current_weight => END"); return;}
|
||||||
|
|
||||||
|
if (address == -1 && requested_weight == 0) {
|
||||||
|
printf("no such arrow found (%2d,%2d,%2d,%2d)", site, x, y, z); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4]);
|
||||||
|
if (! TEST) printf("\n "); else printf(" ");
|
||||||
|
printf("=> END"); return;}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static inline void print_buffers_array_head () {printf(" [rank] load | site x y z [address] buffer-vertex-1 buffer-vertex-2 buffer-lines\n");}
|
||||||
|
static inline void print_empty_buffers_array () {printf(" [NULL] ---- | ---- --- --- --- -1 --- --- ---\n");}
|
||||||
|
|
||||||
|
static void print_one_arrow_in_buffers (struct arrow_t *arrows,
|
||||||
|
GLfloat *buffer_vertex_origin, long buffer_vertex_0_arrow,
|
||||||
|
GLfloat *buffer_lines_origin, long buffer_lines_0_arrow,
|
||||||
|
int i, int arrows_nb, int address)
|
||||||
|
{
|
||||||
|
printf(" [%4d] = %2d | %2d, %2d, %2d, %2d, (%2d) %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %4f %4f\n",\
|
||||||
|
i,
|
||||||
|
arrows[i].load, arrows[i].site, arrows[i].x, arrows[i].y, arrows[i].z,
|
||||||
|
address,
|
||||||
|
|
||||||
|
buffer_vertex_origin [buffer_vertex_0_arrow + i * 6 + 0],
|
||||||
|
buffer_vertex_origin [buffer_vertex_0_arrow + i * 6 + 1],
|
||||||
|
buffer_vertex_origin [buffer_vertex_0_arrow + i * 6 + 2],
|
||||||
|
|
||||||
|
buffer_vertex_origin [buffer_vertex_0_arrow + i * 6 + 3],
|
||||||
|
buffer_vertex_origin [buffer_vertex_0_arrow + i * 6 + 4],
|
||||||
|
buffer_vertex_origin [buffer_vertex_0_arrow + i * 6 + 5],
|
||||||
|
|
||||||
|
buffer_lines_origin [buffer_lines_0_arrow + i * 2 + 0],
|
||||||
|
buffer_lines_origin [buffer_lines_0_arrow + i * 2 + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_vertex_and_lines_buffers (struct arrow_t *arrows_ptr, int arrows_nb,
|
||||||
|
GLfloat *buffer_vertex_origin, long buffer_vertex_0_arrow,
|
||||||
|
GLfloat *buffer_lines_origin, long buffer_lines_0_arrow,
|
||||||
|
int address, int requested_weight, int current_weight, int site, int x, int y, int z)
|
||||||
|
{
|
||||||
|
/* for (int i = 0; i < 6; i++) printf("%5.2f ", buffer_vertex_origin [buffer_vertex_0_arrow + i]); printf("\n"); */
|
||||||
|
/* for (int i = 0; i < 6; i++) printf("%5.2f ", buffer_lines_origin [buffer_lines_0_arrow + i]); printf("\n"); */
|
||||||
|
print_buffers_array_head ();
|
||||||
|
for (int i = 0; i < arrows_nb; i++)
|
||||||
|
print_one_arrow_in_buffers(arrows_ptr, buffer_vertex_origin, buffer_vertex_0_arrow,
|
||||||
|
buffer_lines_origin, buffer_lines_0_arrow, i, arrows_nb, address);
|
||||||
|
if (arrows_nb == 0) print_empty_buffers_array();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,207 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph OpenGL experiments
|
||||||
|
*
|
||||||
|
* Desc: GL functions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Adrien Bourmault <neox@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Jean Sirmai <jean@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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writes values to describe a vertex at (x,y,z) intoq the vertex buffer
|
||||||
|
*
|
||||||
|
* @param coords GLfloat(x,y,z)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <cglm/cglm.h>
|
||||||
|
#include "../../include/base.h"
|
||||||
|
#include "../../include/ui.h"
|
||||||
|
#include "../../include/graphics.h"
|
||||||
|
|
||||||
|
void graphics_draw_vertex (const int stack_id,
|
||||||
|
GLfloat x,
|
||||||
|
GLfloat y,
|
||||||
|
GLfloat z)
|
||||||
|
{
|
||||||
|
//g_printerr("stack_id is %d\n", stack_id);
|
||||||
|
//g_printerr("stack_id is %d\n", stack_id);
|
||||||
|
//g_printerr("graphic_stack is at %p\n", graphic_stack);
|
||||||
|
//g_printerr("graphic_stack[stack_id] is at %p\n", graphic_stack + stack_id);
|
||||||
|
volatile struct graphic_stack_t *stack = &graphic_stack[stack_id];
|
||||||
|
|
||||||
|
//g_printerr("Currently stack->buffer_vertex_origin @ %p\n", stack->buffer_vertex_origin);
|
||||||
|
|
||||||
|
//assert (stack->buffer_vertex_origin);
|
||||||
|
|
||||||
|
stack->buffer_vertex_origin =
|
||||||
|
g_realloc (stack->buffer_vertex_origin,
|
||||||
|
(stack->buffer_vertex_size + 3) * sizeof(GLfloat));
|
||||||
|
//print_stack(stack_id);
|
||||||
|
|
||||||
|
stack->buffer_vertex_origin[stack->buffer_vertex_size + 0] = x;
|
||||||
|
stack->buffer_vertex_origin[stack->buffer_vertex_size + 1] = y;
|
||||||
|
stack->buffer_vertex_origin[stack->buffer_vertex_size + 2] = z;
|
||||||
|
|
||||||
|
stack->buffer_vertex_size += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writes values to describe a color (r,g,b) into the color buffer
|
||||||
|
*
|
||||||
|
* @param color GLfloat(r,g,b)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void graphics_draw_color (const int stack_id,
|
||||||
|
GLfloat r,
|
||||||
|
GLfloat g,
|
||||||
|
GLfloat b)
|
||||||
|
{
|
||||||
|
struct graphic_stack_t *stack = &graphic_stack[stack_id];
|
||||||
|
|
||||||
|
stack->buffer_colors_origin = g_realloc (stack->buffer_colors_origin,
|
||||||
|
(stack->buffer_colors_size + 3) * sizeof(GLfloat));
|
||||||
|
|
||||||
|
assert (stack->buffer_colors_origin);
|
||||||
|
|
||||||
|
stack->buffer_colors_origin[stack->buffer_colors_size + 0] = r;
|
||||||
|
stack->buffer_colors_origin[stack->buffer_colors_size + 1] = g;
|
||||||
|
stack->buffer_colors_origin[stack->buffer_colors_size + 2] = b;
|
||||||
|
|
||||||
|
stack->buffer_colors_size += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writes values to describe a line from a to b into the line buffer
|
||||||
|
*
|
||||||
|
* @param coords GLuint (a,b)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void graphics_draw_line (const int stack_id,
|
||||||
|
GLuint a,
|
||||||
|
GLuint b)
|
||||||
|
{
|
||||||
|
struct graphic_stack_t *stack = &graphic_stack[stack_id];
|
||||||
|
|
||||||
|
stack->buffer_lines_origin = g_realloc (stack->buffer_lines_origin,
|
||||||
|
(stack->buffer_lines_size + 2) * sizeof(GLuint));
|
||||||
|
|
||||||
|
assert (stack->buffer_lines_origin);
|
||||||
|
|
||||||
|
stack->buffer_lines_origin[stack->buffer_lines_size + 0] = a;
|
||||||
|
stack->buffer_lines_origin[stack->buffer_lines_size + 1] = b;
|
||||||
|
|
||||||
|
stack->buffer_lines_size += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writes values to describe an (a,b,c) plan (triangle) into the plan buffer
|
||||||
|
*
|
||||||
|
* @param coords GLuint (a,b,c)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void graphics_draw_plan (const int stack_id,
|
||||||
|
GLuint a,
|
||||||
|
GLuint b,
|
||||||
|
GLuint c)
|
||||||
|
{
|
||||||
|
struct graphic_stack_t *stack = &graphic_stack[stack_id];
|
||||||
|
|
||||||
|
stack->buffer_plans_origin = g_realloc (stack->buffer_plans_origin,
|
||||||
|
(stack->buffer_plans_size + 3) * sizeof(GLuint));
|
||||||
|
|
||||||
|
assert (stack->buffer_plans_origin);
|
||||||
|
|
||||||
|
stack->buffer_plans_origin[stack->buffer_plans_size + 0] = a;
|
||||||
|
stack->buffer_plans_origin[stack->buffer_plans_size + 1] = b;
|
||||||
|
stack->buffer_plans_origin[stack->buffer_plans_size + 2] = c;
|
||||||
|
|
||||||
|
stack->buffer_plans_size += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draws the current buffer to a gl_area
|
||||||
|
*
|
||||||
|
* @param gl_area, ptr to the gl_area widget
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void graphics_draw(const int stack_id)
|
||||||
|
{
|
||||||
|
struct graphic_stack_t *stack = &graphic_stack[stack_id];
|
||||||
|
|
||||||
|
//g_printerr("[debug] graphics_draw() started\n");
|
||||||
|
|
||||||
|
//print_stack(stack_id);
|
||||||
|
|
||||||
|
GLint cur_viewport[4];
|
||||||
|
glGetIntegerv(GL_VIEWPORT, cur_viewport);
|
||||||
|
|
||||||
|
mat4 m = GLM_MAT4_IDENTITY_INIT;
|
||||||
|
glm_rotate_x(m, glm_rad(stack->rotation_angles[X_AXIS]), m);
|
||||||
|
glm_rotate_y(m, glm_rad(stack->rotation_angles[Y_AXIS]), m);
|
||||||
|
glm_rotate_z(m, glm_rad(stack->rotation_angles[Z_AXIS]), m);
|
||||||
|
|
||||||
|
mat4 v = GLM_MAT4_IDENTITY_INIT; // XXX define zoom and translations here ?
|
||||||
|
|
||||||
|
mat4 p = GLM_MAT4_IDENTITY_INIT;
|
||||||
|
//glm_ortho(-1.0f, +1.0f, -1.0f, +1.0f, -1.0f, +1.0f, p);
|
||||||
|
glm_ortho_default((float)cur_viewport[2] / (float)cur_viewport[3], p);
|
||||||
|
//glm_perspective_default((float)cur_viewport[2] / (float)cur_viewport[3], p);
|
||||||
|
|
||||||
|
/* Use our shaders */
|
||||||
|
glUseProgram(stack->program);
|
||||||
|
|
||||||
|
glClearColor(0, 0, 0, 1);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
/* Update the "mvp" matrix we use in the shader */
|
||||||
|
glUniformMatrix4fv(stack->m, 1, GL_FALSE, (float *)m);
|
||||||
|
glUniformMatrix4fv(stack->v, 1, GL_FALSE, (float *)v);
|
||||||
|
glUniformMatrix4fv(stack->p, 1, GL_FALSE, (float *)p);
|
||||||
|
|
||||||
|
/* Use the vertices in our buffer */
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, stack->position_buffer);
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0,(void*)0);
|
||||||
|
|
||||||
|
// couleurs
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, stack->color_buffer);
|
||||||
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0,(void*)0);
|
||||||
|
|
||||||
|
//glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
glDrawElements(GL_LINES, stack->buffer_lines_size, GL_UNSIGNED_INT, stack->buffer_lines_origin);
|
||||||
|
glDrawElements(GL_TRIANGLES, stack->buffer_plans_size, GL_UNSIGNED_INT, stack->buffer_plans_origin);
|
||||||
|
|
||||||
|
/* We finished using the buffers and program */
|
||||||
|
glDisableVertexAttribArray(0);
|
||||||
|
glDisableVertexAttribArray(1);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glUseProgram(0);
|
||||||
|
|
||||||
|
glFlush();
|
||||||
|
//g_printerr("[debug] graphics_draw() ended\n");
|
||||||
|
}
|
|
@ -0,0 +1,369 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph OpenGL experiments
|
||||||
|
*
|
||||||
|
* Desc: User interface functions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Arthur Menges <arthur.menges@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Adrien 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 <stdio.h>
|
||||||
|
|
||||||
|
#include "../../include/base.h"
|
||||||
|
#include "../../include/graphics.h"
|
||||||
|
#include "../../include/parsing.h"
|
||||||
|
#include "../../include/ui.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void on_about_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
static const char *authors[] = { "Adrien Bourmault (neox@a-lec.org)",
|
||||||
|
"Jean Sirmai (jean@a-lec.org)",
|
||||||
|
"Arthur Menges (arthur.menges@a-lec.org)",
|
||||||
|
NULL};
|
||||||
|
GemGraphClientApplication *self = user_data;
|
||||||
|
GtkWindow *window = NULL;
|
||||||
|
|
||||||
|
g_assert (GEM_GRAPH_CLIENT_IS_APPLICATION(self));
|
||||||
|
|
||||||
|
window = gtk_application_get_active_window(GTK_APPLICATION (self));
|
||||||
|
|
||||||
|
gtk_show_about_dialog(window,
|
||||||
|
"program-name", "Gem-graph",
|
||||||
|
"logo-icon-name", "application-x-executable",
|
||||||
|
"authors", authors,
|
||||||
|
"version", "0.1.0",
|
||||||
|
"copyright", "Copyright © 2023 Libre en Communs",
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_quit_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GemGraphClientApplication *self = user_data;
|
||||||
|
|
||||||
|
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
|
||||||
|
|
||||||
|
g_application_quit(G_APPLICATION(self));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_preferences_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GemGraphClientApplication *self = user_data;
|
||||||
|
|
||||||
|
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
|
||||||
|
|
||||||
|
ui_send_internal_notification("Not implemented !");
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_togglesidebar_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GemGraphClientApplication *self = user_data;
|
||||||
|
|
||||||
|
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
|
||||||
|
|
||||||
|
ui_toggle_sidebar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_editmode_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GemGraphClientApplication *self = user_data;
|
||||||
|
|
||||||
|
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
|
||||||
|
|
||||||
|
ui_set_stack(EDIT_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_runmode_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GemGraphClientApplication *self = user_data;
|
||||||
|
|
||||||
|
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
|
||||||
|
|
||||||
|
ui_set_stack(RUN_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_presentmode_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GemGraphClientApplication *self = user_data;
|
||||||
|
|
||||||
|
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
|
||||||
|
|
||||||
|
ui_set_stack(PRESENTATION_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_openfile_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GemGraphClientApplication *self = user_data;
|
||||||
|
|
||||||
|
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
|
||||||
|
|
||||||
|
// Create a new file selection dialog, using the "open" mode
|
||||||
|
GtkFileChooserNative *native =
|
||||||
|
gtk_file_chooser_native_new("Open File",
|
||||||
|
GTK_WINDOW(self),
|
||||||
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||||
|
"_Open",
|
||||||
|
"_Cancel");
|
||||||
|
|
||||||
|
// Connect the "response" signal of the file selection dialog;
|
||||||
|
// this signal is emitted when the user selects a file, or when
|
||||||
|
// they cancel the operation
|
||||||
|
g_signal_connect (native,
|
||||||
|
"response",
|
||||||
|
G_CALLBACK(on_openfile_response),
|
||||||
|
self);
|
||||||
|
|
||||||
|
// Present the dialog to the user
|
||||||
|
gtk_native_dialog_show (GTK_NATIVE_DIALOG (native));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_closefile_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GemGraphClientApplication *self = user_data;
|
||||||
|
|
||||||
|
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
|
||||||
|
|
||||||
|
model_shutdown();
|
||||||
|
|
||||||
|
ui_disable_action("closefile");
|
||||||
|
ui_disable_action("savefile");
|
||||||
|
ui_disable_action("runmode");
|
||||||
|
ui_disable_action("editmode");
|
||||||
|
ui_disable_action("presentmode");
|
||||||
|
ui_disable_action("togglesidebar");
|
||||||
|
ui_set_stack(HOME_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_savefile_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GemGraphClientApplication *self = user_data;
|
||||||
|
|
||||||
|
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_toast_close_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GemGraphClientApplication *self = user_data;
|
||||||
|
|
||||||
|
g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self));
|
||||||
|
|
||||||
|
ui_close_internal_notification();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Graphical/view related events
|
||||||
|
*/
|
||||||
|
|
||||||
|
void on_axis_value_change(GtkAdjustment *adjustment, gpointer data)
|
||||||
|
{
|
||||||
|
|
||||||
|
GtkWidget *slider = gtk_widget_get_parent(GTK_WIDGET(data));
|
||||||
|
GtkWidget *container_widget = gtk_widget_get_parent(GTK_WIDGET(slider));
|
||||||
|
|
||||||
|
const gchar *label_text = gtk_label_get_label(GTK_LABEL(data));
|
||||||
|
|
||||||
|
// THANKS ASCIIIII/Unicode/Whateverrr !
|
||||||
|
int axis = label_text[0] - 'X';
|
||||||
|
|
||||||
|
g_assert(axis >= 0 && axis < N_AXIS);
|
||||||
|
|
||||||
|
/* Update the rotation angle */
|
||||||
|
ui_update_axis_stack(container_widget,
|
||||||
|
axis,
|
||||||
|
gtk_adjustment_get_value(adjustment));
|
||||||
|
|
||||||
|
/* Update the contents of the GL drawing area */
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean on_glarea_render(GtkGLArea *area, GdkGLContext *context)
|
||||||
|
{
|
||||||
|
// Check if the widget is a glarea
|
||||||
|
if(gtk_gl_area_get_error(area) != NULL) {
|
||||||
|
ui_send_internal_notification("An OpenGL error occured !");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ui_render_stack(gtk_widget_get_parent(GTK_WIDGET(area))) == false) {
|
||||||
|
ui_send_internal_notification(
|
||||||
|
"Failed to render corresponding graphic stack !");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* We need to set up our state when we realize the GtkGLArea widget */
|
||||||
|
void on_glarea_realize(GtkWidget *widget)
|
||||||
|
{
|
||||||
|
GError *internal_error = NULL;
|
||||||
|
|
||||||
|
// Make the GL context current to be able to call the GL API
|
||||||
|
gtk_gl_area_make_current(GTK_GL_AREA(widget));
|
||||||
|
|
||||||
|
// Check if the widget is a glarea
|
||||||
|
if(gtk_gl_area_get_error(GTK_GL_AREA(widget)) != NULL) {
|
||||||
|
ui_send_internal_notification("An OpenGL error occured !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link graphical stack to widget
|
||||||
|
if (ui_init_graphic_stack(gtk_widget_get_parent(widget),
|
||||||
|
internal_error) == false) {
|
||||||
|
ui_send_internal_notification(
|
||||||
|
"Failed to link the graphic stack to widgets !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_gl_area_set_auto_render(GTK_GL_AREA(widget), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We should tear down the state when unrealizing */
|
||||||
|
void on_glarea_unrealize(GtkWidget *widget)
|
||||||
|
{
|
||||||
|
GError *internal_error = NULL;
|
||||||
|
|
||||||
|
// Make the GL context current to be able to call the GL API
|
||||||
|
gtk_gl_area_make_current(GTK_GL_AREA(widget));
|
||||||
|
|
||||||
|
// Check if the widget is a glarea
|
||||||
|
if(gtk_gl_area_get_error(GTK_GL_AREA(widget)) != NULL) {
|
||||||
|
ui_send_internal_notification("An OpenGL error occured !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy graphic stack
|
||||||
|
if (ui_shutdown_graphic_stack(gtk_widget_get_parent(widget),
|
||||||
|
internal_error) == false) {
|
||||||
|
ui_send_internal_notification(
|
||||||
|
"Failed to shutdown the graphic stack !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_close_window(GtkWidget *widget)
|
||||||
|
{
|
||||||
|
|
||||||
|
ui_shutdown_all_graphic_stacks();
|
||||||
|
ui_clean_stack_index();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Responses
|
||||||
|
*/
|
||||||
|
void on_openfile_response(GtkNativeDialog *native,
|
||||||
|
int response,
|
||||||
|
GemGraphClientWindow *self)
|
||||||
|
{
|
||||||
|
g_autoptr(GFile) file;
|
||||||
|
GtkFileChooser *chooser;
|
||||||
|
|
||||||
|
if (response == GTK_RESPONSE_ACCEPT) {
|
||||||
|
chooser = GTK_FILE_CHOOSER(native);
|
||||||
|
file = gtk_file_chooser_get_file(chooser);
|
||||||
|
|
||||||
|
// Load asynchroneously not to block control flow
|
||||||
|
g_file_load_contents_async (file,
|
||||||
|
NULL,
|
||||||
|
(GAsyncReadyCallback)ui_model_loading,
|
||||||
|
self);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref(native);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_model_loading(GObject *source_object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GemGraphClientWindow *self)
|
||||||
|
{
|
||||||
|
GFile *file = G_FILE(source_object);
|
||||||
|
|
||||||
|
char *content = NULL;
|
||||||
|
size_t length = 0;
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
char *basename = g_file_get_basename(file);
|
||||||
|
|
||||||
|
// Gives you the contents of the file as a byte array, or
|
||||||
|
// set the error argument
|
||||||
|
g_file_load_contents_finish(file,
|
||||||
|
result,
|
||||||
|
&content,
|
||||||
|
&length,
|
||||||
|
NULL,
|
||||||
|
&error);
|
||||||
|
|
||||||
|
// In case of error, print a warning to the standard error output
|
||||||
|
if (error != NULL) {
|
||||||
|
g_printerr("Unable to open “%s”: %s\n",
|
||||||
|
g_file_peek_path(file),
|
||||||
|
error->message);
|
||||||
|
ui_send_internal_notification("Unable to open file !");
|
||||||
|
g_free(error);
|
||||||
|
g_free(basename);
|
||||||
|
g_free(content);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (model_init(content, length, basename) == false) {
|
||||||
|
ui_send_internal_notification("Error while loading the model");
|
||||||
|
g_free(basename);
|
||||||
|
g_free(content);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_enable_action("closefile");
|
||||||
|
ui_enable_action("savefile");
|
||||||
|
ui_enable_action("runmode");
|
||||||
|
ui_enable_action("editmode");
|
||||||
|
ui_enable_action("presentmode");
|
||||||
|
ui_enable_action("togglesidebar");
|
||||||
|
ui_set_stack(RUN_MODE);
|
||||||
|
|
||||||
|
g_free(basename);
|
||||||
|
g_free(content);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,328 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph OpenGL experiments
|
||||||
|
*
|
||||||
|
* Desc: GL functions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Arthur Menges <arthur.menges@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Adrien Bourmault <neox@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Jean Sirmai <jean@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 <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#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");
|
||||||
|
}
|
|
@ -0,0 +1,314 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph OpenGL experiments
|
||||||
|
*
|
||||||
|
* Desc: OpenGL utils header
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Arthur Menges <arthur.menges@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Adrien Bourmault <neox@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Jean Sirmai <jean@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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "base.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <epoxy/gl.h>
|
||||||
|
#include <GL/glu.h>
|
||||||
|
#include <GL/glext.h>
|
||||||
|
#include <cglm/cglm.h>
|
||||||
|
|
||||||
|
#define VERTEX_SHADER_FILE "src/graphics/shaders/shader.vert"
|
||||||
|
#define FRAG_SHADER_FILE "src/graphics/shaders/shader.frag"
|
||||||
|
#define GL_TARGET_MAJOR_VERSION 0
|
||||||
|
#define GL_TARGET_MINOR_VERSION 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure describing a gl_area and its parameters, used to create a table
|
||||||
|
* of Gem-graph client current gl_areas
|
||||||
|
*/
|
||||||
|
struct graphic_stack_t {
|
||||||
|
|
||||||
|
int id;
|
||||||
|
int mode;
|
||||||
|
|
||||||
|
float rotation_angles[N_AXIS]; // Rotation angles on each axis
|
||||||
|
|
||||||
|
GLuint vao; // init_buffers
|
||||||
|
GLuint position_buffer; // shutdown, draw
|
||||||
|
GLuint color_buffer; // shutdown, draw
|
||||||
|
GLuint program; // shutdown, init_shaders, draw
|
||||||
|
GLuint m; // init_shaders, draw
|
||||||
|
GLuint v; // init_shaders, draw
|
||||||
|
GLuint p; // init_shaders, draw
|
||||||
|
|
||||||
|
struct arrow_t *arrows_ptr;
|
||||||
|
long arrows_nb;
|
||||||
|
|
||||||
|
GLfloat *buffer_vertex_origin;
|
||||||
|
GLfloat *buffer_colors_origin;
|
||||||
|
GLuint *buffer_lines_origin;
|
||||||
|
GLuint *buffer_plans_origin;
|
||||||
|
|
||||||
|
long buffer_vertex_size;
|
||||||
|
long buffer_colors_size;
|
||||||
|
long buffer_lines_size;
|
||||||
|
long buffer_plans_size;
|
||||||
|
|
||||||
|
long buffer_vertex_0_arrow;
|
||||||
|
long buffer_colors_0_arrow;
|
||||||
|
long buffer_lines_0_arrow;
|
||||||
|
long buffer_plans_0_arrow;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dynamic array of ptrs to dynamically allocated gl_area_entry
|
||||||
|
*/
|
||||||
|
extern struct graphic_stack_t *graphic_stack;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initializes a gl_area
|
||||||
|
*
|
||||||
|
* @param gl_area, ptr to the gl_area widget
|
||||||
|
*
|
||||||
|
* @return true if initialized
|
||||||
|
*/
|
||||||
|
int graphics_init(void *error_buffer);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draws the current buffer to a gl_area
|
||||||
|
*
|
||||||
|
* @param gl_area, ptr to the gl_area widget
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void graphics_draw(const int stack_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shutdowns a gl_area
|
||||||
|
*
|
||||||
|
* @param gl_area, ptr to the gl_area widget
|
||||||
|
*
|
||||||
|
* @return true if success
|
||||||
|
*/
|
||||||
|
bool graphics_shutdown(const int stack_id, void *error_buffer);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
bool graphics_init_shaders(const int stack_id);
|
||||||
|
|
||||||
|
/* Initializes the buffer of a gl_area
|
||||||
|
* Calls according to the user preferences
|
||||||
|
* @param gl_area, ptr to the gl_area widget
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void graphics_init_buffers(const int stack_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draws a vertex (x, y, z)
|
||||||
|
* if (console) prints (x, y, z) values to console
|
||||||
|
*
|
||||||
|
* @param GLfloat x, GLfloat y, GLfloat z
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void graphics_draw_vertex (const int stack_id,
|
||||||
|
GLfloat x,
|
||||||
|
GLfloat y,
|
||||||
|
GLfloat z);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draws the color (r, g, b) associated to a vertex
|
||||||
|
* if (console) prints (r, g, b) values to console
|
||||||
|
*
|
||||||
|
* @param GLfloat r, GLfloat g, GLfloat b
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void graphics_draw_color (const int stack_id, GLfloat r, GLfloat g, GLfloat b);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writes values to describe a line from a to b into the line buffer
|
||||||
|
*
|
||||||
|
* @param coords GLuint (a,b)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void graphics_draw_line (const int stack_id, GLuint a, GLuint b);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writes values to describe an (a,b,c) plan (triangle) into the plan buffer
|
||||||
|
*
|
||||||
|
* @param coords GLuint (a,b,c)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void graphics_draw_plan (const int stack_id, GLuint a, GLuint b, GLuint c);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Created and compile a shader
|
||||||
|
*
|
||||||
|
* @param type, shader type
|
||||||
|
* src, source code of shader
|
||||||
|
*
|
||||||
|
* @return shader id
|
||||||
|
*/
|
||||||
|
static inline GLuint create_shader(const int stack_id, 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);
|
||||||
|
assert (buffer);
|
||||||
|
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 void print_stack(int stack_id)
|
||||||
|
{
|
||||||
|
static int n = 0;
|
||||||
|
|
||||||
|
printf("\n[n=%d]***************", n);
|
||||||
|
|
||||||
|
printf("id = %d\tmode = %d\n",
|
||||||
|
graphic_stack[stack_id].id,
|
||||||
|
graphic_stack[stack_id].mode);
|
||||||
|
|
||||||
|
printf("rotation_angles = ");
|
||||||
|
for (int i = 0; i < N_AXIS; i++) {
|
||||||
|
printf("%f\t", graphic_stack[stack_id].rotation_angles[i]); // Rotation angles on each axis
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("vao = %d\n", graphic_stack[stack_id].vao);
|
||||||
|
printf("position_buffer = %d\n", graphic_stack[stack_id].position_buffer);
|
||||||
|
printf("color_buffer = %d\n", graphic_stack[stack_id].color_buffer);
|
||||||
|
printf("program = %d\n", graphic_stack[stack_id].program);
|
||||||
|
printf("m = %d\n", graphic_stack[stack_id].m);
|
||||||
|
printf("v = %d\n", graphic_stack[stack_id].v);
|
||||||
|
printf("p = %d\n", graphic_stack[stack_id].p);
|
||||||
|
|
||||||
|
printf("arrows_ptr = %p\n", graphic_stack[stack_id].arrows_ptr);
|
||||||
|
printf("arrows_nb = %ld\n", graphic_stack[stack_id].arrows_nb);
|
||||||
|
|
||||||
|
printf("buffer_vertex_origin = %p\n", graphic_stack[stack_id].buffer_vertex_origin);
|
||||||
|
printf("buffer_colors_origin = %p\n", graphic_stack[stack_id].buffer_colors_origin);
|
||||||
|
printf("buffer_lines_origin = %p\n", graphic_stack[stack_id].buffer_lines_origin);
|
||||||
|
printf("buffer_plans_origin = %p\n", graphic_stack[stack_id].buffer_plans_origin);
|
||||||
|
|
||||||
|
printf("buffer_vertex_size = %ld\n", graphic_stack[stack_id].buffer_vertex_size);
|
||||||
|
printf("buffer_colors_size = %ld\n", graphic_stack[stack_id].buffer_colors_size);
|
||||||
|
printf("buffer_lines_size = %ld\n", graphic_stack[stack_id].buffer_lines_size);
|
||||||
|
printf("buffer_plans_size = %ld\n", graphic_stack[stack_id].buffer_plans_size);
|
||||||
|
|
||||||
|
printf("buffer_vertex_0_arrow = %p\n", graphic_stack[stack_id].buffer_vertex_0_arrow);
|
||||||
|
printf("buffer_colors_0_arrow = %p\n", graphic_stack[stack_id].buffer_colors_0_arrow);
|
||||||
|
printf("buffer_lines_0_arrow = %p\n", graphic_stack[stack_id].buffer_lines_0_arrow);
|
||||||
|
printf("buffer_plans_0_arrow = %p\n", graphic_stack[stack_id].buffer_plans_0_arrow);
|
||||||
|
|
||||||
|
printf("********************\n");
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void graphics_model_setup (const int stack_id);
|
||||||
|
|
||||||
|
int draw_one_arrow_vertex (const int stack_id,
|
||||||
|
int space_X,
|
||||||
|
int space_Y,
|
||||||
|
int space_Z,
|
||||||
|
int weight,
|
||||||
|
int site,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int z);
|
||||||
|
|
||||||
|
int draw_one_arrow_line(const int stack_id,
|
||||||
|
int offset_vertex);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writes grid ridges to vertex and color buffers
|
||||||
|
*
|
||||||
|
* @param coords long (x,y,z), step_x, step_y, step_z
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
int draw_space_ridges_vertex (const int stack_id,
|
||||||
|
long offset_vertex,
|
||||||
|
long x,
|
||||||
|
long y,
|
||||||
|
long z);
|
||||||
|
|
||||||
|
int draw_space_ridges_lines (const int stack_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writes grid lines on space faces
|
||||||
|
*
|
||||||
|
* @param coords long (x,y,z)
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
long draw_grids_on_space_faces_vertex (const int stack_id,
|
||||||
|
long x,
|
||||||
|
long y,
|
||||||
|
long z);
|
||||||
|
|
||||||
|
long draw_grids_on_space_faces_lines (const int stack_id,
|
||||||
|
long offset_vertex,
|
||||||
|
long x,
|
||||||
|
long y,
|
||||||
|
long z);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph
|
||||||
|
*
|
||||||
|
* Desc: OpenGL grid functions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Jean Sirmai <jean@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Adrien 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 <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "../../include/base.h"
|
||||||
|
#include "../../include/ui.h"
|
||||||
|
#include "../../include/graphics.h"
|
||||||
|
|
||||||
|
int draw_space_ridges_vertex (const int stack_id,
|
||||||
|
long offset_vertex,
|
||||||
|
long x,
|
||||||
|
long y,
|
||||||
|
long z)
|
||||||
|
{
|
||||||
|
GLfloat max = fmax(x, y); max = fmax(max, z);
|
||||||
|
|
||||||
|
graphics_draw_vertex (stack_id, offset_vertex - x / max, offset_vertex - y / max, - z / max);
|
||||||
|
|
||||||
|
graphics_draw_vertex (stack_id, offset_vertex + x / max, offset_vertex - y / max, - z / max);
|
||||||
|
graphics_draw_vertex (stack_id, offset_vertex - x / max, offset_vertex + y / max, - z / max);
|
||||||
|
graphics_draw_vertex (stack_id, offset_vertex - x / max, offset_vertex - y / max, + z / max);
|
||||||
|
|
||||||
|
graphics_draw_vertex (stack_id, offset_vertex + x / max, offset_vertex + y / max, - z / max);
|
||||||
|
graphics_draw_vertex (stack_id, offset_vertex + x / max, offset_vertex - y / max, + z / max);
|
||||||
|
graphics_draw_vertex (stack_id, offset_vertex - x / max, offset_vertex + y / max, + z / max);
|
||||||
|
|
||||||
|
graphics_draw_vertex (stack_id, offset_vertex + x / max, + y / max, + z / max);
|
||||||
|
|
||||||
|
graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
|
||||||
|
graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
|
||||||
|
graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
|
||||||
|
graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
|
||||||
|
graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
|
||||||
|
graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
|
||||||
|
graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
|
||||||
|
graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f);
|
||||||
|
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
int draw_space_ridges_lines (const int stack_id)
|
||||||
|
{
|
||||||
|
graphics_draw_line (stack_id, 0, 1); graphics_draw_line (stack_id, 7, 4);
|
||||||
|
graphics_draw_line (stack_id, 0, 2); graphics_draw_line (stack_id, 7, 5);
|
||||||
|
graphics_draw_line (stack_id, 0, 3); graphics_draw_line (stack_id, 7, 6);
|
||||||
|
|
||||||
|
graphics_draw_line (stack_id, 1, 4); graphics_draw_line (stack_id, 2, 4);
|
||||||
|
graphics_draw_line (stack_id, 1, 5); graphics_draw_line (stack_id, 3, 5);
|
||||||
|
graphics_draw_line (stack_id, 2, 6); graphics_draw_line (stack_id, 3, 6);
|
||||||
|
|
||||||
|
return 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
long draw_grids_on_space_faces_vertex (const int stack_id,
|
||||||
|
long x,
|
||||||
|
long y,
|
||||||
|
long z)
|
||||||
|
{
|
||||||
|
float i, max = fmax(x, y); max = fmax(max, z);
|
||||||
|
|
||||||
|
for (i = 1; i < x; i++) {
|
||||||
|
|
||||||
|
graphics_draw_vertex (stack_id, (2 * i / x - 1) * x / max, - y / max, - z / max);
|
||||||
|
graphics_draw_vertex (stack_id, (2 * i / x - 1) * x / max, - y / max, z / max);
|
||||||
|
graphics_draw_vertex (stack_id, (2 * i / x - 1) * x / max, y / max, z / max);
|
||||||
|
graphics_draw_vertex (stack_id, (2 * i / x - 1) * x / max, y / max, - z / max);
|
||||||
|
|
||||||
|
graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
|
||||||
|
graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
|
||||||
|
graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
|
||||||
|
graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* offset_vertex += (x - 1) * 4; */ /* offset_colors += (x - 1) * 4; */
|
||||||
|
|
||||||
|
for (i = 1; i < y; i++) {
|
||||||
|
|
||||||
|
graphics_draw_vertex (stack_id, - x / max, (2 * i / y - 1) * y / max, - z / max);
|
||||||
|
graphics_draw_vertex (stack_id, - x / max, (2 * i / y - 1) * y / max, z / max);
|
||||||
|
graphics_draw_vertex (stack_id, x / max, (2 * i / y - 1) * y / max, z / max);
|
||||||
|
graphics_draw_vertex (stack_id, x / max, (2 * i / y - 1) * y / max, - z / max);
|
||||||
|
|
||||||
|
graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
|
||||||
|
graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
|
||||||
|
graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
|
||||||
|
graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* offset_vertex += (y - 1) * 4; */ /* offset_colors += (y - 1) * 4; */
|
||||||
|
|
||||||
|
for (i = 1; i < z; i++) {
|
||||||
|
|
||||||
|
graphics_draw_vertex (stack_id, - x / max, - y / max, (2 * i / z - 1) * z / max);
|
||||||
|
graphics_draw_vertex (stack_id, - x / max, y / max, (2 * i / z - 1) * z / max);
|
||||||
|
graphics_draw_vertex (stack_id, x / max, y / max, (2 * i / z - 1) * z / max);
|
||||||
|
graphics_draw_vertex (stack_id, x / max, - y / max, (2 * i / z - 1) * z / max);
|
||||||
|
|
||||||
|
graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
|
||||||
|
graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
|
||||||
|
graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
|
||||||
|
graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (x + y + z - 3) * 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
long draw_grids_on_space_faces_lines (const int stack_id,
|
||||||
|
long offset_vertex,
|
||||||
|
long x,
|
||||||
|
long y,
|
||||||
|
long z)
|
||||||
|
{
|
||||||
|
offset_vertex = offset_vertex / 3;
|
||||||
|
|
||||||
|
for (int i = 0; i < x - 1; i ++) {
|
||||||
|
|
||||||
|
graphics_draw_line (stack_id, offset_vertex + i * 4 + 1, offset_vertex + i * 4 + 2);
|
||||||
|
graphics_draw_line (stack_id, offset_vertex + i * 4 + 2, offset_vertex + i * 4 + 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset_vertex += (x - 1) * 4;
|
||||||
|
|
||||||
|
for (int i = 0; i < y - 1; i ++) {
|
||||||
|
|
||||||
|
graphics_draw_line (stack_id, offset_vertex + i * 4 + 2, offset_vertex + i * 4 + 3);
|
||||||
|
graphics_draw_line (stack_id, offset_vertex + i * 4 + 3, offset_vertex + i * 4 + 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
offset_vertex += (y - 1) * 4;
|
||||||
|
|
||||||
|
for (int i = 0; i < z - 1; i ++) {
|
||||||
|
|
||||||
|
graphics_draw_line (stack_id, offset_vertex + i * 4 + 0, offset_vertex + i * 4 + 1);
|
||||||
|
graphics_draw_line (stack_id, offset_vertex + i * 4 + 3, offset_vertex + i * 4 + 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (x + y + z - 3) * 4;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph OpenGL experiments
|
||||||
|
*
|
||||||
|
* Desc: GL functions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Arthur Menges <arthur.menges@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Adrien 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 <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "../../include/base.h"
|
||||||
|
#include "../../include/ui.h"
|
||||||
|
#include "../../include/graphics.h"
|
||||||
|
|
||||||
|
/* Initializes the buffer of a gl_area
|
||||||
|
* Calls according to the user preferences
|
||||||
|
* @param gl_area, ptr to the gl_area widget
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
void graphics_init_buffers(const int stack_id)
|
||||||
|
{
|
||||||
|
struct graphic_stack_t *stack = &graphic_stack[stack_id];
|
||||||
|
|
||||||
|
//XXX
|
||||||
|
graphics_model_setup(stack_id);
|
||||||
|
|
||||||
|
GLuint vao, vertex_buffer, color_buffer;
|
||||||
|
|
||||||
|
glGenBuffers(1, &vertex_buffer);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER,
|
||||||
|
stack->buffer_vertex_size *
|
||||||
|
sizeof(stack->buffer_vertex_origin[0]),
|
||||||
|
stack->buffer_vertex_origin,
|
||||||
|
GL_STATIC_DRAW);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
|
||||||
|
// colors
|
||||||
|
glGenBuffers(1, &color_buffer);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, color_buffer);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, stack->buffer_colors_size *
|
||||||
|
sizeof(stack->buffer_colors_origin[0]),
|
||||||
|
stack->buffer_colors_origin,
|
||||||
|
GL_STATIC_DRAW);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
// We only use one VAO, so we always keep it bound
|
||||||
|
glGenVertexArrays(1, &vao);
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
|
stack->vao = vao;
|
||||||
|
stack->position_buffer = vertex_buffer;
|
||||||
|
stack->color_buffer = color_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
bool graphics_init_shaders(const int stack_id)
|
||||||
|
{
|
||||||
|
struct graphic_stack_t *stack = &graphic_stack[stack_id];
|
||||||
|
char *vertex_shader;
|
||||||
|
char *fragment_shader;
|
||||||
|
int status;
|
||||||
|
GLuint vertex, fragment;
|
||||||
|
GLuint program = 0;
|
||||||
|
GLuint m = 0;
|
||||||
|
GLuint v = 0;
|
||||||
|
GLuint p = 0;
|
||||||
|
|
||||||
|
// Load vertex shader file
|
||||||
|
vertex_shader = read_file(VERTEX_SHADER_FILE);
|
||||||
|
if (vertex_shader == NULL)
|
||||||
|
return false;
|
||||||
|
vertex = create_shader(stack_id, GL_VERTEX_SHADER, vertex_shader);
|
||||||
|
|
||||||
|
if(vertex == 0) {
|
||||||
|
stack->program = 0;
|
||||||
|
g_free(vertex_shader);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load fragment shader file
|
||||||
|
fragment_shader = read_file(FRAG_SHADER_FILE);
|
||||||
|
if (fragment_shader == NULL)
|
||||||
|
return false;
|
||||||
|
fragment = create_shader(stack_id, GL_FRAGMENT_SHADER, fragment_shader);
|
||||||
|
|
||||||
|
if(fragment == 0) {
|
||||||
|
glDeleteShader(vertex);
|
||||||
|
stack->program = 0;
|
||||||
|
g_free(vertex_shader);
|
||||||
|
g_free(fragment_shader);
|
||||||
|
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 = g_malloc(log_len + 1);
|
||||||
|
assert(buffer);
|
||||||
|
glGetProgramInfoLog(program, log_len, NULL, buffer);
|
||||||
|
|
||||||
|
g_warning("Linking failure:\n%s", buffer);
|
||||||
|
|
||||||
|
g_free(buffer);
|
||||||
|
|
||||||
|
glDeleteProgram(program);
|
||||||
|
program = 0;
|
||||||
|
|
||||||
|
glDeleteShader(vertex);
|
||||||
|
glDeleteShader(fragment);
|
||||||
|
|
||||||
|
g_free(vertex_shader);
|
||||||
|
g_free(fragment_shader);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
glDeleteShader(vertex);
|
||||||
|
glDeleteShader(fragment);
|
||||||
|
|
||||||
|
stack->program = program;
|
||||||
|
stack->m = m;
|
||||||
|
stack->v = v;
|
||||||
|
stack->p = p;
|
||||||
|
|
||||||
|
g_free(vertex_shader);
|
||||||
|
g_free(fragment_shader);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,483 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph client
|
||||||
|
*
|
||||||
|
* Desc: Model parsing functions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Jean Sirmai <jean@a-lec.org>
|
||||||
|
* Copyright (C) 2024 Adrien 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 <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <libxml/tree.h>
|
||||||
|
#include <libxml/parser.h>
|
||||||
|
#include <libxml/xmlreader.h> // http://xmlsoft.org/examples/#parse1.c
|
||||||
|
// https://gnome.pages.gitlab.gnome.org/libxml2/devhelp/general.html
|
||||||
|
|
||||||
|
#include "../../include/base.h"
|
||||||
|
|
||||||
|
#define READ_SITE 1 << 0
|
||||||
|
#define READ_WEIGHT 1 << 1
|
||||||
|
#define READ_X 1 << 2
|
||||||
|
#define READ_Y 1 << 3
|
||||||
|
#define READ_Z 1 << 4
|
||||||
|
#define SUCCESSFUL_READ_ARROW_X (READ_SITE | READ_WEIGHT | READ_X)
|
||||||
|
#define SUCCESSFUL_READ_ARROW_XY (READ_SITE | READ_WEIGHT | READ_X | READ_Y)
|
||||||
|
#define SUCCESSFUL_READ_ARROW_XYZ (READ_SITE | READ_WEIGHT | READ_X | READ_Y | READ_Z)
|
||||||
|
|
||||||
|
static xmlDocPtr model;
|
||||||
|
static xmlHashTablePtr model_hashtable;
|
||||||
|
|
||||||
|
bool model_init(const char *content, size_t length, const char *basename)
|
||||||
|
{
|
||||||
|
xmlNode *node;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this initialize the library and check potential ABI mismatches
|
||||||
|
* between the version it was compiled for and the actual shared
|
||||||
|
* library used.
|
||||||
|
*/
|
||||||
|
LIBXML_TEST_VERSION
|
||||||
|
|
||||||
|
model = xmlReadMemory(content, length, basename, NULL, 0);
|
||||||
|
|
||||||
|
if (model == NULL ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = xmlDocGetRootElement(model);
|
||||||
|
|
||||||
|
if (node == NULL) {
|
||||||
|
g_printerr("Empty XML model !\n");
|
||||||
|
xmlFreeDoc(model);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xmlStrcmp(node->name, (xmlChar *) "gem-graph-model")) {
|
||||||
|
g_printerr("document of the wrong type, root node != gem-graph-model\n");
|
||||||
|
xmlFreeDoc(model);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
model_hashtable = xmlHashCreate(0);
|
||||||
|
|
||||||
|
if (model_hashtable == NULL) {
|
||||||
|
g_printerr("Can't create model hash table !\n");
|
||||||
|
xmlFreeDoc(model);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool model_shutdown(void)
|
||||||
|
{
|
||||||
|
xmlFreeDoc(model);
|
||||||
|
xmlHashFree(model_hashtable, NULL);
|
||||||
|
|
||||||
|
// Cleanup function for the XML library
|
||||||
|
xmlCleanupParser();
|
||||||
|
|
||||||
|
// This is to debug memory for regression tests
|
||||||
|
xmlMemoryDump();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
static inline xmlNodePtr getNextChild(xmlNodePtr node, xmlChar *last)
|
||||||
|
{
|
||||||
|
while (node != NULL && xmlStrcmp(node->name, last)) {
|
||||||
|
// //printf(" <>--- line n°%lu <%s>\n", xmlGetLineNo(node), node->name);
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xmlChar* splitStrAtSlash(xmlChar *toSplit)
|
||||||
|
{
|
||||||
|
toSplit = (xmlChar *)xmlStrchr(toSplit, '/');
|
||||||
|
toSplit = xmlStrsub (toSplit, 1, xmlStrlen(toSplit));
|
||||||
|
return toSplit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xmlChar* getFirstTag(xmlChar *path)
|
||||||
|
{
|
||||||
|
xmlChar *preop = path;
|
||||||
|
path = (xmlChar *)xmlStrchr(path, '/');
|
||||||
|
path = xmlStrsub (path, 1, xmlStrlen(path));
|
||||||
|
|
||||||
|
//printf("%s = %s + / + %s\n", preop,\
|
||||||
|
xmlStrsub (preop, 0, xmlStrlen(preop) - xmlStrlen(path) - 1), path);
|
||||||
|
|
||||||
|
return xmlStrsub (preop, 0, xmlStrlen(preop) - xmlStrlen(path) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline xmlChar* getLastTag(xmlChar *path)
|
||||||
|
{
|
||||||
|
while ((ulong)xmlStrchr (path, '/'))
|
||||||
|
path = splitStrAtSlash((xmlChar *)path);
|
||||||
|
|
||||||
|
// //printf("last tag in the path = <%s>\n", path);
|
||||||
|
return path; // which is no more the given path but only its last tag !
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
static xmlNodePtr model_get_node(xmlChar *path)
|
||||||
|
{
|
||||||
|
xmlNodePtr node;
|
||||||
|
xmlChar *extrait;
|
||||||
|
xmlChar *reste, *last, *affich;
|
||||||
|
|
||||||
|
// Lookup for node from path in hash table
|
||||||
|
node = xmlHashLookup(model_hashtable, path);
|
||||||
|
|
||||||
|
// Found a node in hash table
|
||||||
|
if (node) {
|
||||||
|
return node;
|
||||||
|
|
||||||
|
// no node found in hash table
|
||||||
|
} else {
|
||||||
|
reste = path;
|
||||||
|
affich = reste;
|
||||||
|
last = getLastTag(reste);
|
||||||
|
node = xmlDocGetRootElement(model);
|
||||||
|
|
||||||
|
while (xmlStrchr (reste, '/')) {
|
||||||
|
extrait = getFirstTag(reste);
|
||||||
|
reste = splitStrAtSlash((xmlChar *)reste);
|
||||||
|
node = node->xmlChildrenNode;
|
||||||
|
node = getNextChild(node, extrait);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node && xmlStrcmp(node->name, last)) {
|
||||||
|
node = node->xmlChildrenNode;
|
||||||
|
|
||||||
|
while (node && xmlStrcmp(node->name, last)) {
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
xmlHashAddEntry (model_hashtable, path, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
static inline long model_get_node_long_attrib(xmlNodePtr node, char *id)
|
||||||
|
{
|
||||||
|
xmlAttr *attribute;
|
||||||
|
xmlChar* value;
|
||||||
|
long ret_value;
|
||||||
|
|
||||||
|
if (node && node->properties) {
|
||||||
|
attribute = node->properties;
|
||||||
|
while(attribute && attribute->name && attribute->children) {
|
||||||
|
if (!xmlStrcmp(attribute->name, (const xmlChar *)id)) {
|
||||||
|
value = xmlNodeListGetString(node->doc, attribute->children, 1);
|
||||||
|
ret_value = strtol((char *)value, NULL, 0);
|
||||||
|
xmlFree(value);
|
||||||
|
return ret_value;
|
||||||
|
}
|
||||||
|
attribute = attribute->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool model_get_node_str_attrib(xmlNodePtr node,
|
||||||
|
char *id,
|
||||||
|
char *dest)
|
||||||
|
{
|
||||||
|
xmlAttr *attribute;
|
||||||
|
xmlChar* value;
|
||||||
|
|
||||||
|
if (node && node->properties) {
|
||||||
|
attribute = node->properties;
|
||||||
|
while(attribute && attribute->name && attribute->children) {
|
||||||
|
if (!xmlStrcmp(attribute->name, (const xmlChar *)id)) {
|
||||||
|
value = xmlNodeListGetString(node->doc, attribute->children, 1);
|
||||||
|
strcpy(dest, value);
|
||||||
|
xmlFree(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
attribute = attribute->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
char model_get_dim(void)
|
||||||
|
{
|
||||||
|
xmlAttr *attribute;
|
||||||
|
xmlChar* value;
|
||||||
|
xmlNodePtr node = model_get_node(
|
||||||
|
(xmlChar *)"parameters/space-param/dimension");
|
||||||
|
|
||||||
|
if (xmlHasProp (node, (xmlChar *) "z")) return 3;
|
||||||
|
if (xmlHasProp (node, (xmlChar *) "y")) return 2;
|
||||||
|
if (xmlHasProp (node, (xmlChar *) "x")) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long model_get_dim_value(const char *axis)
|
||||||
|
{
|
||||||
|
xmlAttr *attribute;
|
||||||
|
xmlChar *value;
|
||||||
|
long ret_value;
|
||||||
|
xmlNodePtr node = model_get_node(
|
||||||
|
(xmlChar *)"parameters/space-param/dimension");
|
||||||
|
|
||||||
|
return model_get_node_long_attrib(node, axis);
|
||||||
|
}
|
||||||
|
|
||||||
|
char model_get_multiplicity(void)
|
||||||
|
{
|
||||||
|
xmlAttr *attribute;
|
||||||
|
xmlChar* value;
|
||||||
|
xmlNodePtr node = model_get_node(
|
||||||
|
(xmlChar *)"parameters/space-param/site_multiplicity");
|
||||||
|
|
||||||
|
if (node->children)
|
||||||
|
if (node->children->content)
|
||||||
|
return (char)strtol((char *)node->children->content, NULL, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool model_get_next_state(char *new_state_id)
|
||||||
|
{
|
||||||
|
static xmlNodePtr cur_node = NULL;
|
||||||
|
xmlAttr *attribute;
|
||||||
|
xmlChar *value;
|
||||||
|
|
||||||
|
if (cur_node == NULL) {
|
||||||
|
// Get first state
|
||||||
|
cur_node = model_get_node((xmlChar *)"savedstates/state");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Get next state
|
||||||
|
if (cur_node->next)
|
||||||
|
cur_node = cur_node->next;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup in properties
|
||||||
|
if (model_get_node_str_attrib(cur_node, "id", new_state_id))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
cur_node = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
long model_get_state_arrows_count(const char *state_id)
|
||||||
|
{
|
||||||
|
xmlNodePtr cur_node = NULL;
|
||||||
|
xmlAttr *attribute;
|
||||||
|
long value = 0;
|
||||||
|
bool found = false;
|
||||||
|
char temp_char[25];
|
||||||
|
uint check = 0; // bit field checker
|
||||||
|
|
||||||
|
//printf("NEW CALL : cur_node = %p\n", cur_node);
|
||||||
|
|
||||||
|
assert(state_id);
|
||||||
|
|
||||||
|
// Get first state node
|
||||||
|
cur_node = model_get_node((xmlChar *)"savedstates/state");
|
||||||
|
|
||||||
|
// Lookup in properties
|
||||||
|
while (cur_node && cur_node->properties) {
|
||||||
|
attribute = cur_node->properties;
|
||||||
|
|
||||||
|
// Look for the id attribute
|
||||||
|
if (model_get_node_str_attrib(cur_node, "id", &temp_char)) {
|
||||||
|
if (!xmlStrcmp(temp_char, (const xmlChar *)state_id)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cur_node = cur_node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the state has been found
|
||||||
|
if (!found) {
|
||||||
|
cur_node = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Count arrows
|
||||||
|
if (cur_node->children) {
|
||||||
|
cur_node = cur_node->children;
|
||||||
|
while (cur_node) {
|
||||||
|
if (!xmlStrcmp(cur_node->name, (const xmlChar *)"arrow"))
|
||||||
|
value++;
|
||||||
|
cur_node = cur_node->next;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool model_get_next_arrow(struct arrow_t *new_arrow,
|
||||||
|
const char *state_id,
|
||||||
|
char dimension)
|
||||||
|
{
|
||||||
|
static xmlNodePtr cur_node = NULL;
|
||||||
|
xmlAttr *attribute;
|
||||||
|
xmlChar *value;
|
||||||
|
bool found = false;
|
||||||
|
char temp_char[25];
|
||||||
|
uint check = 0; // bit field checker
|
||||||
|
|
||||||
|
//printf("NEW CALL : cur_node = %p\n", cur_node);
|
||||||
|
|
||||||
|
assert(new_arrow);
|
||||||
|
assert(state_id);
|
||||||
|
|
||||||
|
if (cur_node == NULL) {
|
||||||
|
// Get first state node
|
||||||
|
cur_node = model_get_node((xmlChar *)"savedstates/state");
|
||||||
|
|
||||||
|
// Lookup in properties
|
||||||
|
while (cur_node && cur_node->properties) {
|
||||||
|
attribute = cur_node->properties;
|
||||||
|
|
||||||
|
// Look for the id attribute
|
||||||
|
if (model_get_node_str_attrib(cur_node, "id", &temp_char)) {
|
||||||
|
if (!xmlStrcmp(temp_char, (const xmlChar *)state_id)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cur_node = cur_node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the state has been found
|
||||||
|
if (!found) {
|
||||||
|
cur_node = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get first arrow
|
||||||
|
if (cur_node->children) {
|
||||||
|
cur_node = cur_node->children;
|
||||||
|
|
||||||
|
found = false;
|
||||||
|
while (cur_node && cur_node->name) {
|
||||||
|
if (!xmlStrcmp(cur_node->name, (const xmlChar *)"arrow")) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cur_node = cur_node->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the state has been found
|
||||||
|
if (!found) {
|
||||||
|
cur_node = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Get next arrow
|
||||||
|
found = false;
|
||||||
|
while (cur_node->next) {
|
||||||
|
cur_node = cur_node->next;
|
||||||
|
if (!xmlStrcmp(cur_node->name, (const xmlChar *)"arrow")) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the state has been found
|
||||||
|
if (!found) {
|
||||||
|
cur_node = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("DURING CALL : cur_node = %p\n", cur_node);
|
||||||
|
//printf("DURING CALL : cur_node->name = %s\n", cur_node->name);
|
||||||
|
|
||||||
|
// Lookup in properties
|
||||||
|
if (cur_node && cur_node->properties) {
|
||||||
|
attribute = cur_node->properties;
|
||||||
|
|
||||||
|
while(attribute && attribute->name && attribute->children) {
|
||||||
|
//printf("attr name : %s\n", attribute->name);
|
||||||
|
if (!xmlStrcmp(attribute->name, (const xmlChar *)"site")) {
|
||||||
|
value = xmlNodeListGetString(cur_node->doc, attribute->children, 1);
|
||||||
|
new_arrow->site = strtol((char *)value, NULL, 0);
|
||||||
|
xmlFree(value);
|
||||||
|
check |= READ_SITE;
|
||||||
|
}
|
||||||
|
if (!xmlStrcmp(attribute->name, (const xmlChar *)"weight")) {
|
||||||
|
value = xmlNodeListGetString(cur_node->doc, attribute->children, 1);
|
||||||
|
new_arrow->load = strtol((char *)value, NULL, 0);
|
||||||
|
xmlFree(value);
|
||||||
|
check |= READ_WEIGHT;
|
||||||
|
}
|
||||||
|
if (!xmlStrcmp(attribute->name, (const xmlChar *)"x")) {
|
||||||
|
value = xmlNodeListGetString(cur_node->doc, attribute->children, 1);
|
||||||
|
new_arrow->x = strtol((char *)value, NULL, 0);
|
||||||
|
xmlFree(value);
|
||||||
|
check |= READ_X;
|
||||||
|
}
|
||||||
|
if (!xmlStrcmp(attribute->name, (const xmlChar *)"y")) {
|
||||||
|
value = xmlNodeListGetString(cur_node->doc, attribute->children, 1);
|
||||||
|
new_arrow->y = strtol((char *)value, NULL, 0);
|
||||||
|
xmlFree(value);
|
||||||
|
check |= READ_Y;
|
||||||
|
}
|
||||||
|
if (!xmlStrcmp(attribute->name, (const xmlChar *)"z")) {
|
||||||
|
value = xmlNodeListGetString(cur_node->doc, attribute->children, 1);
|
||||||
|
new_arrow->z = strtol((char *)value, NULL, 0);
|
||||||
|
xmlFree(value);
|
||||||
|
check |= READ_Z;
|
||||||
|
}
|
||||||
|
attribute = attribute->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(dimension) {
|
||||||
|
case 3:
|
||||||
|
return (bool)(check & SUCCESSFUL_READ_ARROW_XYZ);
|
||||||
|
case 2:
|
||||||
|
return (bool)(check & SUCCESSFUL_READ_ARROW_XY);
|
||||||
|
case 1:
|
||||||
|
return (bool)(check & SUCCESSFUL_READ_ARROW_X);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cur_node = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph OpenGL experiments
|
||||||
|
*
|
||||||
|
* Desc: Model parsing header
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Arthur Menges <arthur.menges@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Adrien 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "../include/base.h"
|
||||||
|
|
||||||
|
bool model_init(const char *content, size_t length, const char *basename);
|
||||||
|
bool model_shutdown(void);
|
||||||
|
|
||||||
|
char model_get_dim(void);
|
||||||
|
long model_get_dim_value(const char *axis);
|
||||||
|
char model_get_multiplicity(void);
|
||||||
|
bool model_get_next_state(char *new_state_id);
|
||||||
|
bool model_get_next_arrow(struct arrow_t *new_arrow,
|
||||||
|
const char *state_id,
|
||||||
|
char dimension);
|
|
@ -0,0 +1,118 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gem-graph-model version="0.2.1">
|
||||||
|
|
||||||
|
<identity>
|
||||||
|
<name>Modèle de test</name>
|
||||||
|
|
||||||
|
<owner>Léontine Patinette</owner>
|
||||||
|
|
||||||
|
<owner_id>2</owner_id>
|
||||||
|
|
||||||
|
<date>1630000000</date>
|
||||||
|
|
||||||
|
<version>1.0</version>
|
||||||
|
|
||||||
|
<g_ref id="Cause" date="1630000000" author="toujours" lang="en">Ref</g_ref>
|
||||||
|
</identity>
|
||||||
|
|
||||||
|
<parameters id="texte" date="0" author="Léontine Trottine.">
|
||||||
|
<simulation>
|
||||||
|
<max_thread>0</max_thread>
|
||||||
|
<max_cycles>9</max_cycles>
|
||||||
|
|
||||||
|
</simulation>
|
||||||
|
|
||||||
|
<space-param>
|
||||||
|
<!-- loop_on_zero="true" anything moved before zero reenters at the end of space-->
|
||||||
|
<!-- loop_on_zero="false" anything moved before zero is lost-->
|
||||||
|
<!-- loop_on_max="true" anything moved beyond max reenters at the zero of space-->
|
||||||
|
<!-- loop_on_max="false" anything moved beyond max is lost-->
|
||||||
|
|
||||||
|
<dimension x="29"/>
|
||||||
|
|
||||||
|
<!-- Site_multiplicity = number of sites in a space unit. -->
|
||||||
|
<!-- Each site points towards a neighbouring space unit. -->
|
||||||
|
<!-- Several arrows can be stacked in the same site. -->
|
||||||
|
|
||||||
|
<site_multiplicity>3</site_multiplicity>
|
||||||
|
|
||||||
|
</space-param>
|
||||||
|
|
||||||
|
</parameters>
|
||||||
|
|
||||||
|
<!-- Model objects definition -->
|
||||||
|
|
||||||
|
<objects id="only dimers in this model" date="1630000000" author="inanimés,... âme ?">
|
||||||
|
<object id="a dimer" date="1630000000" author="Alphonse">
|
||||||
|
<arrow site="1" weight="1" x="0"/>
|
||||||
|
<arrow site="2" weight="1" x="1"/>
|
||||||
|
</object>
|
||||||
|
|
||||||
|
</objects>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Saved space description (initial space is sequence 0) -->
|
||||||
|
|
||||||
|
<savedstates id="texte" date="1630000000" author="Qui courrait dans l'herbe'">
|
||||||
|
<state id="initial" date="1630000000" author="Une souris verte">
|
||||||
|
<arrow site="0" weight="1" x="0"/>
|
||||||
|
<arrow site="1" weight="1" x="1"/>
|
||||||
|
<arrow site="0" weight="1" x="10"/>
|
||||||
|
<arrow site="1" weight="1" x="11"/>
|
||||||
|
<arrow site="0" weight="1" x="20"/>
|
||||||
|
<arrow site="1" weight="1" x="21"/>
|
||||||
|
|
||||||
|
<!-- Three dimers 1-1 are drawn in the global space
|
||||||
|
at locations (0,1) (10,11) and (20,21) -->
|
||||||
|
|
||||||
|
</state>
|
||||||
|
|
||||||
|
</savedstates>
|
||||||
|
|
||||||
|
<!-- Model transitions definition (rules) -->
|
||||||
|
<!-- In this version : <xs:sequence minOccurs="0" maxOccurs="unbounded">-->
|
||||||
|
<!-- Transitions should be edited by hand and written in a 'human-readable' format -->
|
||||||
|
|
||||||
|
<conditions id="random walk of dimers" date="1630000000" author="Zazard le lézard !">
|
||||||
|
|
||||||
|
<condition site="1" weight="1" node_id="1" parent="0" x="0"/>
|
||||||
|
<condition site="2" weight="1" node_id="2" parent="1" x="1"/>
|
||||||
|
<!-- as soon as conditions 1 and 2 are satisfied, a dimer is identified at atation (0,1). -->
|
||||||
|
|
||||||
|
<condition site="1" weight="0" node_id="3" parent="2" x="2"/>
|
||||||
|
<!-- as soon as condition 3 is satisfied,
|
||||||
|
the neighbouring space unit to East of the dimer is empty
|
||||||
|
and the dimer identified by conditions (1,2) can be moved to East. -->
|
||||||
|
|
||||||
|
<condition site="2" weight="0" node_id="4" parent="2" x="-1"/>
|
||||||
|
<!-- as soon as condition 4 is satisfied,
|
||||||
|
the neighbouring space unit to West of the dimer is empty
|
||||||
|
and the dimer identified by conditions (1,2) can be moved to West. -->
|
||||||
|
|
||||||
|
</conditions>
|
||||||
|
|
||||||
|
<transitions>
|
||||||
|
|
||||||
|
<transition id="move_a_dimer_to_east" date="1630000000" author="Pas moi..."
|
||||||
|
parent="3" probability="1">
|
||||||
|
|
||||||
|
<arrow site="1" weight="0" x="0"/>
|
||||||
|
<arrow site="2" weight="0" x="1"/>
|
||||||
|
<arrow site="1" weight="1" x="1"/>
|
||||||
|
<arrow site="2" weight="1" x="2"/>
|
||||||
|
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
<transition id="move_a_dimer_to_west" date="1630000000" author="Ni moi !"
|
||||||
|
parent="4" probability="1">
|
||||||
|
|
||||||
|
<arrow site="1" weight="0" x="0"/>
|
||||||
|
<arrow site="2" weight="0" x="1"/>
|
||||||
|
<arrow site="2" weight="1" x="0"/>
|
||||||
|
<arrow site="1" weight="1" x="1"/>
|
||||||
|
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
</transitions>
|
||||||
|
|
||||||
|
</gem-graph-model>
|
|
@ -0,0 +1,232 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph OpenGL experiments
|
||||||
|
*
|
||||||
|
* Desc: User interface header
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Arthur Menges <arthur.menges@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Adrien 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <gtk-4.0/gtk/gtk.h>
|
||||||
|
|
||||||
|
#include "../include/base.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define GEM_GRAPH_CLIENT_TYPE_WINDOW (gem_graph_client_window_get_type())
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (GemGraphClientWindow,
|
||||||
|
gem_graph_client_window,
|
||||||
|
GEM_GRAPH_CLIENT,
|
||||||
|
WINDOW,
|
||||||
|
GtkApplicationWindow)
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define GEM_GRAPH_CLIENT_TYPE_APPLICATION (gem_graph_client_application_get_type())
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (GemGraphClientApplication,
|
||||||
|
gem_graph_client_application,
|
||||||
|
GEM_GRAPH_CLIENT,
|
||||||
|
APPLICATION,
|
||||||
|
GtkApplication)
|
||||||
|
|
||||||
|
GemGraphClientApplication *gem_graph_client_application_new(const char *application_id,
|
||||||
|
GApplicationFlags flags);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
||||||
|
void ui_enable_action(const char *name);
|
||||||
|
|
||||||
|
void ui_disable_action(const char *name);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Actions
|
||||||
|
//
|
||||||
|
void on_about_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void on_quit_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void on_preferences_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void on_togglesidebar_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void on_editmode_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void on_runmode_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void on_presentmode_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void on_openfile_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void on_closefile_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void on_savefile_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
void on_toast_close_action(GSimpleAction *action,
|
||||||
|
GVariant *parameter,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
|
||||||
|
static const GActionEntry app_actions[] = {
|
||||||
|
{ "quit", on_quit_action, NULL, NULL, NULL },
|
||||||
|
{ "about", on_about_action, NULL, NULL, NULL },
|
||||||
|
{ "preferences", on_preferences_action, NULL, NULL, NULL },
|
||||||
|
{ "togglesidebar", on_togglesidebar_action, NULL, NULL, NULL },
|
||||||
|
{ "editmode", on_editmode_action, NULL, NULL, NULL },
|
||||||
|
{ "runmode", on_runmode_action, NULL, NULL, NULL },
|
||||||
|
{ "presentmode", on_presentmode_action, NULL, NULL, NULL },
|
||||||
|
{ "openfile", on_openfile_action, NULL, NULL, NULL },
|
||||||
|
{ "closefile", on_closefile_action, NULL, NULL, NULL },
|
||||||
|
{ "savefile", on_savefile_action, NULL, NULL, NULL },
|
||||||
|
{ "toastclose", on_toast_close_action, NULL, NULL, NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Actions responses
|
||||||
|
//
|
||||||
|
void on_openfile_response(GtkNativeDialog *native,
|
||||||
|
int response,
|
||||||
|
GemGraphClientWindow *self);
|
||||||
|
|
||||||
|
void ui_model_loading(GObject *source_object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GemGraphClientWindow *self);
|
||||||
|
|
||||||
|
//
|
||||||
|
// General events
|
||||||
|
//
|
||||||
|
void on_axis_value_change(GtkAdjustment *adjustment, gpointer data);
|
||||||
|
|
||||||
|
gboolean on_glarea_render(GtkGLArea * area, GdkGLContext * context);
|
||||||
|
|
||||||
|
void on_glarea_realize(GtkWidget *widget);
|
||||||
|
|
||||||
|
void on_glarea_unrealize(GtkWidget *widget);
|
||||||
|
|
||||||
|
void on_close_window(GtkWidget *widget);
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
//
|
||||||
|
// Window primitives
|
||||||
|
//
|
||||||
|
|
||||||
|
void ui_set_stack(int mode);
|
||||||
|
|
||||||
|
void ui_send_internal_notification(const char *message);
|
||||||
|
void ui_close_internal_notification(void);
|
||||||
|
void ui_toggle_sidebar();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Graphical stuff
|
||||||
|
//
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creates GLArea and indexes it
|
||||||
|
*
|
||||||
|
* @params target_mode, meaning which ui_stack we're on
|
||||||
|
* target_widget, meaning the box that will host the GLArea
|
||||||
|
*
|
||||||
|
* @returns bool, true if success
|
||||||
|
*/
|
||||||
|
bool ui_setup_glarea(int target_mode, GtkWidget *target_widget);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for stack entry and returns stack_id
|
||||||
|
*
|
||||||
|
* @params container_widget, generally the GtkBox that contains the GLArea
|
||||||
|
*
|
||||||
|
* @returns stack_id
|
||||||
|
*/
|
||||||
|
long ui_get_graphic_stack(void *container_widget);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for stack entry and initializes OpenGL for it
|
||||||
|
*
|
||||||
|
* @params container_widget, generally the GtkBox that contains the GLArea
|
||||||
|
*
|
||||||
|
* @returns bool, true if success
|
||||||
|
*/
|
||||||
|
bool ui_init_graphic_stack(void *container_widget, GError *error_buffer);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for stack entry and shutdowns OpenGL for it
|
||||||
|
*
|
||||||
|
* @params container_widget, generally the GtkBox that contains the GLArea
|
||||||
|
*
|
||||||
|
* @returns bool, true if success
|
||||||
|
*/
|
||||||
|
bool ui_shutdown_graphic_stack(void *container_widget, GError *error_buffer);
|
||||||
|
|
||||||
|
|
||||||
|
void ui_clean_stack_index(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for stack entry and triggers OpenGL for drawing
|
||||||
|
*
|
||||||
|
* @params container_widget, generally the GtkBox that contains the GLArea
|
||||||
|
*
|
||||||
|
* @returns bool, true if success
|
||||||
|
*/
|
||||||
|
bool ui_render_stack(GtkWidget *container_widget);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for every stack entry and shutdowns OpenGL for it
|
||||||
|
*
|
||||||
|
* @params void
|
||||||
|
*
|
||||||
|
* @returns bool, true if success
|
||||||
|
*/
|
||||||
|
void ui_shutdown_all_graphic_stacks(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look for stack entry and triggers OpenGL for drawing
|
||||||
|
*
|
||||||
|
* @params container_widget, generally the GtkBox that contains the GLArea
|
||||||
|
*
|
||||||
|
* @returns bool, true if success
|
||||||
|
*/
|
||||||
|
bool ui_update_axis_stack(GtkWidget *container_widget, int axis, int value);
|
||||||
|
|
|
@ -0,0 +1,236 @@
|
||||||
|
/*
|
||||||
|
* Gem-graph OpenGL experiments
|
||||||
|
*
|
||||||
|
* Desc: User interface functions
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Arthur Menges <arthur.menges@a-lec.org>
|
||||||
|
* Copyright (C) 2023 Adrien 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 <unistd.h>
|
||||||
|
#include <gtk-4.0/gtk/gtk.h>
|
||||||
|
#include <glib-2.0/glib.h>
|
||||||
|
|
||||||
|
#include "../../include/base.h"
|
||||||
|
#include "../../include/ui.h"
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
static GemGraphClientWindow *window;
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
struct _GemGraphClientWindow
|
||||||
|
{
|
||||||
|
GtkApplicationWindow parent_instance;
|
||||||
|
|
||||||
|
/* Template widgets */
|
||||||
|
GtkHeaderBar *main_titlebar;
|
||||||
|
GtkStack *main_stack;
|
||||||
|
GtkStack *side_stack;
|
||||||
|
GtkPaned *main_paned;
|
||||||
|
GtkMenuButton *main_button_mode;
|
||||||
|
GtkToggleButton *main_button_sidebar;
|
||||||
|
GtkRevealer *toast_revealer;
|
||||||
|
GtkToggleButton *toast_close_button;
|
||||||
|
GtkLabel *toast_text;
|
||||||
|
GtkBox *control_zone;
|
||||||
|
GtkBox *run_glarea_box;
|
||||||
|
GtkBox *edition_glarea_box;
|
||||||
|
GtkBox *presentation_glarea_box;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_FINAL_TYPE (GemGraphClientWindow,
|
||||||
|
gem_graph_client_window,
|
||||||
|
GTK_TYPE_APPLICATION_WINDOW)
|
||||||
|
|
||||||
|
static void gem_graph_client_window_class_init(GemGraphClientWindowClass *klass)
|
||||||
|
{
|
||||||
|
gchar *contents;
|
||||||
|
gsize len;
|
||||||
|
GError *err;
|
||||||
|
GBytes *bytes;
|
||||||
|
|
||||||
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
|
||||||
|
|
||||||
|
if (g_file_get_contents("src/ui/gemgraph.ui", &contents, &len, &err) == FALSE)
|
||||||
|
g_error("error reading gemgraph.ui: %s", err->message);
|
||||||
|
|
||||||
|
bytes = g_bytes_new_take(contents, len);
|
||||||
|
gtk_widget_class_set_template(GTK_WIDGET_CLASS(klass), bytes);
|
||||||
|
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
main_titlebar);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
main_stack);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
side_stack);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
main_paned);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
main_button_mode);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
main_button_sidebar);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
toast_revealer);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
toast_close_button);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
toast_text);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
control_zone);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
run_glarea_box);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
edition_glarea_box);
|
||||||
|
gtk_widget_class_bind_template_child(widget_class,
|
||||||
|
GemGraphClientWindow,
|
||||||
|
presentation_glarea_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gem_graph_client_window_init(GemGraphClientWindow *self)
|
||||||
|
{
|
||||||
|
gtk_widget_init_template(GTK_WIDGET(self));
|
||||||
|
window = self;
|
||||||
|
|
||||||
|
// Launch with sidebar off
|
||||||
|
ui_toggle_sidebar();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
void ui_set_stack(int mode)
|
||||||
|
{
|
||||||
|
//g_printerr("[debug] ui_set_stack()\n");
|
||||||
|
|
||||||
|
if (window->main_stack == NULL) {
|
||||||
|
g_printerr("Can't find self->main_stack !\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (window->side_stack == NULL) {
|
||||||
|
g_printerr("Can't find self->side_stack !\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch on the first letter of the mode, because switch is soooo simple :)
|
||||||
|
switch(mode) {
|
||||||
|
case EDIT_MODE:
|
||||||
|
gtk_stack_set_visible_child_full(window->main_stack,
|
||||||
|
"edition",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_stack_set_visible_child_full(window->side_stack,
|
||||||
|
"edition",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_menu_button_set_icon_name(window->main_button_mode,
|
||||||
|
"document-edit-symbolic");
|
||||||
|
ui_setup_glarea(EDIT_MODE, GTK_WIDGET(window->edition_glarea_box));
|
||||||
|
break;
|
||||||
|
case RUN_MODE:
|
||||||
|
gtk_stack_set_visible_child_full(window->main_stack,
|
||||||
|
"run",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_stack_set_visible_child_full(window->side_stack,
|
||||||
|
"run",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_menu_button_set_icon_name(window->main_button_mode,
|
||||||
|
"system-run-symbolic");
|
||||||
|
ui_setup_glarea(RUN_MODE, GTK_WIDGET(window->run_glarea_box));
|
||||||
|
break;
|
||||||
|
case PRESENTATION_MODE:
|
||||||
|
gtk_stack_set_visible_child_full(window->main_stack,
|
||||||
|
"presentation",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_stack_set_visible_child_full(window->side_stack,
|
||||||
|
"presentation",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_menu_button_set_icon_name(window->main_button_mode,
|
||||||
|
"x-office-presentation-symbolic");
|
||||||
|
ui_setup_glarea(PRESENTATION_MODE,
|
||||||
|
GTK_WIDGET(window->presentation_glarea_box));
|
||||||
|
break;
|
||||||
|
case HOME_MODE:
|
||||||
|
gtk_stack_set_visible_child_full(window->main_stack,
|
||||||
|
"home",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_stack_set_visible_child_full(window->side_stack,
|
||||||
|
"home",
|
||||||
|
GTK_STACK_TRANSITION_TYPE_CROSSFADE);
|
||||||
|
gtk_paned_set_position(window->main_paned, 0);
|
||||||
|
gtk_menu_button_set_icon_name(window->main_button_mode,
|
||||||
|
"user-home-symbolic");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_send_internal_notification(const char *message)
|
||||||
|
{
|
||||||
|
if (window->toast_revealer == NULL) {
|
||||||
|
g_printerr("Can't find self->toast_overlay !\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->toast_text == NULL) {
|
||||||
|
g_printerr("Can't find self->toast_overlay !\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_label_set_label(window->toast_text, message);
|
||||||
|
gtk_revealer_set_reveal_child(window->toast_revealer, true);
|
||||||
|
g_printerr("%s\n", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_close_internal_notification(void)
|
||||||
|
{
|
||||||
|
if (window->toast_revealer == NULL) {
|
||||||
|
g_printerr("Can't find self->toast_overlay !\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->toast_text == NULL) {
|
||||||
|
g_printerr("Can't find self->toast_overlay !\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_revealer_set_reveal_child(window->toast_revealer, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ui_toggle_sidebar(void)
|
||||||
|
{
|
||||||
|
int position = gtk_paned_get_position(window->main_paned);
|
||||||
|
|
||||||
|
if (position != 0) {
|
||||||
|
gtk_paned_set_position(window->main_paned, 0);
|
||||||
|
} else {
|
||||||
|
gtk_paned_set_position(window->main_paned, 400);
|
||||||
|
}
|
||||||
|
}
|
88
hot.c
88
hot.c
|
@ -5,29 +5,33 @@
|
||||||
#include "cold.h"
|
#include "cold.h"
|
||||||
|
|
||||||
GtkWidget *get_space_page_new(){
|
GtkWidget *get_space_page_new(){
|
||||||
GtkWidget *space_grid = gtk_grid_new();
|
// https://docs.gtk.org/gtk4/visual_index.html < widgets gallery
|
||||||
|
|
||||||
GtkScrolledWindow *scrolled = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new());
|
GtkScrolledWindow *scrolled = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new());
|
||||||
gtk_scrolled_window_set_min_content_width (scrolled, 600);
|
gtk_scrolled_window_set_min_content_width (scrolled, 600);
|
||||||
gtk_scrolled_window_set_min_content_height (scrolled, 600);
|
gtk_scrolled_window_set_min_content_height (scrolled, 600);
|
||||||
GtkAdjustment *width = gtk_adjustment_new (600, 300, 1000, 1, 1, 1000);
|
// GtkAdjustment *width = gtk_adjustment_new (600, 300, 1000, 1, 1, 1000);
|
||||||
GtkAdjustment *height = gtk_adjustment_new (600, 300, 1000, 1, 1, 1000);
|
// GtkAdjustment *height = gtk_adjustment_new (600, 300, 1000, 1, 1, 1000);
|
||||||
// (value, lower, upper, step_increment, page_increment, page_size)
|
// (value, lower, upper, step_increment, page_increment, page_size)
|
||||||
GtkWidget *viewport = gtk_viewport_new (width, height);
|
GtkWidget *GLarea = gtk_gl_area_new();
|
||||||
gtk_scrolled_window_set_child (scrolled, viewport);
|
gtk_scrolled_window_set_child (scrolled, GLarea);
|
||||||
|
// https://docs.gtk.org/gtk4/class.GLArea.html
|
||||||
|
|
||||||
GtkBox *controls_box = GTK_BOX(gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0)); // spacing = 2
|
GtkBox *controls_box = GTK_BOX(gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0));
|
||||||
gtk_box_append (controls_box, gtk_button_new_with_label ("RUN / STOP"));
|
gtk_box_append (controls_box, gtk_button_new_with_label ("RUN / STOP"));
|
||||||
gtk_box_append (controls_box, gtk_button_new_with_label ("slow down / speed up"));
|
gtk_box_append (controls_box, gtk_button_new_with_label ("slow down / speed up"));
|
||||||
gtk_box_append (controls_box, gtk_button_new_with_label ("step by step"));
|
gtk_box_append (controls_box, gtk_button_new_with_label ("step by step"));
|
||||||
gtk_box_append (controls_box, gtk_button_new_with_label ("buffer"));
|
// GtkLevelBar *buffer = GTK_LEVEL_BAR (gtk_level_bar_new ());
|
||||||
|
// GtkWidget *buffer = gtk_level_bar_new_for_interval (0, 100000);
|
||||||
|
// gtk_level_bar_set_mode (buffer, GTK_LEVEL_BAR_MODE_CONTINUOUS); //_DISCRETE
|
||||||
|
gtk_box_append (controls_box, gtk_button_new_with_label ("---- buffer ----"));
|
||||||
|
|
||||||
GtkBox *XYZ_box = GTK_BOX(gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2)); // spacing = 2
|
GtkBox *XYZ_box = GTK_BOX(gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2)); // spacing = 2
|
||||||
// GtkWidget *scale_X = gtk_scale_button_new (0, 360, 10, NULL); < à étudier
|
// GtkWidget *scale_X = gtk_scale_button_new (0, 360, 10, NULL); < à étudier
|
||||||
// (double min, double max, double step, const char** icons)
|
// (double min, double max, double step, const char** icons)
|
||||||
GtkAdjustment *X_adjust = gtk_adjustment_new (0, 0, 380, 10, 0, 0);
|
GtkAdjustment *X_adjust = gtk_adjustment_new (0, 0, 380, 1, 0, 0);
|
||||||
GtkAdjustment *Y_adjust = gtk_adjustment_new (0, 0, 380, 10, 0, 0);
|
GtkAdjustment *Y_adjust = gtk_adjustment_new (0, 0, 380, 1, 0, 0);
|
||||||
GtkAdjustment *Z_adjust = gtk_adjustment_new (0, 0, 380, 10, 0, 0);
|
GtkAdjustment *Z_adjust = gtk_adjustment_new (0, 0, 380, 1, 0, 0);
|
||||||
GtkWidget *scroll_X = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, X_adjust);
|
GtkWidget *scroll_X = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, X_adjust);
|
||||||
GtkWidget *scroll_Y = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, Y_adjust);
|
GtkWidget *scroll_Y = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, Y_adjust);
|
||||||
GtkWidget *scroll_Z = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, Z_adjust);
|
GtkWidget *scroll_Z = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, Z_adjust);
|
||||||
|
@ -36,12 +40,64 @@ GtkWidget *get_space_page_new(){
|
||||||
gtk_box_append (XYZ_box, scroll_Y);
|
gtk_box_append (XYZ_box, scroll_Y);
|
||||||
gtk_box_append (XYZ_box, scroll_Z);
|
gtk_box_append (XYZ_box, scroll_Z);
|
||||||
|
|
||||||
gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET(scrolled), 0, 0, 2, 1);
|
GtkWidget *bottom_grid = gtk_grid_new();
|
||||||
gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET(controls_box), 0, 1, 1, 1);
|
gtk_grid_attach (GTK_GRID(bottom_grid), GTK_WIDGET(controls_box), 0, 0, 1, 1);
|
||||||
gtk_grid_attach (GTK_GRID(space_grid), gtk_button_new_with_label ("Objects / Situations (transparences, styles)"), 0, 2, 1, 1);
|
gtk_grid_attach (GTK_GRID(bottom_grid), gtk_button_new_with_label ("Objects / Situations (transparences, styles)"), 0, 1, 1, 1);
|
||||||
gtk_grid_attach (GTK_GRID(space_grid), gtk_button_new_with_label ("zoom, +/- grid,\npresentation,\nstyles,..."), 1, 1, 1, 2);
|
gtk_grid_attach (GTK_GRID(bottom_grid), gtk_button_new_with_label ("zoom, +/- grid,\npresentation,\nstyles,..."), 1, 0, 1, 2);
|
||||||
gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET(XYZ_box), 2, 0, 1, 3);
|
|
||||||
|
GtkWidget *space_grid = gtk_grid_new();
|
||||||
|
gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET(scrolled), 0, 0, 1, 1);
|
||||||
|
gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET(XYZ_box), 1, 0, 1, 1);
|
||||||
|
gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET(bottom_grid), 0, 1, 2, 1); // ?! échec x_size
|
||||||
|
// gtk_grid_attach (GTK_GRID(space_grid), gtk_button_new_with_label ("?"), 1, 1, 1, 1);
|
||||||
|
|
||||||
return space_grid;
|
return space_grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
gg/draw.c: * Draws the current buffer to a gl_area
|
||||||
|
gg/draw.c: * @param gl_area, ptr to the gl_area widget
|
||||||
|
gg/init.c: * Initializes the buffer of a gl_area
|
||||||
|
gg/init.c: * @param gl_area, ptr to the gl_area widget
|
||||||
|
gg/init.c: * Initializes the shaders of a gl_area and link them to a program
|
||||||
|
gg/init.c: * @param gl_area, ptr to the gl_area widget
|
||||||
|
gg/graphics.c: * @param gl_area, ptr to the gl_area widget
|
||||||
|
gg/graphics.c: * Shutdowns a gl_area
|
||||||
|
gg/graphics.c: * @param gl_area, ptr to the gl_area widget
|
||||||
|
gg/GtkGLArea.c: void *gl_area;
|
||||||
|
gg/GtkGLArea.c: gtk_widget_queue_draw((GtkWidget*)(stack_index[i].gl_area));
|
||||||
|
gg/GtkGLArea.c: GtkWidget *gl_area;
|
||||||
|
gg/GtkGLArea.c: gl_area = GTK_WIDGET(gtk_gl_area_new());
|
||||||
|
gg/GtkGLArea.c: assert(gl_area);
|
||||||
|
gg/GtkGLArea.c: //gtk_widget_set_size_request(gl_area, 1000, 1000);
|
||||||
|
gg/GtkGLArea.c: gtk_gl_area_set_auto_render(GTK_GL_AREA(gl_area), true);
|
||||||
|
gg/GtkGLArea.c: gtk_widget_set_hexpand(gl_area, TRUE);
|
||||||
|
gg/GtkGLArea.c: gtk_widget_set_vexpand(gl_area, TRUE);
|
||||||
|
gg/GtkGLArea.c: //gtk_widget_set_halign(gl_area, GTK_ALIGN_CENTER);
|
||||||
|
gg/GtkGLArea.c: //gtk_widget_set_valign(gl_area, GTK_ALIGN_CENTER);
|
||||||
|
gg/GtkGLArea.c: g_signal_connect(GTK_GL_AREA(gl_area),
|
||||||
|
gg/GtkGLArea.c: g_signal_connect(gl_area,
|
||||||
|
gg/GtkGLArea.c: g_signal_connect(gl_area,
|
||||||
|
gg/GtkGLArea.c: stack_index[stack_index_size-1].gl_area = (void*)gl_area;
|
||||||
|
gg/GtkGLArea.c: gtk_box_append(GTK_BOX(target_widget), gl_area);
|
||||||
|
gg/GtkGLArea.c: gtk_widget_show(GTK_WIDGET(gl_area));
|
||||||
|
gg/events.c: if(gtk_gl_area_get_error(area) != NULL) {
|
||||||
|
gg/events.c: gtk_gl_area_make_current(GTK_GL_AREA(widget));
|
||||||
|
gg/events.c: if(gtk_gl_area_get_error(GTK_GL_AREA(widget)) != NULL) {
|
||||||
|
gg/events.c: gtk_gl_area_set_auto_render(GTK_GL_AREA(widget), true);
|
||||||
|
gg/events.c: gtk_gl_area_make_current(GTK_GL_AREA(widget));
|
||||||
|
gg/events.c: if(gtk_gl_area_get_error(GTK_GL_AREA(widget)) != NULL) {
|
||||||
|
gg/graphics.h: * Structure describing a gl_area and its parameters, used to create a table
|
||||||
|
gg/graphics.h: * of Gem-graph client current gl_areas
|
||||||
|
gg/graphics.h: * Dynamic array of ptrs to dynamically allocated gl_area_entry
|
||||||
|
gg/graphics.h: * Initializes a gl_area
|
||||||
|
gg/graphics.h: * @param gl_area, ptr to the gl_area widget
|
||||||
|
gg/graphics.h: * Draws the current buffer to a gl_area
|
||||||
|
gg/graphics.h: * @param gl_area, ptr to the gl_area widget
|
||||||
|
gg/graphics.h: * Shutdowns a gl_area
|
||||||
|
gg/graphics.h: * @param gl_area, ptr to the gl_area widget
|
||||||
|
gg/graphics.h: * Initializes the shaders of a gl_area and link them to a program
|
||||||
|
gg/graphics.h: * @param gl_area, ptr to the gl_area widget
|
||||||
|
gg/graphics.h: * Initializes the buffer of a gl_area
|
||||||
|
gg/graphics.h: * @param gl_area, ptr to the gl_area widget
|
||||||
|
*/
|
||||||
|
|
2
warm.c
2
warm.c
|
@ -47,7 +47,7 @@ GtkWidget *get_rules_page_new(){
|
||||||
gtk_paned_set_start_child (GTK_PANED(hpaned), GTK_WIDGET (frame1));
|
gtk_paned_set_start_child (GTK_PANED(hpaned), GTK_WIDGET (frame1));
|
||||||
gtk_paned_set_end_child (GTK_PANED(hpaned), GTK_WIDGET (frame2));
|
gtk_paned_set_end_child (GTK_PANED(hpaned), GTK_WIDGET (frame2));
|
||||||
gtk_widget_set_size_request (hpaned, 600, 600);
|
gtk_widget_set_size_request (hpaned, 600, 600);
|
||||||
gtk_widget_set_size_request (frame1, 300, 0); // < utile seulement pour la largeur min/max
|
gtk_widget_set_size_request (frame1, 100, 0); // < utile seulement pour la largeur min/max
|
||||||
// gtk_widget_set_size_request (frame2, 50, 100);
|
// gtk_widget_set_size_request (frame2, 50, 100);
|
||||||
|
|
||||||
// gtk_grid_attach (GTK_GRID (rules_grid), hpaned, 0, 0, 1, 1);
|
// gtk_grid_attach (GTK_GRID (rules_grid), hpaned, 0, 0, 1, 1);
|
||||||
|
|
Loading…
Reference in New Issue