diff --git a/(notes) b/(notes) new file mode 100644 index 0000000..930caee --- /dev/null +++ b/(notes) @@ -0,0 +1,239 @@ + +contain.c: (136) gtk_box_append (middle_box, GTK_WIDGET (get_GLArea())); + +graph_area.h: (177) static inline GLuint create_shader(const int stack_id, int type, const char *src) {...} + +graph_area.c: (153) graphics_draw (stack_index[i].stack_id); + +graph_area.c: (233) g_signal_connect (adj, "value-changed", G_CALLBACK(on_axis_value_change), (gpointer) label); +graph_area.c: (289) g_signal_connect(GTK_GL_AREA(gl_area), "render", G_CALLBACK(on_glarea_render), NULL); +graph_area.c: g_signal_connect(gl_area, "realize", G_CALLBACK(on_glarea_realize), NULL); +graph_area.c: g_signal_connect(gl_area, "unrealize", G_CALLBACK(on_glarea_unrealize), NULL); + +graph_stack.c: (149) if (!graphics_init_shaders(cur_id)) return -1; +graph_stack.c: (153) graphics_init_buffers(cur_id); + +graph_stack.c: (288) draw_space_ridges_vertex (stack_id, stack->buffer_vertex_size, space_X, space_Y, space_Z); +graph_stack.c: draw_space_ridges_lines (stack_id); +graph_stack.c: draw_grids_on_space_faces_vertex (stack_id, space_X, space_Y, space_Z); +graph_stack.c: draw_grids_on_space_faces_lines (stack_id, stack->buffer_lines_size, space_X, space_Y, space_Z); + +graph_stack.c: (316) stack->arrows_nb = set_arrow (stack_id, stack->arrows_nb, space_X, space_Y, space_Z, arrow.load, arrow.site, arrow.x, arrow.y, arrow.z); + +-------------------------------------------------------------------------------- + +contain is called (#included) in : callback, display, tree, graph_stack, graph_area, init, + +-------------------------------------------------------------------------------- + +// https://docs.gtk.org/gtk4/visual_index.html < widgets gallery +// https://docs.gtk.org/gtk4/section-text-widget.html +// https://docs.gtk.org/gtk4/class.Widget.html#height-for-width-geometry-management +// GTK_ORIENTATION_VERTICAL GTK_ORIENTATION_HORIZONTAL + + + + + + + + + + + + +https://docs.gtk.org/gtk4/visual_index.html widgets gallery +https://forge.a-lec.org/gem-graph/gem-graph-client/src/branch/devel/Makefile +https://docs.gtk.org/gtk4/class.Widget.html#height-for-width-geometry-management +// GtkSizeRequestMode get_request_mode (GtkWidget* widget); +// gtk_window_set_default_size (GTK_WINDOW (a_box), 30, 400); < TO STUDY +https://docs.gtk.org/gtk4/section-text-widget.html texts +https://docs.gtk.org/gtk4/drag-and-drop.html drag-and-drop +https://docs.gtk.org/gtk4/class.GestureZoom.html GtkGestureZoom +https://docs.gtk.org/gtk4/class.ListView.html +https://blog.gtk.org/2020/09/08/on-list-models/ < TODO +https://docs.gtk.org/gio/method.ActionMap.add_action_entries.html +-------------------------------------------------------------------------------- + + +GTK_ORIENTATION_VERTICAL GTK_ORIENTATION_HORIZONTAL + +GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT GTK_SIZE_REQUEST_CONSTANT_SIZE + +g_signal_connect (button, "clicked", G_CALLBACK (printf("%s\n", text)), text); +g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_window_destroy), window); + +-------------------------------------------------------------------------------- + +GtkBox GtkGrid GtkRevealer GtkStack +GtkOverlay GtkPaned GtkExpander GtkFixed + +box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); +gtk_widget_set_halign (box, GTK_ALIGN_FILL); +gtk_widget_set_valign (box, GTK_ALIGN_CENTER); // START CENTER END FILL +gtk_window_set_child (GTK_WINDOW (window), box); +puis, après déclaration du bouton, gtk_box_append (GTK_BOX (box), button); + +grid = gtk_grid_new (); +gtk_window_set_child (GTK_WINDOW (window), grid); +button = gtk_button_new_with_label (" I "); n fois +gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 1); n fois + +-------------------------------------------------------------------------------- + +TODO (or NOT TODO) + +GtkWidget *get_text_view(){ // WTF ?!& @Grr #~! + // https://docs.gtk.org/gtk4/section-text-widget.html + GtkWidget *my_view = gtk_text_view_new (); + GtkTextTagTable *my_table = gtk_text_tag_table_new (); + GtkTextBuffer *my_buffer = gtk_text_buffer_new (my_table); + + gtk_text_buffer_set_text (my_buffer, "Hello, this is some text", -1); + gtk_text_view_set_buffer (GTK_TEXT_VIEW (my_view), my_buffer); + + /* Now you might put the view in a container and display it on the + * screen; when the user edits the text, signals on the buffer + * will be emitted, such as "changed", "insert_text", and so on. + */ + return my_view; +} + + + + + + +/* +https://docs.gtk.org/gtk4/class.ApplicationWindow.html + +GtkApplication *app = gtk_application_new ("org.gtk.test", 0); + +GtkBuilder *builder = gtk_builder_new_from_string ( + "" + " " + " " + " _Edit" + " " + " _Copy" + " win.copy" + " " + " " + " _Paste" + " win.paste" + " " + " " + " " + "", + -1); + +GMenuModel *menubar = G_MENU_MODEL (gtk_builder_get_object (builder, "menubar")); +gtk_application_set_menubar (GTK_APPLICATION (app), menubar); +g_object_unref (builder); + +// ... + +GtkWidget *window = gtk_application_window_new (app); + +*/ +//------------------------------------------------------------------------------ + +GtkScrolledWindow *get_scrolled_gl_area(){ + GtkScrolledWindow *scrolled = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new()); + gtk_scrolled_window_set_min_content_width (scrolled, W_IMAGE); + gtk_scrolled_window_set_min_content_height (scrolled, H_IMAGE); +// GtkAdjustment *width = 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) +// GtkWidget *GLarea = gtk_gl_area_new(); +// gtk_scrolled_window_set_child (scrolled, GLarea); +// https://docs.gtk.org/gtk4/class.GLArea.html + return scrolled; +} + + + + +// https://docs.gtk.org/gtk4/getting_started.html (m'aura bien servi, quand même !) + + + +//typedef anytype = {(int)(*fnct) {printf("typedef {(int)(*fnct) {printf("");}");} GtkModelFnct; + + + + + + + + + + + +/* + essai run-stop, speed et step by step dans une seule box controls + ----------------------------------------------------------------- + + +#include +#include +#include "cold.h" + +void print_text(GtkWidget *widget, gpointer data) {g_print (data);} + +GtkWidget *get_a_space_test_image(){ + GtkWidget *image; + image = GTK_WIDGET(get_scrolled_gl_area()); + image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/images/aXoris.png"); + image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/images/gg sketch.png"); + image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/images/E coli.png"); + image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/images/E coli resized.png"); + image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/E coli by David S. Goodsell (2009).png"); + return image; +} + +GtkWidget *get_scroll_speed(){ + GtkAdjustment *speed_adjust = gtk_adjustment_new (0, 0, 100, 1, 0, 0); + GtkWidget *scroll_speed = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, speed_adjust); + return scroll_speed; +} + +// TODO cliquer sur "RUN" --> affiche "STOP" (et inversement) +GtkBox *get_RUN_STOP_box(){ + GtkBox *RUN_STOP_box = GTK_BOX(gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2)); // spacing = 2 + + GtkWidget *RUN_Label = GTK_WIDGET (gtk_label_new (NULL)); // "RUN")); + const char *str = " RUN\n STOP"; + const char *format = "\%s"; + char *markup; + + markup = g_markup_printf_escaped (format, str); + gtk_label_set_markup (GTK_LABEL (RUN_Label), markup); // Sets the labels text and attributes from markup. + g_free (markup); + + gtk_label_set_max_width_chars (GTK_LABEL(RUN_Label), 12); + gtk_label_set_wrap (GTK_LABEL(RUN_Label), TRUE); + gtk_label_set_xalign (GTK_LABEL(RUN_Label), 0.5); // xalign value, between 0 and 1 + gtk_label_set_yalign (GTK_LABEL(RUN_Label), 0.5); + gtk_label_set_selectable (GTK_LABEL(RUN_Label), FALSE); // default = FALSE + gtk_label_set_single_line_mode (GTK_LABEL(RUN_Label), TRUE); // default = TRUE + // + gtk_box_append (RUN_STOP_box, RUN_Label); + return RUN_STOP_box; +} + +GtkBox *get_STEP_by_STEP_box(){ + GtkBox *STEP_by_STEP_box = GTK_BOX(gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0)); + GtkWidget *STEP_by_STEP_Label = GTK_WIDGET (gtk_label_new ("ONE\nSTEP")); + gtk_box_append (STEP_by_STEP_box, STEP_by_STEP_Label); + return STEP_by_STEP_box; +} + +GtkBox *get_CONTROL_box(){ + GtkBox *CONTROL_box = GTK_BOX(gtk_box_new (GTK_ORIENTATION_VERTICAL, 0)); + gtk_box_append (CONTROL_box, GTK_WIDGET (get_RUN_STOP_box())); + gtk_box_append (CONTROL_box, GTK_WIDGET (get_scroll_speed())); + gtk_box_append (CONTROL_box, GTK_WIDGET (get_STEP_by_STEP_box())); + return CONTROL_box; +} +*/ diff --git a/Makefile b/Makefile index ed08dd6..18f51cb 100644 --- a/Makefile +++ b/Makefile @@ -1,24 +1,158 @@ -all: Getting_Started_with_GTK +.PHONY: run clean install all +.DELETE_ON_ERROR: $(BINDIR)/Getting_Started_with_GTK +.DEFAULT_GOAL: all +NTHREADS= $(shell nproc) +CC=gcc +CFLAGS=`pkg-config --cflags gtk4 gl glib-2.0 libxml-2.0` +LDFLAGS=`pkg-config --libs gtk4 gl glib-2.0 libxml-2.0` -lGL -lGLU -lm -lepoxy -lX11 -lGLEW WARNINGS = -Wall -DEBUG = -ggdb -fno-omit-frame-pointer -OPTIMIZE = -O2 +DEBUG = -ggdb -fno-omit-frame-pointer #-fdiagnostics-color=always -fsanitize=bounds -fstack-check +OPTIMIZE = -O3 +BINDIR=bin +BUILDDIR=build +SRCDIR=src -Getting_Started_with_GTK: Makefile main.c - $(CC) -o $@ $(WARNINGS) $(DEBUG) $(OPTIMIZE) main.c +sources = $(shell find . -maxdepth 1 -type f -name "*.c") +objects = $(patsubst %.c,%.o,$(sources)) +dependencies = $(patsubst %.c,%.d,$(sources)) -clean: - rm -f Getting_Started_with_GTK +all: myprogram + +-include $(dependencies) + +myprogram: $(objects) + $(CC) $(LDFLAGS) $(WARNINGS) $(DEBUG) $(OPTIMIZE) $^ -o $@ + +%.o: %.c Makefile + $(CC) $(CFLAGS) $(WARNINGS) $(DEBUG) $(OPTIMIZE) -c $< -o $@ + +%.d: %.c Makefile + $(CC) $(CFLAGS) -MM -MT $(@:%.d=%.o) -MF $@ $< -# Builder will call this to install the application before running. install: echo "Installing is not supported" -# Builder uses this target to run your application. -run: - ./main +run: myprogram + ./myprogram -# gcc $( pkg-config --cflags gtk4 ) -o main main.c $( pkg-config --libs gtk4 ) +clean: + rm -f myprogram + rm -f *.o + rm -f *.d + +# /!\ erreur fatale: GL/glu.h +# gcc -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -g -Wall -Wextra +# -std=c99 -lm *.c -o formattage `pkg-config --cflags --libs glib-2.0` + +#------------------------------------------------------------------------------# +# 'make' has an implicit rule for updating a ‘.o’ file # +# from a correspondingly named ‘.c’ file # +# using a ‘cc -c’ command. # +# Implicit rules are listed and applied in a predefined order (C before P...) # +# Predefined implicit rules are implemented in make as suffix rules # +# The default suffix list is: .out, .a, .ln, .o, .c, .cc, .C, .cpp, .p,... # +# Rules whose suffixes fail to be on the list are disabled. # +# You can define your own implicit rules by writing pattern rules. # +#------------------------------------------------------------------------------# + +# If there are many implicit rules with the same target pattern, +# the rule that actually applies is the one whose prerequisites exist or can be made +# ex: a .o can be made from a .c (C compiler) or a .p (Pascal compiler) + +# Variables allow a text string to be defined once +# and substituted in multiple places later. +# (see Chapter 6 [How to Use Variables], page 65) + + + +#------------------------------------------------------------------------------# +# To study : how can the following commands be modified ? # +#------------------------------------------------------------------------------# + +#SHELL = /bin/sh +#.SUFFIXES: +#.SUFFIXES: .c .o .h # is .h useful ? +#.PHONY = run +#.PHONY = clean +#.PHONY: Makefile + +#CC=gcc +#CFLAGS=`pkg-config --cflags gtk4 --libs gtk4` +#WARNINGS = -Wall +#DEBUG = -ggdb -fno-omit-frame-pointer +#OPTIMIZE = -O2 + +# in exec.o: +# $(WARNINGS) $(DEBUG) $(OPTIMIZE) < ne sont pas indispensables +# si le $@ est supprimé, main.cest modifié +#all: +# exec + +#install: +# echo "Installing is not supported" + + + + + + +#------------------------------------------------------------------------------# +# Personnal notes & links # +#------------------------------------------------------------------------------# + + +# gcc $( pkg-config --cflags gtk4 ) -o exec main.c $( pkg-config --libs gtk4 ) + +# https://www.gnu.org/software/make/manual/ + +# Makefiles contain five kinds of things: +# explicit rules, implicit rules, variable definitions, directives and comments. + + +# Variables automatiques -------------------------------------------------- +# $@ fait référence à la cible de la règle (au nom de la cible). +# $< fait référence à la première dépendance. +# $? fait référence aux noms de touess les dépendances plus récentes que la cible. +# = les fichiers qui ont été modifiés après la compilation de code la plus récente +# $^ fait référence aux noms de touess les dépendances avec des espaces entre eux. + +# Variables implicites ------------------------------------------------- +# VPATH Équivalent utilitaire de la variable PATH de Bash. Vide par défaut. +# Les chemins sont séparés par le signe deux-points (:). +# CC Le programme pour compiler des fichiers C. +# La valeur par défaut est cc. (Habituellement, cc pointe vers gcc.) +# CPP Le programme qui exécute le préprocesseur C. +# La valeur par défaut est $ (CC) -E. +# LEX Le programme qui transforme les grammaires lexicales en code source. +# La valeur par défaut est lex. (Vous devriez remplacer cela par flex.) +# LINT Le programme qui lint votre code source. La valeur par défaut est lint. +# RM La commande pour supprimer un fichier. La valeur par défaut est rm -f. +# CFLAGS Contient tous les indicateurs du compilateur C (cc). +# CPPFLAGS tous les indicateurs du préprocesseur C. +# .PHONY Spécifie des cibles qui ne ressemblent pas au nom d'un fichier. +# Un exemple est la cible "make clean" ; où clean est une valeur de .PHONY + +# Syntaxe de Base +# Règles : Une règle se compose d'une cible, des dépendances et des commandes. +# Elle est généralement structurée comme suit : +# cible: dépendances +# commande +# +# La cible (target) est le fichier à générer, +# les dépendances (prerequisites) sont les fichiers requis pour construire la cible +# et les commandes (recipe) sont les instructions exécutées pour créer la cible. +# +# A simple makefile consists of “rules” with the following shape: +# target ... : prerequisites ... +# recipe +# ... +# A target is usually the name of a file that is generated by a program; +# examples of targets are executable or object files. +# A target can also be the name of an action to carry out, such as ‘clean’ + + +# accessoirement : https://blog.stephane-robert.info/docs/makefile/ & /docs/task/ diff --git a/Makefile de gem-graph-client b/Makefile de gem-graph-client deleted file mode 100644 index 7012b2b..0000000 --- a/Makefile de gem-graph-client +++ /dev/null @@ -1,132 +0,0 @@ -## -## Gem-graph OpenGL experiments -## -## Desc: Makefile -## -## Copyright (C) 2023 Arthur Menges -## Copyright (C) 2023 Adrien Bourmault -## -## This file is part of Gem-graph. -## -## This program is free software: you can redistribute it and/or modify -## it under the terms of the GNU Affero General Public License as published by -## the Free Software Foundation, either version 3 of the License, or -## (at your option) any later version. -## -## This program is distributed in the hope that it will be useful, -## but WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -## GNU Affero General Public License for more details. -## -## You should have received a copy of the GNU Affero General Public License -## along with this program. If not, see . -## - -.PHONY: all clean install run build_system -.DELETE_ON_ERROR: $(BINDIR)/gem-graph-client -.DEFAULT_GOAL := all - -# -# Color codes -# -CL='\033[0;32m' -CL2='\033[1;36m' -CL3='\033[0m' -NC='\033[1;37m' - -# -# Variables & constants -# -NTHREADS= $(shell nproc) - -CC=gcc -WARNINGS= -Wall -DEBUG= -ggdb -fno-omit-frame-pointer -fdiagnostics-color=always -fsanitize=bounds -fstack-check - #-fsanitize=address \ - #-fsanitize=pointer-compare -fsanitize=pointer-subtract \ - #-fsanitize=leak -fsanitize=undefined -fsanitize=null -fsanitize=bounds -OPTIMIZE= -O3 -INCLUDE= $(shell pkg-config --cflags glib-2.0 libxml-2.0 gtk4) -LIBS= $(shell pkg-config --libs glib-2.0 libxml-2.0 gtk4) -lGL -lGLU -lm -lepoxy -lX11 -lGLEW - -BINDIR=bin -BUILDDIR=build -SRCDIR=src -#vpath %.c $(SRCDIR) - -SOURCES= $(shell find $(SRCDIR) -type f -name "*.c") -BUILDBINS=$(patsubst %.c,$(BUILDDIR)/%.o,$(SOURCES)) -BUILDDEPS=$(patsubst %.c,$(BUILDDIR)/%.d,$(SOURCES)) - --include /etc/os-release - -# -# Directories -# -$(BUILDDIR): - @mkdir -p $@ - @echo -e ${CL2}[$@] ${CL}folder generated.${CL3} - -$(BINDIR): - @mkdir -p $@ - @echo -e ${CL2}[$@] ${CL}folder generated.${CL3} - -# -# Dependencies -# --include $(BUILDDEPS) - -$(BUILDDIR)/%.d: %.c | $(BUILDDIR) - @mkdir -p $(shell dirname $@) - @$(CC) -MM -MT $(@:%.d=%.o) -MF $@ $< - @echo -e ${CL2}[$@] ${CL}dependencies generated.${CL3} - -# -# Compilation -# -$(BINDIR)/gem-graph-client: $(BUILDBINS) | $(BINDIR) - @$(CC) -o $@ $(WARNINGS) $(DEBUG) $(OPTIMIZE) $^ $(INCLUDE) $(LIBS) - @echo -e ${CL2}[$@] ${CL}built.${CL3} - - -$(BUILDDIR)/%.o: %.c | $(BUILDDIR) - @mkdir -p $(shell dirname $@) - @$(CC) $(WARNINGS) $(DEBUG) $(OPTIMIZE) $(INCLUDE) -c $< -o $@ - @echo -e ${CL2}[$@] ${CL}compiled.${CL3} - - -# -# Virtual recipes -# -clean: - @rm -rf $(BINDIR) - @rm -rf $(BUILDDIR) - @echo -e ${CL2}[$@] ${CL}done.${CL3} - -install: - echo "Installing is not supported" - -build_system: - @echo -e ${CL2}[$@] ${CL}building...${CL3} - @make $(BINDIR)/gem-graph-client -j $(NTHREADS) - @echo -e ${CL2}[$@] ${CL}done.${CL3} - -run: build_system - @echo -e ${CL2}[$@] ${CL}executing...${CL3} - @$(BINDIR)/gem-graph-client - @echo -e ${CL2}[$@] ${CL}done.${CL3} - -debug: build_system - @echo -e ${CL2}[$@] ${CL}executing...${CL3} - @gdb $(BINDIR)/gem-graph-client - @echo -e ${CL2}[$@] ${CL}done.${CL3} - -valgrind: build_system - @echo -e ${CL2}[$@] ${CL}executing...${CL3} - @valgrind $(BINDIR)/gem-graph-client - @echo -e ${CL2}[$@] ${CL}done.${CL3} - -all: build_system - @echo -e ${CL2}[$@] ${CL}done.${CL3} - - diff --git a/automaton.c b/automaton.c new file mode 100644 index 0000000..4f4f6fa --- /dev/null +++ b/automaton.c @@ -0,0 +1,79 @@ +#include +#include +#include "callback.h" +#include "automaton.h" + + +/******************************************************************************/ +/* S T A T E S */ +/******************************************************************************/ + +static int choice_EXEC_EDIT = EXEC; +static int choice_STATE_RULES_DATA = STATE; + + +/******************************************************************************/ +/* T R A N S I T I O N S */ +/******************************************************************************/ + +static void debug_printing (int prescribed, int sub_automaton); + +void set_EXEC_EDIT (int prescribed) { + if (choice_EXEC_EDIT != prescribed) { + debug_printing (prescribed, 0); // EXEC_EDIT is sub_automaton 0 + choice_EXEC_EDIT = prescribed; + } +} + +void set_STATE_RULES_DATA (int prescribed) { + if (choice_STATE_RULES_DATA != prescribed) { + debug_printing (prescribed, 1); // STATE_RULES_DATA is sub_automaton 1 + choice_STATE_RULES_DATA = prescribed; + } +} + + +/******************************************************************************/ +/* G E T T E R S & D E B U G G E R S */ +/******************************************************************************/ + +int get_EXEC_EDIT () {return choice_EXEC_EDIT;} +int get_STATE_RULES_DATA () {return choice_STATE_RULES_DATA;} + +static char *get_str_EXEC_EDIT (int value) { + switch (value) { + case (EXEC) : return "EXEC"; + case (EDIT) : return "EDIT"; + default : printf("default in automaton.get_EXEC_EDIT ()\n"); return NULL; + } +} + +static char *get_str_STATE_RULES_DATA (int value) { + switch (value) { + case (STATE) : return "STATE"; + case (RULES) : return "RULES"; + case (DATA) : return "DATA"; + default : printf("default in automaton.get_STATE_RULES_DATA ()\n"); return NULL; + } +} + +static void debug_printing (int prescribed, int sub_automaton) { + switch (sub_automaton) { // sub_automaton 0 is EXEC_EDIT and + // sub_automaton 1 is STATE_RULES_DATA + case (0) : printf("switch > %5s X %5s <> %5s X %5s\n", + get_str_EXEC_EDIT (choice_EXEC_EDIT), + get_str_STATE_RULES_DATA (choice_STATE_RULES_DATA), + get_str_EXEC_EDIT (prescribed), + get_str_STATE_RULES_DATA (choice_STATE_RULES_DATA)); + break; + case (1) : printf("switch > %5s X %5s <> %5s X %5s\n", + get_str_EXEC_EDIT (choice_EXEC_EDIT), + get_str_STATE_RULES_DATA (choice_STATE_RULES_DATA), + get_str_EXEC_EDIT (choice_EXEC_EDIT), + get_str_STATE_RULES_DATA (prescribed)); + break; + default : printf("default in automaton.debug_printing()\n"); + } +} + + diff --git a/automaton.h b/automaton.h new file mode 100644 index 0000000..48e5517 --- /dev/null +++ b/automaton.h @@ -0,0 +1,16 @@ +#include +#include + +enum choice_EXEC_EDIT { EXEC, EDIT }; +enum choice_STATE_RULES_DATA { STATE, RULES, DATA }; + // MEASURE, OBSERVE, INTERPRET, HELP, CONFIGURE }; ? + +void set_EXEC_EDIT (int prescribed); +void set_STATE_RULES_DATA (int prescribed); + +int get_EXEC_EDIT (); +int get_STATE_RULES_DATA (); + +// char *get_str_EXEC_EDIT (int value); +// char *get_str_STATE_RULES_DATA (int value); + diff --git a/base.h b/base.h new file mode 100644 index 0000000..365d60f --- /dev/null +++ b/base.h @@ -0,0 +1,91 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: Base header + * + * Copyright (C) 2023 Arthur Menges + * Copyright (C) 2023 Adrien Bourmault + * + * This file is part of Gem-graph. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#define G_APPLICATION_DEFAULT_FLAGS 0 + +enum { X_AXIS, Y_AXIS, Z_AXIS, N_AXIS }; // < used by : graph_area.h +enum { HOME_MODE, RUN_MODE, EDIT_MODE, PRESENTATION_MODE, N_MODE }; // Gem-graph modes +struct arrow_t { uint load; uint site; uint x; uint y; uint z; }; // describes an arrow +static inline char *read_file(char *filename); // < used by : init.c + +/* I'm standing on Earth (or any spinning spheroid) and looking towards its North pole, then : + X - X = EAST - WEST = rouge - cyan + Y - Y = ZENITH - NADIR = vert - magenta (fuschia) + 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 + + +/* + * char *read_file(char *filename) reads 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; +} + diff --git a/callback.c b/callback.c new file mode 100644 index 0000000..f42cd4a --- /dev/null +++ b/callback.c @@ -0,0 +1,219 @@ +#include +#include + +#include "callback.h" +#include "contain.h" +#include "tree.h" +#include "contain.h" +#include "dialog.h" +#include "texts.h" +#include "automaton.h" +#include "parsing.h" +#include "graph_area.h" + +/******************************************************************************/ +/* W I N D O W S A C T I V A T I O N */ +/******************************************************************************/ + +static GtkWindow *main_window, *dialog_window; + +void on_main_window_activation (GtkApplication *app, gpointer no_user_data) +{ + main_window = GTK_WINDOW (gtk_application_window_new (app)); + main_window_design (main_window); + g_signal_connect (app, "activate", G_CALLBACK (on_dialog_window_activation), main_window); +} + +void on_dialog_window_activation (GtkApplication *app, gpointer no_user_data) +{ + dialog_window = GTK_WINDOW (gtk_application_window_new (app)); + dialog_window_design (main_window, dialog_window); +} + + +void on_auto_notification (const char *message) +{ + /* Ignored (2024-06-06) because I don't know how to get "main_window" easily + + if (window->toast_revealer == NULL) { + g_printerr("Can't find app->toast_overlay !\n"); + return; + } + + if (window->toast_text == NULL) { + g_printerr("Can't find app->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); +} + +/******************************************************************************/ +/* T R E E */ +/******************************************************************************/ +void on_user_tree_expander_toggled (GtkExpander *expander, gpointer user_data) +{ + GtkTreeListRow *row = GTK_TREE_LIST_ROW (user_data); + gboolean is_expanded = gtk_tree_list_row_get_expanded(row); + gtk_tree_list_row_set_expanded (row, !is_expanded); +} + +void on_bind_user_tree_factory (GtkSignalListItemFactory *factory, GObject* object, gpointer user_data) +{ + GtkListItem *list_item = GTK_LIST_ITEM (object); assert (list_item); + GtkTreeListRow *row = gtk_list_item_get_item (list_item); assert (row); // if (row != NULL) {...} ? + const gchar *text = gtk_string_object_get_string (GTK_STRING_OBJECT (gtk_tree_list_row_get_item (row))); + GtkWidget *expander = gtk_list_item_get_child (list_item); + gtk_expander_set_label (GTK_EXPANDER (expander), text); + g_signal_handlers_disconnect_by_func(expander, G_CALLBACK (on_user_tree_expander_toggled), row); + g_signal_connect(expander, "activate", G_CALLBACK (on_user_tree_expander_toggled), row); + gtk_widget_set_margin_start(expander, gtk_tree_list_row_get_depth(row) * 20); +} + +/******************************************************************************/ +/* G L A R E A */ +/******************************************************************************/ +gboolean on_glarea_render(GtkGLArea *area, GdkGLContext *context) +{ + // Check if the widget is a glarea + if(gtk_gl_area_get_error(area) != NULL) { + on_auto_notification("An OpenGL error occured !"); + return false; + } + + if (ui_render_stack(gtk_widget_get_parent(GTK_WIDGET(area))) == false) { + on_auto_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) { + on_auto_notification("An OpenGL error occured !"); + return; + } + + // Link graphical stack to widget + if (ui_init_graphic_stack(gtk_widget_get_parent(widget), + internal_error) == false) { + on_auto_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) { + on_auto_notification("An OpenGL error occured !"); + return; + } + + // Destroy graphic stack + if (ui_shutdown_graphic_stack(gtk_widget_get_parent(widget), + internal_error) == false) { + on_auto_notification( + "Failed to shutdown the graphic stack !"); + return; + } +} + +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 */ +} + + +/******************************************************************************/ +/* B U T T O N S */ +/******************************************************************************/ + +void on_toggle_EXEC_EDIT (GtkWidget *toggled_button, gpointer user_data) { + + if (get_EXEC_EDIT ()) { + gtk_button_set_icon_name (GTK_BUTTON (toggled_button), "power-profile-balanced-rtl-symbolic"); + set_EXEC_EDIT (EXEC); + } else { + gtk_button_set_icon_name (GTK_BUTTON (toggled_button), "text-editor-symbolic"); + set_EXEC_EDIT (EDIT); + } + switch (get_STATE_RULES_DATA()) { + case (STATE) : gtk_window_set_child (main_window, GTK_WIDGET (get_window_child_STATE())); break; + case (RULES) : gtk_window_set_child (main_window, GTK_WIDGET (get_window_child_RULES())); break; + case (DATA) : gtk_window_set_child (main_window, GTK_WIDGET (get_window_child_DATA())); break; + default : printf("default in callback.on_toggle_STATE_RULES_DATA()\n"); + } +} + +void on_toggle_STATE_RULES_DATA (GtkWidget *toggled_button, gpointer user_data) { + + const char *toggled_button_name = gtk_check_button_get_label (GTK_CHECK_BUTTON (toggled_button)); + int is_active = gtk_check_button_get_active (GTK_CHECK_BUTTON (toggled_button)); + + if (! strcmp (toggled_button_name, "state")) set_STATE_RULES_DATA (STATE); + if (! strcmp (toggled_button_name, "rules")) set_STATE_RULES_DATA (RULES); + if (! strcmp (toggled_button_name, "data analysis")) set_STATE_RULES_DATA (DATA); + + if (is_active) + switch (get_STATE_RULES_DATA()) { + case (STATE) : gtk_window_set_child (main_window, GTK_WIDGET (get_window_child_STATE())); break; + case (RULES) : gtk_window_set_child (main_window, GTK_WIDGET (get_window_child_RULES())); break; + case (DATA) : gtk_window_set_child (main_window, GTK_WIDGET (get_window_child_DATA())); break; + default : printf("default in callback.on_toggle_STATE_RULES_DATA()\n"); + } +} + +void on_SAVE_CURRENT_MODEL_BEFORE_EDITING (GtkWidget *btt_SAVE_CURRENT_MODEL, gpointer data) { + gtk_widget_set_sensitive (GTK_WIDGET (data), TRUE); + printf ("callback.c (line 201) - SAVE_CURRENT_MODEL_BEFORE_EDITING\n"); +} + +void on_DISCARD_CURRENT_MODEL_AND_START_EDITING (GtkWidget *btt_SAVE_CURRENT_MODEL, gpointer data) { + gtk_window_close (GTK_WINDOW (data)); + printf ("callback.c (line 206) - DISCARD_CURRENT_MODEL_AND_START_EDITING\n"); +} + +void on_WRITE_CURRENT_MODEL (GtkWidget *btt_WRITE_CURRENT_MODEL, gpointer data) { + gtk_window_close (GTK_WINDOW (data)); + printf ("callback.c (line 211) - WRITE_CURRENT_MODEL\n"); +} + diff --git a/callback.h b/callback.h new file mode 100644 index 0000000..678c9ba --- /dev/null +++ b/callback.h @@ -0,0 +1,27 @@ +#include + + +void on_main_window_activation (GtkApplication *app, gpointer user_data); +void on_dialog_window_activation (GtkApplication *app, gpointer user_data); +void on_auto_notification (const char *message); + +void on_user_tree_expander_toggled (GtkExpander *expander, gpointer user_data); +void on_bind_user_tree_factory (GtkSignalListItemFactory *factory, GObject* object, gpointer user_data); + +gboolean on_glarea_render (GtkGLArea *area, GdkGLContext *context); +void on_glarea_realize (GtkWidget *widget); +void on_glarea_unrealize (GtkWidget *widget); + +void on_axis_value_change (GtkAdjustment *adjustment, gpointer data); + +void on_toggle_EXEC_EDIT (GtkWidget *btt_XOR_EXEC_EDIT, gpointer user_data); +void on_toggle_MODEL_RUN_STOP (GtkWidget *btt_MODEL_RUN_STOP, gpointer data); + +void on_open_STATE (GtkWidget *btt_open_STATE, gpointer data); +void on_open_RULES (GtkWidget *btt_open_RULES, gpointer data); +void on_open_DATA (GtkWidget *btt_open_DATA, gpointer data); + +void on_SAVE_CURRENT_MODEL_BEFORE_EDITING (GtkWidget *btt_SAVE_CURRENT_MODEL, gpointer data); +void on_DISCARD_CURRENT_MODEL_AND_START_EDITING (GtkWidget *btt_SAVE_CURRENT_MODEL, gpointer data); +void on_WRITE_CURRENT_MODEL (GtkWidget *btt_WRITE_CURRENT_MODEL, gpointer data); +void on_toggle_STATE_RULES_DATA (GtkWidget *btt, gpointer user_data); diff --git a/contain.c b/contain.c new file mode 100644 index 0000000..3f0a463 --- /dev/null +++ b/contain.c @@ -0,0 +1,426 @@ +#include +#include + +#include "graph_area.h" +#include "callback.h" +#include "automaton.h" +#include "display.h" +#include "tree.h" +#include "texts.h" + +// https://blog.gtk.org/2020/09/08/on-list-models/ < TODO +// https://docs.gtk.org/gtk4/visual_index.html < widgets gallery + + +GtkFrame *get_frame_with_label(){ // EN ATTENDANT DE SAVOIR UTILISER : GtkTextTagTable , GtkTextBuffer + GtkFrame *space_specif = GTK_FRAME(gtk_frame_new ("Space (run / edit) specifications")); + GtkWidget *any_Label = GTK_WIDGET (gtk_label_new (get_space_run_edit_specif())); + gtk_frame_set_child (GTK_FRAME (space_specif), GTK_WIDGET (any_Label)); + return space_specif; +} + +GtkWidget *get_edit_rules_page_new(){ + GtkPaned *hpaned = GTK_PANED (gtk_paned_new (GTK_ORIENTATION_HORIZONTAL)); + + GtkWidget *arbre_des_règles = gtk_frame_new ("Arbre des règles"); + GtkWidget *édition_de_la_règle_sélectionnée = gtk_frame_new ("Édition de la règle sélectionnée"); + + gtk_paned_set_start_child (hpaned, GTK_WIDGET (arbre_des_règles)); + gtk_paned_set_end_child (hpaned, GTK_WIDGET (édition_de_la_règle_sélectionnée)); + // gtk_widget_set_size_request (GTK_WIDGET (hpaned), W, H); + gtk_paned_set_wide_handle (hpaned, TRUE); + + return GTK_WIDGET (hpaned); +} + +GtkWidget *get_edit_measures_page_new(){ + GtkWidget *measures_grid = gtk_grid_new(); + return measures_grid; +} + +GtkWidget *get_edit_results_page_new(){ + GtkWidget *xxx_grid = gtk_grid_new(); + return xxx_grid; +} + +GtkWidget *get_edit_discuss_page_new(){ + GtkWidget *xxx_grid = gtk_grid_new(); + return xxx_grid; +} + +GtkWidget *get_edit_help_page_new(){ + GtkWidget *edit_help_grid = gtk_grid_new(); + gtk_grid_attach (GTK_GRID(edit_help_grid), GTK_WIDGET(get_frame_with_label()), 0, 0, 1, 1); + return edit_help_grid; +} + +GtkWidget *get_measures_page_new(){ + GtkWidget *measures_grid = gtk_grid_new(); + gtk_grid_attach (GTK_GRID (measures_grid), gtk_button_new_with_label ("movements"), 0, 0, 1, 1); + gtk_grid_attach (GTK_GRID (measures_grid), gtk_button_new_with_label ("transports"), 1, 0, 1, 1); + gtk_grid_attach (GTK_GRID (measures_grid), gtk_button_new_with_label ("transformations"), 2, 0, 1, 1); + gtk_grid_attach (GTK_GRID (measures_grid), gtk_button_new_with_label ("objects"), 0, 1, 1, 1); + gtk_grid_attach (GTK_GRID (measures_grid), gtk_button_new_with_label ("situations"), 1, 1, 1, 1); + return measures_grid; +} + +GtkWidget *get_results_page_new(){ + GtkWidget *results_grid = gtk_grid_new(); + gtk_grid_attach (GTK_GRID(results_grid), gtk_button_new_with_label ("Repartitions"), 0, 0, 1, 1); + gtk_grid_attach (GTK_GRID(results_grid), gtk_button_new_with_label ("Correlations"), 0, 1, 1, 1); + gtk_grid_attach (GTK_GRID(results_grid), gtk_button_new_with_label ("Evolutions"), 0, 2, 1, 1); + return results_grid; +} + +GtkWidget *get_discuss_page_new(){ + GtkWidget *discuss_grid = gtk_grid_new(); + gtk_grid_attach (GTK_GRID (discuss_grid), gtk_button_new_with_label ("Interpretations"), 0, 0, 1, 1); + gtk_grid_attach (GTK_GRID (discuss_grid), gtk_button_new_with_label ("Discussions"), 0, 1, 1, 1); + return discuss_grid; +} + +GtkWidget *get_help_page_new(){ + GtkWidget *run_help_grid = gtk_grid_new(); + gtk_grid_attach (GTK_GRID(run_help_grid), GTK_WIDGET(get_frame_with_label()), 0, 0, 1, 1); + return run_help_grid; +} + +GtkWidget *get_edit_space_page_new(){ + GtkWidget *space_grid = gtk_grid_new(); + gtk_grid_attach (GTK_GRID(space_grid), get_image_ALL_SPACE(), 0, 0, 1, 3); + gtk_grid_attach (GTK_GRID(space_grid), get_OBJECTS_and_SITUATIONS(), 0, 4, 1, 1); + gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET (get_XYZ_box()), 1, 0, 1, 2); + gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET (get_ZOOM_box()), 1, 2, 1, 2); + gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET (get_edit_TOOL_box()), 1, 3, 1, 2); + gtk_widget_set_size_request (space_grid, W, H); + return space_grid; +} + +//------------------------------------------------------------------------------ + +GtkWidget *get_selected_rules_vpaned_new(){ + GtkPaned *V_selected_1_vs_2 = GTK_PANED (gtk_paned_new (GTK_ORIENTATION_VERTICAL)); + + GtkBox *up_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2)); + gtk_box_append (up_box, GTK_WIDGET (get_image_GLUTAMATE())); + gtk_box_append (up_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_VERTICAL))); + gtk_box_append (up_box, GTK_WIDGET (get_image_GLUTAMINE())); + + GtkBox *bottom_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2)); + gtk_box_append (bottom_box, GTK_WIDGET (get_image_ATP())); + gtk_box_append (bottom_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_VERTICAL))); + gtk_box_append (bottom_box, GTK_WIDGET (get_image_AMP())); + + gtk_paned_set_start_child (V_selected_1_vs_2, GTK_WIDGET (up_box)); + gtk_paned_set_end_child (V_selected_1_vs_2, GTK_WIDGET (bottom_box)); + + return GTK_WIDGET (V_selected_1_vs_2); +} + + + +GtkWidget *get_TIME_EXEC_controls_box(){ + GtkBox *top_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2)); + gtk_box_append (top_box, GTK_WIDGET (get_ELAPSED_TIME_ProgressBar())); + gtk_box_append (top_box, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_VERTICAL))); + gtk_box_append (top_box, GTK_WIDGET (get_RUN_STOP_box())); + return GTK_WIDGET (top_box); +} + +GtkWidget *get_SPACE_VIEW_box(){ + GtkBox *right_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 2)); + gtk_box_append (right_box, GTK_WIDGET (get_XYZ_box())); + gtk_box_append (right_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + gtk_box_append (right_box, GTK_WIDGET (get_ZOOM_box())); + + GtkBox *middle_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2)); + gtk_box_append (middle_box, GTK_WIDGET (get_image_ALL_SPACE())); +// ui_setup_glarea (0, GTK_WIDGET (middle_box)); + + gtk_box_append (middle_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_VERTICAL))); + gtk_box_append (middle_box, GTK_WIDGET (right_box)); + return GTK_WIDGET (middle_box); +} + +GtkWidget *get_SPACE_EDIT_controls_box() { + GtkWidget *label_ad_hoc = gtk_label_new ("_____________\n\ + SPACE EDIT\n controls\n_____________"); + return GTK_WIDGET (label_ad_hoc); +} + + +static void icons_for_fun (GtkHeaderBar *header_bar); + +static GtkButton *btt_open_STATE; +static GtkButton *btt_open_RULES; +static GtkButton *btt_open_DATA; + +GtkButton *get_GtkButton (char *btt_name) { + if (strcmp (btt_name, "state")) return btt_open_STATE; + if (strcmp (btt_name, "rules")) return btt_open_RULES; + if (strcmp (btt_name, "data analysis")) return btt_open_DATA; + return NULL; +} + +void set_check_button_active (GtkButton *button, int active){ + const char *lab = gtk_button_get_label (button); + if (strcmp (lab, "state")) printf("set_check_button_active > %s\n", lab); +} + + +void window_header_bar (GtkWindow *window, char *title){ + GtkWidget *header_bar = GTK_WIDGET (gtk_header_bar_new ()); + gtk_header_bar_set_title_widget (GTK_HEADER_BAR (header_bar), gtk_label_new (title)); + gtk_window_set_titlebar (window, header_bar); + + gpointer no_local_data = NULL; + + GtkButton *btt_XOR_EXEC_EDIT = GTK_BUTTON (gtk_toggle_button_new ()); + gtk_button_set_icon_name (btt_XOR_EXEC_EDIT, "system-run-symbolic"); + gtk_button_set_icon_name (btt_XOR_EXEC_EDIT, "process-stop-symbolic"); + gtk_button_set_icon_name (btt_XOR_EXEC_EDIT, "power-profile-balanced-rtl-symbolic"); + g_signal_connect (btt_XOR_EXEC_EDIT, "clicked", G_CALLBACK (on_toggle_EXEC_EDIT), no_local_data); + + GtkWidget *any_Label = GTK_WIDGET (gtk_label_new (" | ")); + + GtkCheckButton *group_STATE_RULES_DATA = GTK_CHECK_BUTTON (gtk_check_button_new ()); + + btt_open_STATE = GTK_BUTTON (gtk_check_button_new_with_label ("state")); + g_signal_connect (btt_open_STATE, "toggled", G_CALLBACK (on_toggle_STATE_RULES_DATA), no_local_data); + gtk_check_button_set_group (GTK_CHECK_BUTTON (btt_open_STATE), group_STATE_RULES_DATA); + + btt_open_RULES = GTK_BUTTON (gtk_check_button_new_with_label ("rules")); + g_signal_connect (btt_open_RULES, "toggled", G_CALLBACK (on_toggle_STATE_RULES_DATA), no_local_data); + gtk_check_button_set_group (GTK_CHECK_BUTTON (btt_open_RULES), group_STATE_RULES_DATA); + + btt_open_DATA = GTK_BUTTON (gtk_check_button_new_with_label ("data analysis")); + g_signal_connect (btt_open_DATA, "toggled", G_CALLBACK (on_toggle_STATE_RULES_DATA), no_local_data); + gtk_check_button_set_group (GTK_CHECK_BUTTON (btt_open_DATA), group_STATE_RULES_DATA); + + gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), GTK_WIDGET (btt_XOR_EXEC_EDIT)); + gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), GTK_WIDGET (any_Label)); + gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), GTK_WIDGET (btt_open_STATE)); + gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), GTK_WIDGET (btt_open_RULES)); + gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), GTK_WIDGET (btt_open_DATA)); + + + icons_for_fun (GTK_HEADER_BAR (header_bar)); // https://iconduck.com/sets/adwaita-icon-theme +// https://iconduck.com/sets/carbon-icons < pas mal ... +// https://thenounproject.com/icon/train-134324/ +// ma préférée : Transport Steam Engine Icon mais : [ process icon ] semble un bon choix... +} + +void main_window_design (GtkWindow *main_window){ + window_header_bar (main_window, + "E coli (with permission from David S. Goodsell, 2009)"); + gtk_check_button_set_active (GTK_CHECK_BUTTON (btt_open_STATE), TRUE); + gtk_window_present (GTK_WINDOW (main_window)); +} + + + + + + + + + + + + + +GtkWidget *get_window_child_STATE() { + if (0) printf("contain.get_window_child_STATE (line 235)\n"); + GtkBox *page_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 2)); + gtk_box_append (page_box, GTK_WIDGET (get_OBJECTS_and_SITUATIONS())); + gtk_box_append (page_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + gtk_box_append (page_box, GTK_WIDGET (get_SPACE_VIEW_box())); + gtk_box_append (page_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + if (get_EXEC_EDIT ()) gtk_box_append (page_box, GTK_WIDGET (get_SPACE_EDIT_controls_box())); + else gtk_box_append (page_box, GTK_WIDGET (get_TIME_EXEC_controls_box())); + return GTK_WIDGET (page_box); +} + +GtkWidget *get_window_child_RULES(){ + if (0) printf("contain.get_window_child_RULES (line 246)\n"); + GtkPaned *H_tree_vs_selected = GTK_PANED (gtk_paned_new (GTK_ORIENTATION_HORIZONTAL)); +// GtkWidget *arbre_des_règles = gtk_frame_new ("Arbre des règles"); +// GtkWidget *édition_de_la_règle_sélectionnée_n_1 = gtk_frame_new ("Inspection"); + gtk_paned_set_start_child (H_tree_vs_selected, GTK_WIDGET (get_rules_tree_hpaned_new())); + gtk_paned_set_end_child (H_tree_vs_selected, GTK_WIDGET (get_selected_rules_vpaned_new())); + gtk_paned_set_position (H_tree_vs_selected, 400); // WARNING : c'est une position "absolue" + gtk_paned_set_wide_handle (H_tree_vs_selected, TRUE); + return GTK_WIDGET (H_tree_vs_selected); +} + +GtkWidget *get_window_child_DATA (){ + if (0) printf("contain.get_window_child_DATA (line 259)\n"); + GtkBox *data_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 32)); + + GtkWidget* frame_rule_effect = gtk_frame_new ("rule effect\n-----------"); + gtk_frame_set_label_align (GTK_FRAME (frame_rule_effect), 0.5); + GtkBox *rule_effect_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 8)); + gtk_frame_set_child (GTK_FRAME (frame_rule_effect), GTK_WIDGET (rule_effect_box)); + + GtkWidget* frame_rule_topic = gtk_frame_new ("rule topic\n----------"); + gtk_frame_set_label_align (GTK_FRAME (frame_rule_topic), 0.5); + GtkBox *rule_topic_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 8)); + gtk_frame_set_child (GTK_FRAME (frame_rule_topic), GTK_WIDGET (rule_topic_box)); + + GtkWidget* frame_data_type = gtk_frame_new ("data type\n----------"); + gtk_frame_set_label_align (GTK_FRAME (frame_data_type), 0.5); + GtkBox *data_type_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 8)); + gtk_frame_set_child (GTK_FRAME (frame_data_type), GTK_WIDGET (data_type_box)); + + GtkWidget* frame_interpretations = gtk_frame_new ("interpretation\n---------------"); + gtk_frame_set_label_align (GTK_FRAME (frame_interpretations), 0.5); + GtkBox *interpretations_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 8)); + gtk_frame_set_child (GTK_FRAME (frame_interpretations), GTK_WIDGET (interpretations_box)); + + GtkWidget* frame_discussions = gtk_frame_new ("discussion\n------------"); + gtk_frame_set_label_align (GTK_FRAME (frame_discussions), 0.5); + GtkBox *discussions_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 8)); + gtk_frame_set_child (GTK_FRAME (frame_discussions), GTK_WIDGET (discussions_box)); + + GtkWidget* frame_separator = gtk_frame_new ("\n"); + + GtkWidget* frame_game = gtk_frame_new ("game\n------"); + gtk_frame_set_label_align (GTK_FRAME (frame_game), 0.5); + GtkBox *game_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 8)); + gtk_frame_set_child (GTK_FRAME (frame_game), GTK_WIDGET (game_box)); + + GtkWidget* frame_help = gtk_frame_new ("help\n-----"); + gtk_frame_set_label_align (GTK_FRAME (frame_help), 0.5); + GtkBox *help_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 8)); + gtk_frame_set_child (GTK_FRAME (frame_help), GTK_WIDGET (help_box)); + + gtk_box_append (data_box, GTK_WIDGET (frame_rule_effect)); + gtk_box_append (data_box, GTK_WIDGET (frame_rule_topic)); + gtk_box_append (data_box, GTK_WIDGET (frame_data_type)); + gtk_box_append (data_box, GTK_WIDGET (frame_interpretations)); + gtk_box_append (data_box, GTK_WIDGET (frame_discussions)); + gtk_box_append (data_box, GTK_WIDGET (frame_separator)); + gtk_box_append (data_box, GTK_WIDGET (frame_game)); + gtk_box_append (data_box, GTK_WIDGET (frame_help)); + + gtk_box_append (rule_effect_box, gtk_button_new_with_label ("movement")); + gtk_box_append (rule_effect_box, gtk_button_new_with_label ("transport")); + gtk_box_append (rule_effect_box, gtk_button_new_with_label ("transformation")); + + gtk_box_append (rule_topic_box, gtk_button_new_with_label ("objects")); + gtk_box_append (rule_topic_box, gtk_button_new_with_label ("situations")); + + gtk_box_append (rule_topic_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + gtk_box_append (rule_topic_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + gtk_box_append (rule_topic_box, gtk_button_new_with_label ("accuracy")); + gtk_box_append (rule_topic_box, gtk_button_new_with_label ("pattern recognition")); + + gtk_box_append (data_type_box, gtk_button_new_with_label ("repartitions")); + gtk_box_append (data_type_box, gtk_button_new_with_label ("evolutions")); + gtk_box_append (data_type_box, gtk_button_new_with_label ("correlations")); + + gtk_box_append (interpretations_box, gtk_button_new_with_label ("stochastic")); + gtk_box_append (interpretations_box, gtk_button_new_with_label ("deterministic")); + + gtk_box_append (interpretations_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + gtk_box_append (interpretations_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + gtk_box_append (interpretations_box, gtk_button_new_with_label ("physical")); + gtk_box_append (interpretations_box, gtk_button_new_with_label ("chemical")); + gtk_box_append (interpretations_box, gtk_button_new_with_label ("biological")); + gtk_box_append (interpretations_box, gtk_button_new_with_label ("social")); + gtk_box_append (interpretations_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + + gtk_box_append (discussions_box, gtk_button_new_with_label ("context")); + gtk_box_append (discussions_box, gtk_button_new_with_label ("methodology")); + gtk_box_append (discussions_box, gtk_button_new_with_label ("comparisons")); + gtk_box_append (discussions_box, gtk_button_new_with_label ("to improve")); + gtk_box_append (discussions_box, gtk_button_new_with_label ("summary")); + + gtk_box_append (game_box, gtk_button_new_with_label ("single player")); + gtk_box_append (game_box, gtk_button_new_with_label ("multiple players")); + gtk_box_append (game_box, gtk_button_new_with_label ("edition facilities")); + + gtk_box_append (help_box, gtk_button_new_with_label ("modelization")); + gtk_box_append (help_box, gtk_button_new_with_label ("measurements")); + gtk_box_append (help_box, gtk_button_new_with_label ("results")); + gtk_box_append (help_box, gtk_button_new_with_label ("data analysis")); + + gtk_box_append (help_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + gtk_box_append (help_box, GTK_WIDGET (gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + gtk_box_append (help_box, gtk_button_new_with_label ("preferences")); + + //SWITCH_TO (DATA); + return GTK_WIDGET (data_box); +} + +static void icons_for_fun (GtkHeaderBar *header_bar) +{ + GtkButton *go_home = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (go_home, "go-home-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (go_home)); + + GtkButton *user_trash = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (user_trash, "user-trash-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (user_trash)); + + GtkButton *help_biblio = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (help_biblio, "accessories-dictionary-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (help_biblio)); + + GtkButton *help_doc = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (help_doc, "emblem-documents-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (help_doc)); + + GtkButton *help_about = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (help_about, "help-about-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (help_about)); + + GtkButton *help_faq = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (help_faq, "help-faq-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (help_faq)); + + GtkButton *terminal = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (terminal, "utilities-terminal-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (terminal)); + + GtkButton *search = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (search, "folder-saved-search-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (search)); + + GtkButton *preferences_desktop_appearance = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (preferences_desktop_appearance, "preferences-desktop-appearance-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (preferences_desktop_appearance)); + + GtkButton *preferences_system = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (preferences_system, "preferences-system-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (preferences_system)); + + GtkButton *document_properties = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (document_properties, "document-properties-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (document_properties)); + + GtkButton *text_edit = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (text_edit, "text-editor-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (text_edit)); + + GtkButton *applications_utilities = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (applications_utilities, "applications-utilities-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (applications_utilities)); + + GtkButton *open_menu = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (open_menu, "open-menu-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (open_menu)); + + GtkButton *power_max = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (power_max, "power-profile-performance-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (power_max)); + + GtkButton *power_middle = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (power_middle, "power-profile-balanced-rtl-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (power_middle)); + + GtkButton *power_low = GTK_BUTTON (gtk_button_new ()); + gtk_button_set_icon_name (power_low, "power-profile-power-saver-symbolic"); + gtk_header_bar_pack_end (header_bar, GTK_WIDGET (power_low)); +} + diff --git a/contain.h b/contain.h new file mode 100644 index 0000000..23364c8 --- /dev/null +++ b/contain.h @@ -0,0 +1,44 @@ +//******************************************************************************/ +/* */ +/* E coli by David S. Goodsell (2009) */ +/* --- */ +/* Let this freeze frame guide us towards the model */ +/* that alone can account for the phenomenon ! */ +/* */ +/******************************************************************************/ + +#include + +#define W 1920 +#define H 960 +#define W_IMAGE W - 320 +#define H_IMAGE H - 126 +#define H_STYLES_PANE 30 +#define W_IMAGE_LOCAL W / 16 +#define H_IMAGE_LOCAL H / 16 + +/* +G_BEGIN_DECLS +#define MY_TYPE_WINDOW (my_window_get_type()) +G_DECLARE_FINAL_TYPE (MyWindow, my_window, MY, WINDOW, GtkApplicationWindow) +G_END_DECLS + +G_BEGIN_DECLS +#define MY_TYPE_APPLICATION (my_application_get_type()) +G_DECLARE_FINAL_TYPE (MyApplication, my_application, MY, APPLICATION, GtkApplication) +MyApplication *my_application_new (const char *application_id, GApplicationFlags flags); +G_END_DECLS +*/ + +void main_window_design (GtkWindow *main_window); +void set_check_button_active (GtkButton *button, int active); +void two_notebooks_in_two_panes (GtkWindow *window); + +GtkFrame *get_frame_with_label(); +GtkWidget *get_selected_rules_vpaned_new(); +GtkWidget *get_TIME_EXEC_controls_box(); +GtkWidget *get_SPACE_EDIT_controls_box(); +GtkButton *get_GtkButton (char *btt_name); +GtkWidget *get_window_child_STATE(); +GtkWidget *get_window_child_RULES(); +GtkWidget *get_window_child_DATA(); diff --git a/dialog.c b/dialog.c new file mode 100644 index 0000000..a872962 --- /dev/null +++ b/dialog.c @@ -0,0 +1,37 @@ +#include "callback.h" + +void dialog_window_design (GtkWindow *main_window, GtkWindow *dialog_window){ + char *title = " Save the current model before modifying it? "; + GtkWidget *header_bar = GTK_WIDGET (gtk_header_bar_new ()); + gtk_header_bar_set_title_widget (GTK_HEADER_BAR (header_bar), gtk_label_new (title)); + gtk_window_set_titlebar (dialog_window, header_bar); + + GtkWidget *dialog_window_grid = gtk_grid_new (); + + const char *txt = " SAVE CURRENT MODEL "; + GtkButton *action_save_current_model = GTK_BUTTON (gtk_button_new_with_label (txt)); + gtk_widget_set_sensitive (GTK_WIDGET (action_save_current_model), FALSE); + g_signal_connect (action_save_current_model, "clicked", + G_CALLBACK (on_WRITE_CURRENT_MODEL), dialog_window); + + GtkButton *click_yes = GTK_BUTTON (gtk_button_new_with_label ("YES")); + g_signal_connect (click_yes, "clicked", + G_CALLBACK (on_SAVE_CURRENT_MODEL_BEFORE_EDITING), action_save_current_model); + + GtkButton *click_no = GTK_BUTTON (gtk_button_new_with_label ("NO")); + g_signal_connect (click_no, "clicked", + G_CALLBACK (on_DISCARD_CURRENT_MODEL_AND_START_EDITING), dialog_window); + + gtk_grid_attach (GTK_GRID (dialog_window_grid), GTK_WIDGET (click_yes), 0, 0, 1, 1) ; + gtk_grid_attach (GTK_GRID (dialog_window_grid), GTK_WIDGET (click_no), 1, 0, 1, 1) ; + gtk_grid_attach (GTK_GRID (dialog_window_grid), GTK_WIDGET (action_save_current_model), 0, 2, 2, 1) ; + gtk_window_set_child (GTK_WINDOW (dialog_window), GTK_WIDGET (dialog_window_grid)); + + gtk_window_set_transient_for (GTK_WINDOW (dialog_window), GTK_WINDOW (main_window)); + gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog_window), TRUE); + gtk_window_set_deletable (GTK_WINDOW (dialog_window), FALSE); // FALSE + gtk_window_set_modal (GTK_WINDOW (dialog_window), TRUE); +// gtk_window_present (GTK_WINDOW (dialog_window)); see button... +} + + diff --git a/dialog.h b/dialog.h new file mode 100644 index 0000000..3cbf6a2 --- /dev/null +++ b/dialog.h @@ -0,0 +1,2 @@ +void dialog_window_design (GtkWindow *main_window, GtkWindow *dialog_window); + diff --git a/dimers random walk.xml b/dimers random walk.xml new file mode 100644 index 0000000..12ae465 --- /dev/null +++ b/dimers random walk.xml @@ -0,0 +1,118 @@ + + + + + Modèle de test + + Léontine Patinette + + 2 + + 1630000000 + + 1.0 + + Ref + + + + + 0 + 9 + + + + + + + + + + + + + + + + 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/display.c b/display.c new file mode 100644 index 0000000..439ad62 --- /dev/null +++ b/display.c @@ -0,0 +1,280 @@ +#include +#include + +#include "contain.h" +#include "tree.h" +#include "texts.h" + +//------------------------------------------------------------------------------ + +GtkWidget *get_image_ALL_SPACE(){ + GtkWidget *image; + // forget > GTK_WIDGET(get_scrolled_gl_area()); + // Use GtkImage if you want to display a fixed-size icon + // and GtkPicture if you want to display a (maybe) scaled picture. + image = gtk_image_new_from_file("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/aXoris.png"); + image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/gg sketch.png"); + image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/E coli (Goodsell) 2.png"); + gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE, H_IMAGE); + return image; +} + +GtkWidget *get_image_GLUTAMATE(){ + GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/glutamate.png"); + gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL); + return image; +} + +GtkWidget *get_image_GLUTAMINE(){ + GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/glutamine.png"); + gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL); + return image; +} + +GtkWidget *get_image_HISTIDINE(){ + GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/histidine.png"); + gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL); + return image; +} + +GtkWidget *get_image_HISTAMINE(){ + GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/histamine.png"); + gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL); + return image; +} + +GtkWidget *get_image_PHENYLALANINE(){ + GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/phénylalanine.png"); + gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL); + return image; +} + +GtkWidget *get_image_DOPAMINE(){ + GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/dopamine.png"); + gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL); + return image; +} + +GtkWidget *get_image_ATP(){ + GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/ATP.png"); + gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL); + return image; +} + +GtkWidget *get_image_AMP(){ + GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/AMP.png"); + gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL); + return image; +} + +GtkWidget *get_user_tree(){ + GtkWidget *image = gtk_picture_new_for_filename ("/home/jean/01/Gtk4/Getting_Started_with_GTK/image/arbre utilisateur.png"); + gtk_widget_set_size_request (GTK_WIDGET (image), W_IMAGE_LOCAL, H_IMAGE_LOCAL); + return image; +} + +//------------------------------------------------------------------------------ + +// TODO cliquer sur "RUN" --> affiche "STOP" (et inversement) +static GtkWidget *get_scroll_speed(){ + GtkAdjustment *speed_adjust = gtk_adjustment_new (100, 0, 100, 1, 0, 0); + GtkWidget *scroll_speed = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, speed_adjust); + gtk_widget_set_size_request (GTK_WIDGET (scroll_speed), 120, 2); + return scroll_speed; +} + +static GtkBox *get_UNDO_SPEED_box(){ + GtkBox *SPEED_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 0)); + gtk_box_append (SPEED_box, GTK_WIDGET(gtk_label_new ("< UNDO <\n"))); + gtk_box_append (SPEED_box, get_scroll_speed()); + return SPEED_box; +} + +static GtkBox *get_DO_SPEED_box(){ + GtkBox *SPEED_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 0)); + gtk_box_append (SPEED_box, GTK_WIDGET(gtk_label_new ("> DO >\n"))); + gtk_box_append (SPEED_box, get_scroll_speed()); + return SPEED_box; +} + +GtkBox *get_RUN_STOP_box(){ + GtkBox *RUN_STOP_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 20)); + gtk_box_append (RUN_STOP_box, GTK_WIDGET (get_UNDO_SPEED_box())); + gtk_box_append (RUN_STOP_box, GTK_WIDGET(gtk_label_new (" STEP\n(show active rule) "))); + gtk_box_append (RUN_STOP_box, GTK_WIDGET (get_DO_SPEED_box())); + gtk_box_append (RUN_STOP_box, GTK_WIDGET(gtk_label_new (" R U N\n S T O P"))); + return RUN_STOP_box; +} +//------------------------------------------------------------------------------ + +GtkBox *get_ZOOM_box(){ + GtkBox *ZOOM_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0)); + GtkWidget *ZOOM_Label = GTK_WIDGET (gtk_label_new (\ + "\n TOOLS\n ---\n zoom\n ---\n space\n struct.\n\ + ---\n arrows\n struct.\n ---\n orient\n state\n in space\n")); + gtk_widget_set_size_request (GTK_WIDGET (ZOOM_box), 10, 80); + gtk_box_append (ZOOM_box, ZOOM_Label); + return ZOOM_box; +} + +//------------------------------------------------------------------------------ + +GtkBox *get_edit_TOOL_box(){ + GtkBox *TOOL_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0)); + GtkWidget *ZOOM_Label = GTK_WIDGET (gtk_label_new ("TOOLS\n ---\n(space\nstruct.)")); + gtk_widget_set_size_request (GTK_WIDGET (TOOL_box), 10, 120); + gtk_box_append (TOOL_box, ZOOM_Label); + return TOOL_box; +} + +//------------------------------------------------------------------------------ + +GtkBox *get_XYZ_box(){ + GtkBox *XYZ_labels_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 2)); // spacing = 2 + GtkBox *XYZ_scrollbar_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2)); // spacing = 2q + // GtkWidget *scale_X = gtk_scale_button_new (0, 360, 10, NULL); < à étudier + // (double min, double max, double step, const char** icons) + GtkAdjustment *X_adjust = gtk_adjustment_new (0, 0, 380, 1, 0, 0); + GtkAdjustment *Y_adjust = gtk_adjustment_new (0, 0, 380, 1, 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_Y = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, Y_adjust); + GtkWidget *scroll_Z = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, Z_adjust); + gtk_widget_set_size_request (GTK_WIDGET (scroll_X), 1, 500); + + gtk_box_append (XYZ_scrollbar_box, GTK_WIDGET (gtk_label_new (" "))); // AD HOC (pour "centrer") + gtk_box_append (XYZ_scrollbar_box, scroll_X); + gtk_box_append (XYZ_scrollbar_box, scroll_Y); + gtk_box_append (XYZ_scrollbar_box, scroll_Z); + + gtk_box_append (XYZ_labels_box, GTK_WIDGET (gtk_label_new ("\nX Y Z"))); + gtk_box_append (XYZ_labels_box, GTK_WIDGET (XYZ_scrollbar_box)); + gtk_box_append (XYZ_labels_box, GTK_WIDGET (gtk_label_new (""))); + return XYZ_labels_box; +} + +//------------------------------------------------------------------------------ + +GtkProgressBar *get_ELAPSED_TIME_ProgressBar(){ // To rename : DO - UNDO - REDO ? + GtkProgressBar *buffer = GTK_PROGRESS_BAR (gtk_progress_bar_new ()); + gtk_progress_bar_set_text (buffer,\ + "\n<--- [buffer] (simulation extensive time) --->\n\ + supports DO - UNDO - REDO functions\n"); + gtk_progress_bar_set_show_text (buffer, TRUE); + gtk_widget_set_size_request (GTK_WIDGET (buffer), W - 560, 0); + return buffer; +} + +//------------------------------------------------------------------------------ + +// Chaque label "objet" ou "situation" sera remplacé par un curseur "transparence" (vertical) + +static GtkBox *get_objects_box(){ + GtkBox *objects_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0)); + GtkAdjustment *adjust = gtk_adjustment_new (0, 0, 255, 1, 0, 0); + if (0) for (int i = 0; i < 10; i++) + gtk_box_append (objects_box, gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, adjust)); + char string[7]; + for (int i = 0; i < 16; i++){ + sprintf(string, "[%d] ", i); + if (0) printf("%s\n", string); // répété deux fois ! pourquoi ? + gtk_box_append (objects_box, GTK_WIDGET (gtk_label_new (string))); + } + gtk_box_append (objects_box, GTK_WIDGET (gtk_label_new (" membrane "))); + gtk_box_append (objects_box, GTK_WIDGET (gtk_label_new (" co-enzyme A "))); + gtk_box_append (objects_box, GTK_WIDGET (gtk_label_new (" ribosome "))); + gtk_box_append (objects_box, GTK_WIDGET (gtk_label_new (" ATP synthase "))); + return objects_box; +} + +static GtkBox *get_situations_box(){ + GtkBox *situations_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0)); + char string[7]; + for (int i = 0; i < 64; i++){ + sprintf(string, "[%d] ", i); + if (0) printf("%s\n", string); // répété deux fois ! pourquoi ? + gtk_box_append (situations_box, GTK_WIDGET (gtk_label_new (string))); + } + gtk_box_append (situations_box, GTK_WIDGET (gtk_label_new (" transcription "))); + gtk_box_append (situations_box, GTK_WIDGET (gtk_label_new (" transport Na/K "))); + gtk_box_append (situations_box, GTK_WIDGET (gtk_label_new (" ubiquitination "))); + gtk_box_append (situations_box, GTK_WIDGET (gtk_label_new (" rotation moteur flagellaire "))); + return situations_box; +} + +static GtkWidget *get_frame_objects(){ + GtkWidget *scroll = gtk_scrolled_window_new (); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER); + GtkWidget *frame_objects = gtk_frame_new (" Objects"); // defines each class of object transparence + gtk_widget_set_size_request (frame_objects, 0, H_STYLES_PANE); // < utile seulement pour la largeur min/max + gtk_frame_set_child (GTK_FRAME (frame_objects), GTK_WIDGET (get_objects_box())); + gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scroll), frame_objects); + return scroll; +} + +static GtkWidget *get_frame_situations(){ + GtkWidget *scroll = gtk_scrolled_window_new (); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER); + GtkWidget *frame_situations = gtk_frame_new (" Situations"); // facilitates each situation identification + gtk_widget_set_size_request (GTK_WIDGET (frame_situations), 0, H_STYLES_PANE); // < utile seulement pour la largeur min/max + gtk_frame_set_child (GTK_FRAME (frame_situations), GTK_WIDGET (get_situations_box())); + gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scroll), frame_situations); + return scroll; +} + +GtkWidget *get_OBJECTS_and_SITUATIONS(){ + GtkWidget *objects_and_situations_horizontal_pane = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); + gtk_paned_set_start_child (GTK_PANED(objects_and_situations_horizontal_pane), GTK_WIDGET (get_frame_objects())); + gtk_paned_set_end_child (GTK_PANED(objects_and_situations_horizontal_pane), GTK_WIDGET (get_frame_situations())); + return objects_and_situations_horizontal_pane; +} + + +GtkBox *get_rules_comparator_new(){ + GtkBox *comparator = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 2)); + gtk_box_append (comparator, GTK_WIDGET (get_image_ATP())); + gtk_box_append (comparator, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + gtk_box_append (comparator, GTK_WIDGET (get_image_AMP())); + gtk_box_append (comparator, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + gtk_box_append (comparator, GTK_WIDGET (get_image_GLUTAMATE())); + gtk_box_append (comparator, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + gtk_box_append (comparator, GTK_WIDGET (get_image_GLUTAMINE())); + gtk_box_append (comparator, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + gtk_box_append (comparator, GTK_WIDGET (get_image_HISTIDINE())); + gtk_box_append (comparator, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + gtk_box_append (comparator, GTK_WIDGET (get_image_PHENYLALANINE())); + gtk_box_append (comparator, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + gtk_box_append (comparator, GTK_WIDGET (get_image_DOPAMINE())); + gtk_box_append (comparator, GTK_WIDGET(gtk_separator_new (GTK_ORIENTATION_HORIZONTAL))); + return comparator; +} + +GtkWidget *get_rules_tree_hpaned_new(){ + GtkPaned *H_tree_vs_comparison = GTK_PANED (gtk_paned_new (GTK_ORIENTATION_HORIZONTAL)); + +// GtkWidget *arbre_des_règles = gtk_frame_new ("Arbre"); +// GtkWidget *comparaison_des_règles_sélectionnées = gtk_frame_new ("Sélection"); + + gtk_paned_set_start_child (H_tree_vs_comparison, GTK_WIDGET (get_user_rules_tree())); + gtk_paned_set_end_child (H_tree_vs_comparison, GTK_WIDGET (get_rules_comparator_new())); + gtk_paned_set_position (H_tree_vs_comparison, 300); + gtk_paned_set_wide_handle (H_tree_vs_comparison, TRUE); + gtk_paned_set_shrink_start_child (H_tree_vs_comparison, FALSE); + gtk_paned_set_shrink_end_child (H_tree_vs_comparison, FALSE); + return GTK_WIDGET (H_tree_vs_comparison); +} + +GtkWidget *get_rules_page_new(){ + GtkPaned *H_tree_vs_selected = GTK_PANED (gtk_paned_new (GTK_ORIENTATION_HORIZONTAL)); + +// GtkWidget *arbre_des_règles = gtk_frame_new ("Arbre des règles"); +// GtkWidget *édition_de_la_règle_sélectionnée_n_1 = gtk_frame_new ("Inspection"); + + gtk_paned_set_start_child (H_tree_vs_selected, GTK_WIDGET (get_rules_tree_hpaned_new())); + gtk_paned_set_end_child (H_tree_vs_selected, GTK_WIDGET (get_selected_rules_vpaned_new())); + gtk_paned_set_position (H_tree_vs_selected, 600); // WARNING : c'est une position "absolue" + gtk_paned_set_wide_handle (H_tree_vs_selected, TRUE); + // gtk_widget_set_size_request (GTK_WIDGET (H_tree_vs_selected), W, H); // inutile... ? + return GTK_WIDGET (H_tree_vs_selected); +} + diff --git a/display.h b/display.h new file mode 100644 index 0000000..157190b --- /dev/null +++ b/display.h @@ -0,0 +1,38 @@ +/******************************************************************************/ +/* */ +/* E coli by David S. Goodsell (2009) */ +/* --- */ +/* Let this freeze frame guide us towards the model */ +/* that alone can account for the phenomenon ! */ +/* */ +/******************************************************************************/ + +GtkWidget *get_text_view(); +GtkFrame *get_frame_with_label(); +GtkWidget *get_rules_page_new(); +GtkBox *get_rules_user_tree_new(); + +GtkWidget *get_image_ALL_SPACE(); +GtkWidget *get_image_GLUTAMATE(); +GtkWidget *get_image_GLUTAMINE(); +GtkWidget *get_image_HISTIDINE(); +GtkWidget *get_image_HISTAMINE(); +GtkWidget *get_image_PHENYLALANINE(); +GtkWidget *get_image_DOPAMINE(); +GtkWidget *get_image_ATP(); +GtkWidget *get_image_AMP(); +GtkWidget *get_rules_tree_hpaned_new(); + +GtkProgressBar *get_ELAPSED_TIME_ProgressBar(); +GtkBox *get_RUN_STOP_box(); +GtkBox *get_ZOOM_box(); +GtkBox *get_edit_TOOL_box(); +GtkBox *get_XYZ_box(); +GtkWidget *get_OBJECTS_and_SITUATIONS(); +GtkBox *get_ELAPSED_TIME_box(); + +GtkButton *get_btt_run_xor_edit(); + +void window_bar(GtkWindow *window, char *title); + + diff --git a/draw.c b/draw.c new file mode 100644 index 0000000..fea1ca7 --- /dev/null +++ b/draw.c @@ -0,0 +1,207 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: GL functions + * + * Copyright (C) 2023 Adrien Bourmault + * Copyright (C) 2023 Jean Sirmai + * + * This file is part of Gem-graph. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/* + * Writes values to describe a vertex at (x,y,z) intoq the vertex buffer + * + * @param coords GLfloat(x,y,z) + * + * @return void + */ + +#include +#include +#include +#include "base.h" +//#include "ui.h" +#include "graph_area.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"); +} diff --git a/graph_area.c b/graph_area.c new file mode 100644 index 0000000..2732cf3 --- /dev/null +++ b/graph_area.c @@ -0,0 +1,332 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: User interface functions + * + * Copyright (C) 2023 Adrien Bourmault + * + * This file is part of Gem-graph. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include "contain.h" +#include "graph_area.h" +#include "callback.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; + + +int set_arrow (int stack_id, // 2024-06-27 DEBUG ! + 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) { + printf("graph_area.c > int set_arrow (...) 2024-06-27 DEBUG\n"); + return 0; + +} // 2024-06-27 DEBUG ! + + + +/* + * 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 %ld\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; +} + +//void graphics_draw(const int stack_id) {printf("graph_area.c > void graphics_draw(const int stack_id) (161)\n");} + +/* + * 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_set_visible (label, TRUE); + + 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_set_visible (slider, TRUE); + + gtk_widget_set_visible (box, TRUE); + + 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_set_visible (GTK_WIDGET (gl_area), TRUE); + + // Create sliders + for(int i = 0; i < N_AXIS; i++) + gtk_box_append(GTK_BOX(target_widget), create_axis_slider(i)); + + return true; +} diff --git a/graph_area.h b/graph_area.h new file mode 100644 index 0000000..e492cc6 --- /dev/null +++ b/graph_area.h @@ -0,0 +1,328 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: OpenGL utils header + * + * Copyright (C) 2023 Arthur Menges + * Copyright (C) 2023 Adrien Bourmault + * Copyright (C) 2023 Jean Sirmai + * + * This file is part of Gem-graph. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +#include "base.h" +//#include "draw.c" + +// #define VERTEX_SHADER_FILE "src/graphics/shaders/shader.vert" +// #define FRAG_SHADER_FILE "src/graphics/shaders/shader.frag" +#define VERTEX_SHADER_FILE "shader.vert" +#define FRAG_SHADER_FILE "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; +}; + +bool ui_render_stack(GtkWidget *container_widget); + +bool ui_setup_glarea(int target_mode, GtkWidget *target_widget); + +/* + * 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); + +bool ui_init_graphic_stack(void *container_widget, GError *error_buffer); +bool ui_shutdown_graphic_stack(void *container_widget, GError *error_buffer); +bool ui_update_axis_stack(GtkWidget *container_widget, int axis, int value); + +/* 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 = %ld\n", graphic_stack[stack_id].buffer_vertex_0_arrow); + printf("buffer_colors_0_arrow = %ld\n", graphic_stack[stack_id].buffer_colors_0_arrow); + printf("buffer_lines_0_arrow = %ld\n", graphic_stack[stack_id].buffer_lines_0_arrow); + printf("buffer_plans_0_arrow = %ld\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); + diff --git a/graph_stack.c b/graph_stack.c new file mode 100644 index 0000000..6d77b9e --- /dev/null +++ b/graph_stack.c @@ -0,0 +1,323 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: GL functions + * + * Copyright (C) 2023 Arthur Menges + * Copyright (C) 2023 Adrien Bourmault + * Copyright (C) 2023 Jean Sirmai + * + * This file is part of Gem-graph. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "contain.h" +#include "graph_area.h" +#include "parsing.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 (or not !) + 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 = %d, density_max = %d\n", multiplicity, density_max); + + /*------------------------------------------------------------------------*/ + + /* 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((char *)&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, (char *)&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, arrow.site, arrow.x, arrow.y, arrow.z); + } + + if (stack->arrows_nb != announced_arrows_nb) + g_printerr("ARGH : not all arrows have been parsed !\n"); +} + diff --git a/graphics.h b/graphics.h new file mode 100644 index 0000000..c83b60c --- /dev/null +++ b/graphics.h @@ -0,0 +1,314 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: OpenGL utils header + * + * Copyright (C) 2023 Arthur Menges + * Copyright (C) 2023 Adrien Bourmault + * Copyright (C) 2023 Jean Sirmai + * + * This file is part of Gem-graph. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once +#include "base.h" +#include +#include +#include +#include +#include +#include + +#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 = %ld\n", graphic_stack[stack_id].buffer_vertex_0_arrow); + printf("buffer_colors_0_arrow = %ld\n", graphic_stack[stack_id].buffer_colors_0_arrow); + printf("buffer_lines_0_arrow = %ld\n", graphic_stack[stack_id].buffer_lines_0_arrow); + printf("buffer_plans_0_arrow = %ld\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); + diff --git a/grid.c b/grid.c new file mode 100644 index 0000000..0947d80 --- /dev/null +++ b/grid.c @@ -0,0 +1,162 @@ +/* + * Gem-graph + * + * Desc: OpenGL grid functions + * + * Copyright (C) 2023 Jean Sirmai + * Copyright (C) 2023 Adrien Bourmault + * + * This file is part of Gem-graph. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include "base.h" +//#include "ui.h" +#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; +} + diff --git a/image/AMP.png b/image/AMP.png new file mode 100644 index 0000000..450dfb7 Binary files /dev/null and b/image/AMP.png differ diff --git a/image/ATP.png b/image/ATP.png new file mode 100644 index 0000000..ba106d3 Binary files /dev/null and b/image/ATP.png differ diff --git a/image/E coli (Goodsell) 2.png b/image/E coli (Goodsell) 2.png new file mode 100644 index 0000000..b2eb7d7 Binary files /dev/null and b/image/E coli (Goodsell) 2.png differ diff --git a/image/E coli (Goodsell).png b/image/E coli (Goodsell).png new file mode 100644 index 0000000..55b14b8 Binary files /dev/null and b/image/E coli (Goodsell).png differ diff --git a/image/aXoris.png b/image/aXoris.png new file mode 100644 index 0000000..1994d91 Binary files /dev/null and b/image/aXoris.png differ diff --git a/image/catécholamines.png b/image/catécholamines.png new file mode 100644 index 0000000..4878e2f Binary files /dev/null and b/image/catécholamines.png differ diff --git a/image/dopamine.png b/image/dopamine.png new file mode 100644 index 0000000..5360f44 Binary files /dev/null and b/image/dopamine.png differ diff --git a/image/glutamate.png b/image/glutamate.png new file mode 100644 index 0000000..dc474be Binary files /dev/null and b/image/glutamate.png differ diff --git a/image/glutamine.png b/image/glutamine.png new file mode 100644 index 0000000..7ac3bb7 Binary files /dev/null and b/image/glutamine.png differ diff --git a/image/hb.png b/image/hb.png new file mode 100644 index 0000000..a010e57 Binary files /dev/null and b/image/hb.png differ diff --git a/image/insuline Zn.png b/image/insuline Zn.png new file mode 100644 index 0000000..9f7dd18 Binary files /dev/null and b/image/insuline Zn.png differ diff --git a/image/insuline.png b/image/insuline.png new file mode 100644 index 0000000..ea1c2a7 Binary files /dev/null and b/image/insuline.png differ diff --git a/image/phénylalanine.png b/image/phénylalanine.png new file mode 100644 index 0000000..10498bf Binary files /dev/null and b/image/phénylalanine.png differ diff --git a/init.c b/init.c new file mode 100644 index 0000000..12756a4 --- /dev/null +++ b/init.c @@ -0,0 +1,191 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: GL functions + * + * Copyright (C) 2023 Arthur Menges + * Copyright (C) 2023 Adrien Bourmault + * + * This file is part of Gem-graph. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include "base.h" +#include "contain.h" // instead of "ui.h" +#include "graph_area.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 = 0, fragment; // 2024-06-05 j'initialise vertex à 0 (au pif !) + 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(); + printf("\n------------------------------------------------------------------------------------------\n"); + printf("[debug] graphics_init_shaders() : program = %d, vertex = %d, fragment = %d\n\ + exec > ** (myprogram:-----): WARNING ** : --:--:--:---: Linking failure: (address)\n", + program, vertex, fragment); + + /* (myprogram:11732): WARNING **: 10:37:34.233: v plusieurs 'run' successifs + * (myprogram:11883): WARNING **: 10:38:22.979: glLinkProgram(program); < commenté + * (myprogram:11953): WARNING **: 10:38:46.170: + * (myprogram:12034): WARNING **: 10:39:14.709: + * (myprogram:12182): WARNING **: 10:40:49.788: + * > probablement la même adresse dans la librairie 'mesa' d'OpenGL (?) */ + + glAttachShader(program, vertex); + glAttachShader(program, fragment); + + printf("Failed to link the graphic stack to widgets ! <> see init.c graphics_init_shaders()\n"); + printf("the error in not : vertex shader lacks `main' but : failed to link... (comment line 140)\n"); + // https://registry.khronos.org/OpenGL-Refpages/gl4/html/glLinkProgram.xhtml + // glLinkProgram(program); // Linking failure: (address) + printf("------------------------------------------------------------------------------------------\n"); + + glGetProgramiv(program, GL_LINK_STATUS, &status); // Linking failure: (address) + + 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; +} diff --git a/init.c.todo b/init.c.todo new file mode 100644 index 0000000..7789ec0 --- /dev/null +++ b/init.c.todo @@ -0,0 +1,175 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: GL functions + * + * Copyright (C) 2023 Arthur Menges + * Copyright (C) 2023 Adrien Bourmault + * + * This file is part of Gem-graph. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +/* -------------------------------------------------------------------------- */ + +#include +#include +#include "base.h" +#include "contain.h" // instead of "ui.h" +#include "graph_area.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 = 0, fragment; // 2024-06-05 j'initialise vertex à 0 (au pif !) + 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; +} diff --git a/main b/main deleted file mode 100755 index 8a5e7d6..0000000 Binary files a/main and /dev/null differ diff --git a/main.c b/main.c old mode 100755 new mode 100644 index 6edfd95..a5f9b0c --- a/main.c +++ b/main.c @@ -1,73 +1,26 @@ -/* main.c - * - * Copyright 2024 Jean - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ +/******************************************************************************/ +/* */ +/* E coli by David S. Goodsell (2009) */ +/* --- */ +/* Let this freeze frame guide us towards the model */ +/* that alone can account for the phenomenon ! */ +/* */ +/******************************************************************************/ -#include +#include "callback.h" -static void -print_hello (GtkWidget *widget, - gpointer data) -{ - g_print ("Hello World\n"); -} - -static void -activate (GtkApplication *app, - gpointer user_data) -{ - GtkWidget *window; - GtkWidget *button; - GtkWidget *box; - - window = gtk_application_window_new (app); - gtk_window_set_title (GTK_WINDOW (window), "Window"); - gtk_window_set_default_size (GTK_WINDOW (window), 200, 200); - - box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_set_halign (box, GTK_ALIGN_CENTER); - gtk_widget_set_valign (box, GTK_ALIGN_CENTER); - - gtk_window_set_child (GTK_WINDOW (window), box); - - button = gtk_button_new_with_label ("Hello World"); - - g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL); - g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_window_destroy), window); - - gtk_box_append (GTK_BOX (box), button); - - gtk_window_present (GTK_WINDOW (window)); -} - -int -main (int argc, - char **argv) +int main (int argc, char **argv) { GtkApplication *app; int status; - app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS); - g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); + app = gtk_application_new ("org.jean.GTK4_GG_hack", G_APPLICATION_DEFAULT_FLAGS); + g_signal_connect (app, "activate", G_CALLBACK (on_main_window_activation), NULL); + g_signal_connect (app, "activate", G_CALLBACK (on_dialog_window_activation), NULL); status = g_application_run (G_APPLICATION (app), argc, argv); g_object_unref (app); + printf("in contain.get_SPACE_VIEW_box() (line 138) > ui_setup_glarea (0, GTK_WIDGET (middle_box)); < commented 2024/06/27 > TODO\n"); + return status; } - - diff --git a/manifest.scm b/manifest.scm new file mode 100644 index 0000000..c1ac365 --- /dev/null +++ b/manifest.scm @@ -0,0 +1,30 @@ +;; +;; Dépendances sous GNU Guix +;; + + +(specifications->manifest + (list + "bash" + "coreutils" + "gcc-toolchain" + "pkg-config" + "valgrind" + "findutils" + "gdb" + "make" + "gtk" + "libxml2" + "glu" + "glew" + "glfw" + "cglm" + "libepoxy" + "pango@1.90.0" + "xorgproto" + "glib" + "mesa-headers" + "mesa" + "libadwaita" + ) +) diff --git a/parsing.c b/parsing.c new file mode 100644 index 0000000..b618d5b --- /dev/null +++ b/parsing.c @@ -0,0 +1,481 @@ +/* + * Gem-graph client + * + * Desc: Model parsing functions + * + * Copyright (C) 2023 Jean Sirmai + * Copyright (C) 2024 Adrien Bourmault + * + * This file is part of Gem-graph. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include // http://xmlsoft.org/examples/#parse1.c + // https://gnome.pages.gitlab.gnome.org/libxml2/devhelp/general.html + +#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; + + // 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; + 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, (char *)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, (char *)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; < usage ? + + // Look for the id attribute + if (model_get_node_str_attrib(cur_node, "id", (char *)&temp_char)) { + if (!xmlStrcmp((const xmlChar *)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", (char *)&temp_char)) { + if (!xmlStrcmp((xmlChar *)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; +} diff --git a/parsing.h b/parsing.h new file mode 100644 index 0000000..1cf7ff8 --- /dev/null +++ b/parsing.h @@ -0,0 +1,43 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: Model parsing header + * + * Copyright (C) 2023 Arthur Menges + * Copyright (C) 2023 Adrien Bourmault + * + * This file is part of Gem-graph. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#pragma once +#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); + +long model_get_state_arrows_count(const char *state_id); +bool model_get_next_arrow(struct arrow_t *new_arrow, + const char *state_id, + char dimension); diff --git a/shader.frag b/shader.frag new file mode 100644 index 0000000..fb8a76c --- /dev/null +++ b/shader.frag @@ -0,0 +1,9 @@ +#version 330 core + +in vec4 color; +out vec4 out_frag_color; + +void main(void) +{ + out_frag_color = color; +} \ No newline at end of file diff --git a/shader.vert b/shader.vert new file mode 100644 index 0000000..09e953c --- /dev/null +++ b/shader.vert @@ -0,0 +1,20 @@ +#version 330 core + +uniform mat4 projection_matrix; +uniform mat4 model_matrix; +uniform mat4 view_matrix; + +layout(location=0) in vec3 in_position; +layout(location=1) in vec3 in_color; + +out vec4 color; + +void main(void) +{ + float zoom = 1.1f, chrominance = 1, luminance = 1; + gl_Position = + projection_matrix * view_matrix * model_matrix * vec4(in_position, zoom); + color = vec4 (chrominance * in_color.rgb, luminance); +} + +// https://learnopengl.com/Getting-started/Shaders \ No newline at end of file diff --git a/texts.c b/texts.c new file mode 100644 index 0000000..f14fdf9 --- /dev/null +++ b/texts.c @@ -0,0 +1,48 @@ +/******************************************************************************/ +/* */ +/* E coli by David S. Goodsell (2009) */ +/* --- */ +/* Let this freeze frame guide us towards the model */ +/* that alone can account for the phenomenon ! */ +/* */ +/******************************************************************************/ + +char *get_space_run_edit_specif(){ return "\n\ +>>> Dans : [space_page - mode RUN] doivent être : ------------------------------------------------------\n\n\ +(1) les commandes de mouvement:\n\ + - run/stop, slow down/speed up, step by step, do/undo/redo\n\ + + le buffer [elapsed time] qui montre le temps de simulation écoulé\n\n\ +(2) les commandes qui modifient la perception de l'espace (la caméra)\n\ + - son orientation (X,Y,Z),\n\ + + l'orientation (X,Y,Z) de l'état dans l'espace (six possibilités),\n\ + + le zoom,\n\ + + les paramètres qui définissent la perspective (distances oeil/écran, écran/objet virtuel) \n\n\ +(3) les commandes qui modifient les apparences des objets et des situations d'intérêt\n\ + (+/- transparents, colorés, etc.)\n\n\ +(4) les commandes qui modifient l'apparence de l'espace (grilles, +/- surfaces, aspect des flèches, etc.)\n\n\ +(0) NB >>> AUCUNE COMMANDE NE DOIT PERMETTRE D'ÉDITER L'ESPACE ! <<<\n\n\n\ +>>> Dans : [space_page - mode EDIT] doivent être : ------------------------------------------------------\n\n\ +(1) les commandes qui modifient la perception de l'espace (la caméra)\n\ + - son orientation (X,Y,Z),\n\ + + l'orientation (X,Y,Z) de l'état dans l'espace (six possibilités),\n\ + + le zoom,\n\ + + les paramètres qui définissent la perspective (distances oeil/écran, écran/objet virtuel) \n\n\ +(2) les commandes qui modifient les apparences des objets et des situations d'intérêt\n\ + (+/- transparents, colorés, etc.)\n\n\ +(3) les commandes qui modifient l'apparence de l'espace (grilles, +/- surfaces, aspect des flèches, etc.)\n\n\ +(4) les commandes d'édition locales (drag and drop une flèche)\n\ + ('faire de la place' pour insérer)\n\ + (sélectionner pour déplacer ou enlever...)\n\ + NB ces commandes doivent être graphiques et/ou accessibles par raccourcis ou en ligne\n\n\ +(5) les commandes d'édition globales\n\ + (ex: introduire, retirer, transformer +/-aléatoirement (n) objets dans l'espace)\n\n\n\ + NB une action effectuée sur une zone d'intérêt devrait pouvoir être automatiquement appliquée\n\ + à d'autres zones d'intérêt identifiées comme similaires\n\n\ +(0) NB >>> AUCUNE COMMANDE NE DOIT PERMETTRE D'EXÉCUTER UN RUN ! <<<\n\n\n\ +>>> L'objectif est que l'utilisateur ait accès à une organsisation aussi ergonomique que possible -----\n\n\ + i.e : chaque utilisateur devrait disposer de 'préférences'\n\ + c'est-à-dire avoir la possiblité de faire des choix ergonomiques personnalisés.\n\ +";} + +char *get_rules_run_edit_specif(){ return "\n\ +";} diff --git a/texts.h b/texts.h new file mode 100644 index 0000000..43a7437 --- /dev/null +++ b/texts.h @@ -0,0 +1,39 @@ +char *get_space_run_edit_specif(); +char *get_rules_run_edit_specif(); + +/* +>>> Dans : [space_page - mode RUN] doivent être : ------------------------------------------------------ + +(1) les commandes de mouvement: + - run/stop, slow down/speed up, step by step, do/undo/redo + + le buffer [elapsed time] qui montre le temps de simulation écoulé +(2) les commandes qui modifient la perception de l'espace (la caméra) + - son orientation (X,Y,Z), + + le zoom, + + les paramètres qui définissent la perspective (distances oeil/écran, écran/objet virtuel) +(3) les commandes qui modifient les apparences des objets et des situations d'intérêt + (+/- transparents, colorés, etc.) +(4) les commandes qui modifient l'apparence de l'espace (grilles, +/- surfaces, aspect des flèches, etc.) +(0) NB >>> AUCUNE COMMANDE NE DOIT PERMETTRE D'ÉDITER L'ESPACE ! <<< +>>> Dans : [space_page - mode EDIT] doivent être : ------------------------------------------------------ +(1) les commandes qui modifient la perception de l'espace (la caméra) + - son orientation (X,Y,Z), + + le zoom, + + les paramètres qui définissent la perspective (distances oeil/écran, écran/objet virtuel) +(2) les commandes qui modifient les apparences des objets et des situations d'intérêt + (+/- transparents, colorés, etc.) +(3) les commandes qui modifient l'apparence de l'espace (grilles, +/- surfaces, aspect des flèches, etc.) +(4) les commandes d'édition locales (drag and drop une flèche) + ('faire de la place' pour insérer) + (sélectionner pour déplacer ou enlever...) + NB ces commandes doivent être graphiques et/ou accessibles par raccourcis ou en ligne +(5) les commandes d'édition globales + (ex: introduire, retirer, transformer +/-aléatoirement (n) objets dans l'espace) + NB une action effectuée sur une zone d'intérêt devrait pouvoir être automatiquement appliquée + à d'autres zones d'intérêt identifiées comme similaires +(0) NB >>> AUCUNE COMMANDE NE DOIT PERMETTRE D'EXÉCUTER UN RUN ! <<< +>>> L'objectif est que l'utilisateur ait accès à une organsisation aussi ergonomique que possible ----- + i.e : chaque utilisateur devrait disposer de 'préférences' + c'est-à-dire avoir la possiblité de faire des choix ergonomiques personnalisés. +*/ + diff --git a/tree.c b/tree.c new file mode 100644 index 0000000..99c6fbb --- /dev/null +++ b/tree.c @@ -0,0 +1,135 @@ +#include +#include + +#include + +#include "contain.h" +#include "texts.h" +#include "callback.h" + +// https://docs.gtk.org/gtk4/visual_index.html < widgets gallery +// https://docs.gtk.org/gtk4/section-text-widget.html +// https://docs.gtk.org/gtk4/class.Widget.html#height-for-width-geometry-management +// GTK_ORIENTATION_VERTICAL GTK_ORIENTATION_HORIZONTAL + +struct TreeNode_t {gchar *text; struct TreeNode_t *child, *next;}; + +static void add_child_node (struct TreeNode_t *parent, struct TreeNode_t *child){ + if (parent->child) { + struct TreeNode_t *cur = parent->child; + while (cur && cur->next) {cur = cur->next;} + cur->next = child; + } else parent->child = child; +} + +static struct TreeNode_t *create_user_tree_node (const gchar* text){ + struct TreeNode_t *node = g_malloc0 (sizeof(struct TreeNode_t)); + node->text = g_strdup (text); + node->child = NULL; // if (0) printf("create_user_tree_node %s\n", text); + return node; +} + +static void let_us_create_a_complex_useless_and_expensive_tree (struct TreeNode_t *tree_root) { + struct TreeNode_t *a = create_user_tree_node("We, the people");add_child_node(tree_root, a); + struct TreeNode_t *b = create_user_tree_node("in Order to"); add_child_node(tree_root, b); + struct TreeNode_t *c = create_user_tree_node("do establish"); add_child_node(tree_root, c); + struct TreeNode_t *aa = create_user_tree_node("aware of"); add_child_node(a, aa); + struct TreeNode_t *aaa = create_user_tree_node("our rights"); add_child_node(aa, aaa); + struct TreeNode_t *aab = create_user_tree_node("our duties"); add_child_node(aa, aab); + struct TreeNode_t *aaaa = create_user_tree_node("read"); add_child_node(aaa, aaaa); + struct TreeNode_t *aaab = create_user_tree_node("write"); add_child_node(aaa, aaab); + struct TreeNode_t *aaac = create_user_tree_node("copy"); add_child_node(aaa, aaac); + struct TreeNode_t *aaad = create_user_tree_node("edit"); add_child_node(aaa, aaad); + struct TreeNode_t *aaaba= create_user_tree_node("code"); add_child_node(aaab, aaaba); + struct TreeNode_t *aaabb= create_user_tree_node("language"); add_child_node(aaab, aaabb); + struct TreeNode_t *aaabc= create_user_tree_node("any art..."); add_child_node(aaab, aaabc); + struct TreeNode_t *aaadb= create_user_tree_node("publish"); add_child_node(aaac, aaadb); + struct TreeNode_t *aaada= create_user_tree_node("create"); add_child_node(aaad, aaada); + struct TreeNode_t *aaba = create_user_tree_node("learn"); add_child_node(aab, aaba); + struct TreeNode_t *aabb = create_user_tree_node("help"); add_child_node(aab, aabb); + struct TreeNode_t *ba = create_user_tree_node("promote"); add_child_node(b, ba); + struct TreeNode_t *bb = create_user_tree_node("individual"); add_child_node(b, bb); + struct TreeNode_t *bc = create_user_tree_node("and common"); add_child_node(b, bc); + struct TreeNode_t *bca = create_user_tree_node("education"); add_child_node(bc, bca); + struct TreeNode_t *bcb = create_user_tree_node("mutual"); add_child_node(bc, bcb); + struct TreeNode_t *bcc = create_user_tree_node("support"); add_child_node(bc, bcc); + struct TreeNode_t *bcd = create_user_tree_node("health"); add_child_node(bc, bcd); + struct TreeNode_t *bcda = create_user_tree_node("mental"); add_child_node(bcd, bcda); + struct TreeNode_t *bcdb = create_user_tree_node("physical"); add_child_node(bcd, bcdb); + struct TreeNode_t *ca = create_user_tree_node("free"); add_child_node(c, ca); + struct TreeNode_t *cb = create_user_tree_node("code"); add_child_node(c, cb); + struct TreeNode_t *cc = create_user_tree_node("access"); add_child_node(c, cc); +} + +void on_setup_user_tree_factory (GtkSignalListItemFactory *factory, + GObject* object, gpointer user_data){ + GtkWidget* expander = gtk_expander_new (NULL); + gtk_list_item_set_child (GTK_LIST_ITEM (object), expander); + if (0) printf("[on_setup_user_tree_factory] here is an expander\n"); +} + +static GListModel* get_user_tree_model_child (struct TreeNode_t *parent){ + GtkStringList *list = NULL; + if (parent) { + if (0) printf("[get_user_tree_model_child] here is %s content : ", parent->text); + struct TreeNode_t *child = parent->child; + if (child) {list = gtk_string_list_new(NULL);} + while(child) { + gtk_string_list_append(list, child->text); + if (0) printf("%s ", child->text); + child = child->next; + } + } // else printf("hot.c GListModel* get_user_tree_model_child (struct TreeNode_t *parent) child = %d \n", parent); + if (0) printf("\n"); + return G_LIST_MODEL(list); +} + +GListModel* get_user_tree_model (GObject *item, gpointer root){ + struct TreeNode_t *cur = (struct TreeNode_t *)root; + struct TreeNode_t *parent = root; + const gchar *string = gtk_string_object_get_string (GTK_STRING_OBJECT (item)); + while (cur) { + if (strcmp(string, cur->text) == 0) break; + cur = cur->next; + if (cur == NULL) {cur = parent->child; parent = cur;} + } + if (0) printf("[get_user_user_tree_model] looked for %s in %s item\n", cur->text, string); +// ! WARNING ! TODO CUR EST L'ENFANT, MAINTENANT DONC, SI CUR EST UNE FEUILLE, JE N'ATTEINDRAI PAS SON ENFANT + return get_user_tree_model_child (cur); +} + +GtkScrolledWindow *get_user_rules_tree () +{ + struct TreeNode_t *tree_root = create_user_tree_node("root"); + let_us_create_a_complex_useless_and_expensive_tree (tree_root); + + GtkStringList *model = gtk_string_list_new(NULL); + gtk_string_list_append (model, tree_root->text); + GtkSignalListItemFactory *factory = GTK_SIGNAL_LIST_ITEM_FACTORY (gtk_signal_list_item_factory_new()); + g_signal_connect (factory, "setup", G_CALLBACK(on_setup_user_tree_factory), NULL); + g_signal_connect (factory, "bind", G_CALLBACK(on_bind_user_tree_factory), NULL); + + GtkTreeListModel *tree_model = gtk_tree_list_model_new( + G_LIST_MODEL (model), + FALSE, // Passthrough - False in actual usage with dynamic children retrieval + TRUE, // FALSE, // autoexpand + (GtkTreeListModelCreateModelFunc) &get_user_tree_model, + tree_root, + NULL // (GDestroyNotify) free_user_tree_node + ); + + GtkSingleSelection *selection_model = gtk_single_selection_new (G_LIST_MODEL (tree_model)); + gtk_single_selection_set_autoselect (selection_model, FALSE); + gtk_single_selection_set_can_unselect (selection_model, TRUE); + GtkWidget *list_view = gtk_list_view_new (GTK_SELECTION_MODEL (selection_model), GTK_LIST_ITEM_FACTORY (factory)); + GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (gtk_scrolled_window_new()); +// Allocation height too small. Tried to allocate 1922x1030, but GtkNotebook 0x25cd4c0 needs at least 1922x1064. +// even if I remove (comment) the next line : + gtk_scrolled_window_set_child (scrolled_window, list_view); + gtk_scrolled_window_set_policy (scrolled_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_widget_set_vexpand (GTK_WIDGET (scrolled_window), TRUE); + gtk_widget_set_visible (GTK_WIDGET (scrolled_window), TRUE); + gtk_widget_set_visible (GTK_WIDGET (list_view), TRUE); + return scrolled_window; +} + diff --git a/tree.h b/tree.h new file mode 100644 index 0000000..880cf7b --- /dev/null +++ b/tree.h @@ -0,0 +1,40 @@ +/******************************************************************************/ +/* */ +/* E coli by David S. Goodsell (2009) */ +/* --- */ +/* Let this freeze frame guide us towards the model */ +/* that alone can account for the phenomenon ! */ +/* */ +/******************************************************************************/ + +#pragma once // < WTF !? + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +//#include "cold.h" +#include "display.h" +#include "contain.h" + + +// https://blog.gtk.org/2020/09/08/on-list-models/ < TODO + +GtkScrolledWindow *get_user_rules_tree (); +void set_run_edit_mode(int prescribed_mode); +int get_run_edit_mode(); +GListModel* get_user_tree_model (GObject *item, gpointer root); +void on_setup_user_tree_factory (GtkSignalListItemFactory *factory, + GObject* object, gpointer user_data); +