From 39cf432f6a30218b2545cf456b1b44eb35beac2b Mon Sep 17 00:00:00 2001 From: Jean Sirmai Date: Tue, 30 Apr 2024 18:59:44 +0200 Subject: [PATCH] GtkLevelBar < ? --- 0_application.c | 150 ++++++++++++++ 0_window.c | 236 ++++++++++++++++++++++ 2024-04-30.png | Bin 0 -> 178165 bytes exec.o | Bin 30624 -> 30528 bytes gg/GtkGLArea.c | 323 ++++++++++++++++++++++++++++++ gg/application.c | 150 ++++++++++++++ gg/arrows.c | 285 ++++++++++++++++++++++++++ gg/base.h | 119 +++++++++++ gg/displays.c | 295 +++++++++++++++++++++++++++ gg/draw.c | 207 +++++++++++++++++++ gg/events.c | 369 ++++++++++++++++++++++++++++++++++ gg/graphics.c | 328 ++++++++++++++++++++++++++++++ gg/graphics.h | 314 +++++++++++++++++++++++++++++ gg/grid.c | 162 +++++++++++++++ gg/init.c | 175 ++++++++++++++++ gg/parsing.c | 483 +++++++++++++++++++++++++++++++++++++++++++++ gg/parsing.h | 39 ++++ gg/random_walk.xml | 118 +++++++++++ gg/ui.h | 232 ++++++++++++++++++++++ gg/window.c | 236 ++++++++++++++++++++++ hot.c | 88 +++++++-- warm.c | 2 +- 22 files changed, 4294 insertions(+), 17 deletions(-) create mode 100644 0_application.c create mode 100644 0_window.c create mode 100644 2024-04-30.png create mode 100644 gg/GtkGLArea.c create mode 100644 gg/application.c create mode 100644 gg/arrows.c create mode 100644 gg/base.h create mode 100644 gg/displays.c create mode 100644 gg/draw.c create mode 100644 gg/events.c create mode 100644 gg/graphics.c create mode 100644 gg/graphics.h create mode 100644 gg/grid.c create mode 100644 gg/init.c create mode 100644 gg/parsing.c create mode 100644 gg/parsing.h create mode 100644 gg/random_walk.xml create mode 100644 gg/ui.h create mode 100644 gg/window.c diff --git a/0_application.c b/0_application.c new file mode 100644 index 0000000..11e5d47 --- /dev/null +++ b/0_application.c @@ -0,0 +1,150 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: User interface 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/base.h" +#include "../../include/ui.h" + +struct _GemGraphClientApplication +{ + GtkApplication parent_instance; +}; + +G_DEFINE_TYPE (GemGraphClientApplication, + gem_graph_client_application, + GTK_TYPE_APPLICATION) + + +static GemGraphClientApplication *application; + +/* -------------------------------------------------------------------------- */ + +void ui_enable_action(const char *name) { + g_simple_action_set_enabled( + (GSimpleAction *)g_action_map_lookup_action( + G_ACTION_MAP(application), + name), + true); +} + +void ui_disable_action(const char *name) { + g_simple_action_set_enabled( + (GSimpleAction *)g_action_map_lookup_action( + G_ACTION_MAP(application), + name), + false); +} + +/* + * Window actual presentation on screen + * + */ +static void gem_graph_client_application_activate(GApplication *app) +{ + GtkWindow *window; + + g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(app)); + + window = gtk_application_get_active_window(GTK_APPLICATION (app)); + if (window == NULL) + window = g_object_new(GEM_GRAPH_CLIENT_TYPE_WINDOW, + "application", app, + NULL); + + ui_set_stack(HOME_MODE); + + gtk_window_present(window); +} + +/* + * Action records are registered here + * + */ +static void gem_graph_client_application_init(GemGraphClientApplication *self) +{ + g_action_map_add_action_entries(G_ACTION_MAP(self), + app_actions, + G_N_ELEMENTS(app_actions), + self); + + // Setup shortcuts + gtk_application_set_accels_for_action(GTK_APPLICATION(self), + "app.quit", + (const char *[]) { "q", NULL }); + gtk_application_set_accels_for_action(GTK_APPLICATION(self), + "app.editmode", + (const char *[]) { "e", NULL }); + gtk_application_set_accels_for_action(GTK_APPLICATION(self), + "app.runmode", + (const char *[]) { "r", NULL }); + gtk_application_set_accels_for_action(GTK_APPLICATION(self), + "app.presentmode", + (const char *[]) { "p", NULL }); + gtk_application_set_accels_for_action(GTK_APPLICATION(self), + "app.savefile", + (const char *[]) { "s", NULL }); + + application = self; + + // + // Disable unneeded/inoperant actions + // + ui_disable_action("savefile"); + ui_disable_action("closefile"); + ui_disable_action("editmode"); + ui_disable_action("runmode"); + ui_disable_action("presentmode"); + ui_disable_action("togglesidebar"); +} + +void ui_send_notification(const char *message) +{ + g_print("NOTIFICATION: %s\n", message); + + g_application_send_notification(G_APPLICATION(application), + "notification", + g_notification_new(message) + ); +} + +/* -------------------------------------------------------------------------- */ + +static void gem_graph_client_application_class_init( + GemGraphClientApplicationClass *klass) +{ + GApplicationClass *app_class = G_APPLICATION_CLASS(klass); + + app_class->activate = gem_graph_client_application_activate; +} + +GemGraphClientApplication *gem_graph_client_application_new( + const char *application_id, + GApplicationFlags flags) +{ + g_return_val_if_fail(application_id != NULL, NULL); + + return g_object_new(GEM_GRAPH_CLIENT_TYPE_APPLICATION, + "application-id", application_id, + "flags", flags, + NULL); +} diff --git a/0_window.c b/0_window.c new file mode 100644 index 0000000..a7ed883 --- /dev/null +++ b/0_window.c @@ -0,0 +1,236 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: User interface 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 + +#include "../../include/base.h" +#include "../../include/ui.h" + +/* -------------------------------------------------------------------------- */ + +static GemGraphClientWindow *window; + +/* -------------------------------------------------------------------------- */ + +struct _GemGraphClientWindow +{ + GtkApplicationWindow parent_instance; + + /* Template widgets */ + GtkHeaderBar *main_titlebar; + GtkStack *main_stack; + GtkStack *side_stack; + GtkPaned *main_paned; + GtkMenuButton *main_button_mode; + GtkToggleButton *main_button_sidebar; + GtkRevealer *toast_revealer; + GtkToggleButton *toast_close_button; + GtkLabel *toast_text; + GtkBox *control_zone; + GtkBox *run_glarea_box; + GtkBox *edition_glarea_box; + GtkBox *presentation_glarea_box; +}; + +G_DEFINE_FINAL_TYPE (GemGraphClientWindow, + gem_graph_client_window, + GTK_TYPE_APPLICATION_WINDOW) + +static void gem_graph_client_window_class_init(GemGraphClientWindowClass *klass) +{ + gchar *contents; + gsize len; + GError *err; + GBytes *bytes; + + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + + if (g_file_get_contents("src/ui/gemgraph.ui", &contents, &len, &err) == FALSE) + g_error("error reading gemgraph.ui: %s", err->message); + + bytes = g_bytes_new_take(contents, len); + gtk_widget_class_set_template(GTK_WIDGET_CLASS(klass), bytes); + + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + main_titlebar); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + main_stack); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + side_stack); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + main_paned); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + main_button_mode); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + main_button_sidebar); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + toast_revealer); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + toast_close_button); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + toast_text); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + control_zone); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + run_glarea_box); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + edition_glarea_box); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + presentation_glarea_box); +} + +static void gem_graph_client_window_init(GemGraphClientWindow *self) +{ + gtk_widget_init_template(GTK_WIDGET(self)); + window = self; + + // Launch with sidebar off + ui_toggle_sidebar(); +} + +/* -------------------------------------------------------------------------- */ + +void ui_set_stack(int mode) +{ + //g_printerr("[debug] ui_set_stack()\n"); + + if (window->main_stack == NULL) { + g_printerr("Can't find self->main_stack !\n"); + return; + } + if (window->side_stack == NULL) { + g_printerr("Can't find self->side_stack !\n"); + return; + } + + // Switch on the first letter of the mode, because switch is soooo simple :) + switch(mode) { + case EDIT_MODE: + gtk_stack_set_visible_child_full(window->main_stack, + "edition", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_stack_set_visible_child_full(window->side_stack, + "edition", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_menu_button_set_icon_name(window->main_button_mode, + "document-edit-symbolic"); + ui_setup_glarea(EDIT_MODE, GTK_WIDGET(window->edition_glarea_box)); + break; + case RUN_MODE: + gtk_stack_set_visible_child_full(window->main_stack, + "run", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_stack_set_visible_child_full(window->side_stack, + "run", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_menu_button_set_icon_name(window->main_button_mode, + "system-run-symbolic"); + ui_setup_glarea(RUN_MODE, GTK_WIDGET(window->run_glarea_box)); + break; + case PRESENTATION_MODE: + gtk_stack_set_visible_child_full(window->main_stack, + "presentation", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_stack_set_visible_child_full(window->side_stack, + "presentation", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_menu_button_set_icon_name(window->main_button_mode, + "x-office-presentation-symbolic"); + ui_setup_glarea(PRESENTATION_MODE, + GTK_WIDGET(window->presentation_glarea_box)); + break; + case HOME_MODE: + gtk_stack_set_visible_child_full(window->main_stack, + "home", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_stack_set_visible_child_full(window->side_stack, + "home", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_paned_set_position(window->main_paned, 0); + gtk_menu_button_set_icon_name(window->main_button_mode, + "user-home-symbolic"); + break; + default: + break; + } +} + +void ui_send_internal_notification(const char *message) +{ + if (window->toast_revealer == NULL) { + g_printerr("Can't find self->toast_overlay !\n"); + return; + } + + if (window->toast_text == NULL) { + g_printerr("Can't find self->toast_overlay !\n"); + return; + } + + gtk_label_set_label(window->toast_text, message); + gtk_revealer_set_reveal_child(window->toast_revealer, true); + g_printerr("%s\n", message); +} + +void ui_close_internal_notification(void) +{ + if (window->toast_revealer == NULL) { + g_printerr("Can't find self->toast_overlay !\n"); + return; + } + + if (window->toast_text == NULL) { + g_printerr("Can't find self->toast_overlay !\n"); + return; + } + + gtk_revealer_set_reveal_child(window->toast_revealer, false); +} + + +void ui_toggle_sidebar(void) +{ + int position = gtk_paned_get_position(window->main_paned); + + if (position != 0) { + gtk_paned_set_position(window->main_paned, 0); + } else { + gtk_paned_set_position(window->main_paned, 400); + } +} diff --git a/2024-04-30.png b/2024-04-30.png new file mode 100644 index 0000000000000000000000000000000000000000..ff01e7cec7b53b3de3c1b77f3040bd9dca399e1d GIT binary patch literal 178165 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 z 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

M=Km4RSqSfLb=vcXK~!*{_bQ=6YMY+BEe~ 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�ymh#+K#C9hVlyw30awd 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 literal 0 HcmV?d00001 diff --git a/exec.o b/exec.o index f81c0112a3ba391e5c143dbfaadafb35646176ae..a34b54e2311d9543e051913b8cfe1cccad4df7b8 100755 GIT binary patch delta 11657 zcmZX42Rzl^|Np)A-kW4(W^c+~H+z$il~G1EN!Q9Iyd~K?6*3Fin{1MiQIw0!$VmL( z@5`sp@B8_m9O@NXtPux5r713l^UcgAkl$D1`-2E zm>@xo797NGe7MugT!IFj-0m9g{@I?R)_6F#l9IX)ol0Xd`x*tXNuhCW) zG(UsJ{6uTsq5FDB1JL2o!DZ1l6SVBFLI;;a&j?5NCFtHBjo?G~251d8+D9&$4?^pc z(ftQ>AB48Xqx(^Ge*}!;3IZ%XSU?Ik6~L`bhu;h)4vIAwkj7&NI5g;hV>~LL1&;{G z!xP7Kbh&NgdB+CW!LtA+@hAapeA;SL{77s7PD%;vl89Y`(hdjz^? zF<_&BA}J-DpxT%e7Y-+^wj|Sq!><5kE0!PK@PSmyPd^Q$1k{6uZ zYz7|Bjp!~2-vG*5(OYO0%Jt;z426gGu!V^3MiGOo@Gs#rR3T_+!4iU&=s@*=0_YS1 zoPe`iNI^ZS>R;swq`U$tv;I|%K}umECQuvoueJ%)3ZFGY)q+wy0Tel?v^x>8*pgsL zIv_~hra)fwf*(Ou{ysZ%Al=$PM632XkaB+mX%M6?5QOu8CSd%X5d0hTNQayR3;G{# zV;B4gN)Pmgi1q1hfzIUy7)uMN(271q%g_?2aV5b$mdEpHz3~)8b8~6?o9zz+T%}`N*+d;cO zU+LU~INJIPw4R$T0O-}mP_&>G5!OkEh@QHoXrXASXr*}DvV-)p3Jhk9i2in7l^7tX zr4`&PR3eX$|HjqF0L6W=UvL3bKNw3(KNOWUFvxj{FdvdXLb4Pn(~+Tz;Q^%l1}Vt^ z5>7gLbesl|asyJLj?U}49uCNJ(qeG^1{}HAkra^q5VS*Ec={LezbONAF$3-nj0F*E zdDz#H_-_bfpuU9+{UCLqjKTT;B=bKJq(e9s5Qh@_zl#9)+~jaifRX#Mp)G{qyYTew z@Sn~8e>>s*|8}Bis%WBUtY~zeR0hy4e0BqTeD#2M?n}t8;Cd~x(8_e6(-u{bg9?fe z6mEbI^EhbMiUwor2A^(JEvVIsh7J{VjAlz#|Y-|<`E#y!wP>3nDWR;Jv%r%Q;F3cP>EITRf#^11s`Il z{JJ4`v!Ijnx0P1(YQr`+_^z@+CuRY)2n_OErpRSgfGJv{mFU7+eFL2GNFeKeq3apk zDipp9xB^&$cv|T98oCNCS2;k}f2;7{r0IY&p*g;24=c^i=;b<4zd#ugJr6yl>!3T7 z1lS3K>FI&Wr5-f4+=rrWK~KNbCESXx0q|uC?g0!2bpSzpAxIW5!b^+%2+0p2IS@Ss znvn#S;J-7fA;e<{aq}2GI|~M@1aIf;EDe;Uz_Ak?55W<-MELKWoe6=X)Bf3+5jd8Bqc=Fx zfqO^;M>BAQUVKtevcVAnjwj%V2OgUc=obOVid=;|0nQ>bV>)9H;a=QYSRepM3IJS`9Zm#rh+c;C0jePH4>*H-8W1fiNR0ru z1YKjG2DyZ`sR9g&ieilH0~lhQ7^r=KSBw)*R;@3#fCsc|F3KS3;$mQEag9P$$#Yf|H#lC18UHP5Ne+Rdb!JR zAwXL02^^^Ile>)xuLF3L{NQ9jo>C+{22fO{rN;onA&0Ie;2RWbSm++q0UpY(FWurIp9?+!Xg%A7 zbqBHni>h>RCV*UxmYxm7L79{KPv!)GFRHZkW@s!7Q2qoMIlHvAH4{WO+Rv#fIF#gXynH^Zs3;`Uqc#)>c zSi-?1W`CG;(jH)nM;&MRf8@e%n?Q~Pm-w~5ZdPF~mQ%pbm!p60i38K*#e+VOK<(nl zV8opNEBj~Gng^yB8`CeW1PwKTO-PBX(hPg_Rx~(^fym3-EFr3)yR;1)E$e_yRC{6t<%!rOs zqr0P9jBBQGaziMHGJlO#cT{(mcuHPP^}6!o{X~;@a4n8BOY^zcdl|2C+iQQ_+x*SK zQblrio^?L&@D5Jp6K5YeRh>a0>!Z-`ljJKp`Ry{L9Bq31>g4NW`xR3O_vSIo3P&>) zJ|J0yyk3N8IzKP7{_Iv&Gj9Gp^1j`#;a27nceV_r9+fwlxMCZ=wxWWpkBTD+;=2e- z@Wtx7MX+Wyblg<=yJr?c)0>JhRRWdu#Ax{ziL2dJ4ZA0pBR;C}_SATw=t8{byyesd}dpBU+R$if+S$FWUzcCe86E>msT?VbvxX!ljiR0cY zdncmTB@3Iguj-r;PF4pH#+=4~`?6hrFqbwX@fx#@@Jo8Tw{`RuE)e{O#a5HmTsQwj zs=-W?Z-L#E!mwMlAlfy=iTry8>AY&E4l)8oN3C4vM4~Us+7OeLXHgS3b&vI!Mwq&> zd%trYZ?xdbtL1#{&Uu_sW(s4EQOwSH+))}^hC001Rs5)!mrmdFbIA7jz8}+%y2d4+ zYPMNld6F)MGeZ<4{&YOvEOKb?Q}_e?mkS#&bWRjYgpH4Lu)|jQDhv6?&v=&8PV|v^ z7WazD%tgnW`t>5kMP(-fBBq%Lo@WbAm<7eEA{aP>62Jbsvzi+Bd5!AbM$9atYa`hE zb=>D6{m+le>a_Jgp9;)XCCwJa+?v_+$*`QB-BP=?dVp8FAmBaa;pZ{;`A{;$g7Z{t z!?6B`G5KtDzVZ0?{kyu^ubqE-#a}Z{MXt(fSf>6Qo%Atyd2dzS;+YBcmFH81om#-P=%e~?KlqhoR_4w;nqwmY}SMs>7&a5%< zcj;(Rn`e$4e+;b;NjqxyCYH2RyTfRrc`b&dW`ltL!``=cOihobtEpd8oOs*}Fg6X4 z7%_S`#U~^@-m)%j7!Eiht>G zEpD-!E!K~@41)l@Df z%V|uZ1TLvPl{c+O*CPk{LK=jYopS}=0GL7~gIK6tctc|scFVXF3ZtqD*3g(bvv8Nf zy9sZVwV}W^Uc7E=Y&g_S2gPRQqEf;CW0|p{lbHU^OJ=P#u|<={M>REZk{TbbBblBD za0X8Y6Tueopdw`4=mcnmF_ASQU+aab@V=?;c@){OTc#Jp(7Hv zpQ2!C_rLmv&jWMxX|6%-mrW@eHxeWUg5UekbkRfwFRF5FA#ZpnxsW0GN(8Bda&xqE z&n>SjW;(l|tG3e8Nswd1>lFWe?TsciQ{i_g8j?M1yjK+RURgYdoWW==?D4 z-@YMs01xY?$l!TM@38VhJg=vIly@rDSWo#_ab!4u%X47Y}Bi~^v zD1C?3tB0cCWxA4)s5+JfnfQ{43{t{1c29NWO(7|6Okn&>-1<|8l&O6Bmrk24=HOJq zAEFYfXAu;4vx$tE_fb3?Mma*$napK*G(R^?=iRM;;=4{o2D9h20CFzw?`~|2N)^$& z_c@$s&(BtVkZYuu#=N$8>BpsvE&l+*W(M)jW=wTn?}fZAa1fXCj~ertmxN{xF=jSN)}ea*Ki5<$~3rdDWw8xd}u> ziWMHY9p5gwu5v@I{&D&kkC>c_RyVVXd2**=VlAmE`;DtvWC(f;L>4ZR41?v)m*X3n zEIxvNiv0|KX~*^$ehJ`B17R#%hmofxtVb9%a3W7vw1p~^I= z@^;t!UUp{a5<4i_bwBAFsIT)DkNzr1X1V$B-4Ge6cc30JxtLHZ#kUInz06+Kah=duYag z<395cpNfz}BksomZ~oMQTGX$TJ7Asmx@;#Rzj2mMM$XbJ0$YI+I@l}?6^y6C+JRWel0%pICmoHK>)v}K zNhEkQ+4+Cn9*xWB?T59Kf;SnJjT1}p(WBH-*~$voCBl2Ud;%qv{u^H0W~oW-JP7&^M8y%)4AH;J}&Us`i-F#$JMq`m@s0D}Fu9 zT`pES*o5<3mb?2?q6YZ|xO}zGhuM=_3I*E?U{cQ8Zz8Wp;x3+1?AE;i8h=WxgbYzG z5=!Ts$t6AKp&=QozAxhb)HwQhdyzgklWK-`d}5jOYN$QukIP8K;m`$^e#^=``d9;k zR|7G=-uNtg=C)?jrlPZeU+p{pVK{fey~lS-x{0V+<<2hUDJi?~n_?H@oyX#hM{PMJ z5zDJn9?tD+NM(uxfx!;eRNrNRR|>+SGoe!zGQRq0`-NP`OEwSeCS2oGazekcuk+kp zTAJDH{VsN0*}k#>`Qq9oece!MS{tXELH-32_rAoxa-F4Ohe^MC9ZQ{Bu+#z*>b7+W z3!pTQpj`Ah#-TEN5<}7W$!J}kl|d^X&O^j!#T>KB7!iz}&!A25O>4r`g)cXN*FP$b zp|2sNIW#c(Iigc~kN81m8of%*msMo&{hs?7`=M@iuOsb}R9?pygpX$Vy5Xpv z(&w3LzVgXyskF>!v$cDS5!;!`M^~B`NsSfmXj!ezUAdeMB)+&B+HXoAKKZ&HA!IhR z^-7O`=V`rGbjnIJA}5xujOOkS;-4Qh3cVVelQxam29uLaRFgKT@BWbSdO@)o`-g4A zgiV&4eU3?WMsNZ-HT<2NV{G`hs!Xwp3o- zlNEmwEBtV7Ubrc2rF_YR7H8_x+c@7zvz)i&nOUscY7efHx+D1yS7=^fmoH3q#9ccw zT`VV1>Bjs?9#wut{T+S&yXc^&&B^O&*J$21$0bBwUkd#5*FRV2;Z@J=RPK3ny2O2G8tEROR|>IPd+gux;?^nmh?|dmTSokV;m9ox^4c&^C2f+31)0Dw+z|#cJB4~ z#=EGG^bWU*bJ%s|CoP00oiTbBq4s&#c6{nwgMm`DOy^+pcO#P9m)q;-lEQ?tD*1*g zm`4*m^vxdW1yN2XuqITjL`ykE84@}ziJt(gn(aW2`5QtU2*YQ;BkxT=X6qFBhoFyJ@D(#`p@C zzlwE4jTVcIQ7OtA7aYE3voSUh)$~UAQza3z{ux)5*z==lqF-lYY=2+wFF&a&5srMk zoZH>{!7a%jX#&b(aBjTm#E{6kw1J4`gpaJ%c{<+y4avmtZfQ2g^tixL^63%2Y~n6^ zi9PYp1^N;-8B(_$lt0IV3U9JheF<--R1rp*A%1CZu@OAXvj0%y5_?RsRe4K% z{Sn#rASOk1dPEx(+#K~K_S9+aD3?ky_A4X5ad5q~Pg_#H(zK z{k+q9k*p3+s#xc5f`Fg?5{0oYB@~)!_R5yM>~e&yKBCMCi$x*%UEMi(d5Vvb7A0_8 z=f*5|=dpCt&M(IbJ)JSdE+{$^jNu3{M z)!vGe2z>t^+N>QSi`Jh*ZJA974AOENz7rc33n^yVL?D(+Muo|N1>aC0Kxq z$uB+hoGAL__OnG5dfe4me}0@7O;|l`!S&H~#C)&mlWx_AFHT8IY9K2m=v39kw#+yl zu9-RT5$kSO60yN3oTMra$*Nfk4(rTIel96@Ed73kO6VoLZXu@fVpQJ#`O_;rs!M8P zpAZXrt*(Q8%G;XJE#b{EGObt4x0a*hsGe;1-Ba}!tAjsjhsn=&203{l(m!*%jC`5S zBc2nKa2vXmbm#q~%hEhc&C#Wdll1MjiuuB0GL|akI-{fD3J?C5FIvuEo?o;p0XHjV zf=d!+6#a#b|W*>VDBo&pLDCe3+zh zxkAUlkAXAf`&Z(}JQr{?<|5|<;m&b*#s zs(3MXir|be!i$B^Xt;JG6VJ98F!w0gkpM0Z?q0J|UQmGHuHDXOZcI7~szSP0CWfEk zo#n5hN;S7abV-ERO53#Yh1@i53T7u?YAwS`v#8vo&WNx_v2jRE@k!FB?{&Mpb8ZSG z5_(T{ci=sW#!lk-W_rd?qwr6UxSOko9#2rfMwXUqpT^b9h`BCH>=_dtSmxobStCs~ zKLvL>DwyMb>r-wbKW?dGQ+O9)NZDej!XxK;Rc<_Hxae!Zt)2W;#i+s+1P@=LE*pBm9A65Uz?i7 zyS2lETwJmfYSD^4o?T@!iQW0qhH-C?Wb7QO_J_qC-qZiMxfRRw@ln*A0Qsx%-+}$9 zEe;%}IFUYM;}Yq^E@DqJhl4ts%?j9$qE6>+++@}>> z`GvcmNobD+PuSX3HihqPnFm&~hzb5O?|L2nwXCKqmc@WvckFAQa)yDdKaUkw+af7d zN;WmMyU8p6?XLrF0OuHDe=+Q!>3P=l-1Jd%5TgMe9(y^GkhL&H{??Oi^(sf)WER8B zBEN)r(>-5(g}%bO_v8mz2~DK}QZc=VB=H(&i4O3TNa>h`uix<>tQg!*_;O7dLC$nX zK_mR5nnT<(YOY1qq%l`S26rQDmB;^q{|<+(dDZ0))kty=-)Cg+Z1R*0Xd@0q3o+OE zFQc?2{Z&<*kxx4*Ra!=P3lL5>McSmMDP1y3@tb#dC149!h|g8c!x`(rEk7ySPEO6p zPmOogLU(0kEZefWQ|nB7(q{wSwf&ADc{W?w|MGpYt(C%BuTm;=QB;a__1GckI|*sM+wnG;| zu^ZnL9T-1Fo){M&2xESL@nKdFZO3U&+gkH4%HF!xxJ&vrMSW4ULT*GkwH+31|Dq>) zSqg^(2elWb%%OERCdyEN;+uocns2p*nN;Ld{>JdFP2K5Ig>kBpZ~1RwONki@6rOab zFd`<0YG0S?R#)W~_Nttzok4o5fp>$xn*KGN->8ZLkbM}QZ{y}0L_Ec=n(&wn)%a=e zrfqTm+~^|NOaFC`c4Ef`|DjHahKrT$>*Lo)Z#ud>H{v>YWNe!i7y{Tc!@r+uE4hZL z6jj_e!~e!3UGt`(EZuo!2X5G|(HM5+wJ%R-Nt?pYJXDeC|ZL{^-}Y^=I;& z;~nMFWQKFj+BU)`$j6b+*iCjudR>HO6vjq=?#MYE_ZHpaxTmvyVwja#iAckMMTZ8% zWrY{<%k6rP=~`{YIb$erV`?j&cyl~`J|)TYJjlLH^=LurR+mjWZa`+yp|Hib9X`Ye zA?LSY6UNSpO86Hi9U{eADwnUPrSxjVzmg=v^|$(>?F4FA^K(n!MD3ZMXr@h?ZN|im zQlgws1zoan%E~;ExyV?+AP?j>?pjSrQfJ z-ng&^hgdc#HkJ+IQeVa5HbUwWuDc4!OYzkUn3w(bmHb^~tj3%=Tk16D?LJf?I`KLy z5cee8BEQkjiMSN?CRJ(261l)ado0;Q&L`(M6UT;IBZTiGgVQY# z9e!IQPgCOy-&#<&68|Xqrr2Qq45roRw>%wEhx3vBC98%3-EHSdpEYviEQtzv_8n)2 zAx|d0-TOY3R`S>%?ntSZ7587G@LvhO|4Ixsn<`~1+2dP_s)!db;%wNnr%~#$M*hWhY|jCnJ(fEDt79Qi@J|u`0E` zGVLt9GEK4XvKBM7pxcC?5b%^Q6UH2Vdqm1!}ZK1%Ldcy z%#FA7SRU+hC*Ua>)lOB<#mI_e1hJ54~yTbfqRYUMlp}y)*X&=gVLWGX)JTO+sGE1d#CWsPRX$n+5Bb4 zT!!~Mj$WGz0n^5(6VgRzOurpym!?0tdlXE&y}dJ+BG247{i?V!Z7NyG(R-RU{Y-5D z&}&Uha-SCysCDeIrF&?#EZa^q;nDj;xb(eR!Crp_e->>XpdZ^WlH^sQMoASvY(?m- zO*}v~nHv^<|09z93NmQ>^+%5Fx>7YfDGv_m{l^R2GoH$i}}QW!OUoH%5m20&fy^PEkzHRyvL=#%^+K53G_?71ydWd*R5M9$2?e&?>)MIl}Ev zy^?i)q4}Hh2=Kp9q4xKNgUqx9S~PFzQ}t{~A2jMMSr<*U!HA6|Nfhi2@?s}9V!dm)guhoD4g3&)g$YzAJ6z|m{b$eZK4$3dn&T?7ilzqLf{pO&P$x6+Nb;>xl zBKDtW=}|VJZ==4@e5}`fWV!q7)!X=9k7vi`1D|A;TDk9JhT8Q!9F{h_F_K`%rEO@U zm+G0opZy|8@%P?zCI6!r$f{hCAkW5vpNr-5fJ|V+tNNT*avuj}Y+I}1Zgz8wrtV$K z`Ncr1a;w$V-j&g>qG)dGPSF98nN--q!^JiHw;S91)GZWc%3`YpLL(Pk+U zyKaJ@5YCnoLFDghfD_XmdmpQ;xlFLLDbfJ8lp=y-N)(Af5}zlX98O}`tK6|6%|>O8 zNmn2au(L^%U@@gJCCx^_qefdfTd`ajl(mRB;2d^Q)A?cBnK(}r1RWgB@vXFe3Tp{| zs7k#v!~MP`xap>bC~`z`A;Ab&cba@}3;dIO*S4%J(;`y3o=Lx%$$bQ=!P)<Qr6N@P~&(la0gluE46rBk5I^D?mLLx*2tcdkJKa9>G$Zl`l808j*_66bR% a76|c`go^_8zL9VbK+#VUt^ox2as59?xG^{Y delta 11791 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 + * + * 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/base.h" +#include "../../include/ui.h" +#include "../../include/graphics.h" + +struct stack_index_t { + long stack_id; + void *container_widget; + void *gl_area; +}; + +static struct stack_index_t *stack_index = NULL; +size_t stack_index_size = 0; + + +/* + * Look for stack entry and returns stack_id + * + * @params container_widget, generally the GtkBox that contains the GLArea + * + * @returns stack_id + */ +long ui_get_graphic_stack(void *container_widget) +{ + // look for stack_index entry + for (int i = 0; i < stack_index_size; i++) { + if (stack_index[i].container_widget == (void *)container_widget) { + return stack_index[i].stack_id; + } + } + return -1; +} + +/* + * Look for stack entry and returns stack_id + * + * @params container_widget, generally the GtkBox that contains the GLArea + * + * @returns stack_id + */ +long ui_is_graphic_stack_ready(void *container_widget) +{ + // look for stack_index entry + for (int i = 0; i < stack_index_size; i++) { + if (stack_index[i].container_widget == (void *)container_widget) { + return stack_index[i].stack_id; + } + } + return -1; +} + +/* + * Look for stack entry and initializes OpenGL for it + * + * @params container_widget, generally the GtkBox that contains the GLArea + * + * @returns bool, true if success + */ +bool ui_init_graphic_stack(void *container_widget, GError *error_buffer) +{ + //g_printerr("[debug] ui_init_graphic_stack()\n"); + + //g_printerr("[debug] ui_init_graphic_stack() : target is %p\n", container_widget); + + // look for stack_index entry + for (int i = 0; i < stack_index_size; i++) { + //g_printerr("[debug] ui_init_graphic_stack() : i is %d\n", i); + //g_printerr("[debug] ui_init_graphic_stack() : target would be %p\n", + //stack_index[i].container_widget); + if (stack_index[i].container_widget == (void *)container_widget) { + stack_index[i].stack_id = graphics_init(&error_buffer); + //g_printerr("[debug] ui_init_graphic_stack() : stack_id is %d\n", + //stack_index[i].stack_id); + if (stack_index[i].stack_id >= 0) + return true; + else + return false; + } + } + return false; +} + +/* + * Look for stack entry and shutdowns OpenGL for it + * + * @params container_widget, generally the GtkBox that contains the GLArea + * + * @returns bool, true if success + */ +bool ui_shutdown_graphic_stack(void *container_widget, GError *error_buffer) +{ + // look for stack_index entry + for (int i = 0; i < stack_index_size; i++) { + if (stack_index[i].container_widget == (void *)container_widget) { + if (graphics_shutdown(stack_index[i].stack_id, + &error_buffer) == false) { + return false; + } + stack_index[i].stack_id = 0; + return true; + } + } + return false; +} + + +void ui_clean_stack_index(void) +{ + // look for stack_index entry + for (int i = 0; i < stack_index_size; i++) { + stack_index[i].stack_id = 0; + } + return; +} + +/* + * Look for stack entry and triggers OpenGL for drawing + * + * @params container_widget, generally the GtkBox that contains the GLArea + * + * @returns bool, true if success + */ +bool ui_render_stack(GtkWidget *container_widget) +{ + // look for stack_index entry + for (int i = 0; i < stack_index_size; i++) { + if (stack_index[i].container_widget == (void *)container_widget) { + graphics_draw(stack_index[i].stack_id); + return true; + } + } + return false; +} + +/* + * Look for stack entry and triggers OpenGL for drawing + * + * @params container_widget, generally the GtkBox that contains the GLArea + * + * @returns bool, true if success + */ +bool ui_update_axis_stack(GtkWidget *container_widget, int axis, int value) +{ + // look for stack_index entry + for (int i = 0; i < stack_index_size; i++) { + if (stack_index[i].container_widget == (void *)container_widget) { + graphic_stack[stack_index[i].stack_id].rotation_angles[axis] = value; + gtk_widget_queue_draw((GtkWidget*)(stack_index[i].gl_area)); + return true; + } + } + return false; +} + +/* + * Look for every stack entry and shutdowns OpenGL for it + * + * @params void + * + * @returns bool, true if success + */ +void ui_shutdown_all_graphic_stacks(void) +{ + // look for stack_index entry + for (int i = 0; i < stack_index_size; i++) { + graphics_shutdown(stack_index[i].stack_id, NULL); + } + return; +} + +/* + * Creates a slider widget + * + * @params axis, meaning which axis we're building (for label) + * + * @returns GtkWidget*, pointer to the new widget + */ +GtkWidget *create_axis_slider(int axis) +{ + GtkWidget *box, *label, *slider; + GtkAdjustment *adj; + const char *text; + + box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + + switch (axis) { + case X_AXIS: + text = "X"; + break; + + case Y_AXIS: + text = "Y"; + break; + + case Z_AXIS: + text = "Z"; + break; + + default: + g_assert_not_reached(); + } + + label = gtk_label_new(text); + gtk_box_append(GTK_BOX(box), label); + gtk_widget_show(label); + + adj = gtk_adjustment_new(0.0, 0.0, 360.0, 1.0, 12.0, 0.0); + g_signal_connect(adj, "value-changed", + G_CALLBACK(on_axis_value_change), + (gpointer) label); + slider = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, adj); + gtk_box_append(GTK_BOX(box), slider); + gtk_widget_set_hexpand(slider, TRUE); + gtk_widget_show(slider); + + gtk_widget_show(box); + + return box; +} + +/* + * Creates GLArea and indexes it + * + * @params target_mode, meaning which ui_stack we're on + * target_widget, meaning the box that will host the GLArea + * + * @returns bool, true if success + */ +bool ui_setup_glarea(int target_mode, GtkWidget *target_widget) +{ + GtkWidget *gl_area; + + ////g_printerr("[debug] ui_setup_glarea()\n"); + + assert(target_widget); + + ////g_printerr("[debug] ui_setup_glarea() : target is %p\n", target_widget); + + if (stack_index == NULL) { + stack_index = g_malloc(sizeof(struct stack_index_t)); + stack_index_size = 1; + } else { + // look for stack_index entry + for (int i = 0; i < stack_index_size; i++) { + if (stack_index[i].container_widget == (void *)target_widget) { + return false; + } + } + // create entry + stack_index = + g_realloc(stack_index, + ++stack_index_size * sizeof(struct stack_index_t)); + } + + gl_area = GTK_WIDGET(gtk_gl_area_new()); + assert(gl_area); + + //gtk_widget_set_size_request(gl_area, 1000, 1000); + gtk_gl_area_set_auto_render(GTK_GL_AREA(gl_area), true); + gtk_widget_set_hexpand(gl_area, TRUE); + gtk_widget_set_vexpand(gl_area, TRUE); + //gtk_widget_set_halign(gl_area, GTK_ALIGN_CENTER); + //gtk_widget_set_valign(gl_area, GTK_ALIGN_CENTER); + + // The main "draw" call for GtkGLArea + g_signal_connect(GTK_GL_AREA(gl_area), + "render", + G_CALLBACK(on_glarea_render), NULL); + + g_signal_connect(gl_area, + "realize", + G_CALLBACK(on_glarea_realize), NULL); + + g_signal_connect(gl_area, + "unrealize", + G_CALLBACK(on_glarea_unrealize), NULL); + + stack_index[stack_index_size-1].container_widget = + (void*)target_widget; + + stack_index[stack_index_size-1].gl_area = (void*)gl_area; + + ////g_printerr("[debug] ui_setup_glarea() : set target to %p\n", target_widget); + + ////g_printerr("[debug] ui_setup_glarea() : stack_index (@0x%p) had %ld elements\n", + //stack_index, + //stack_index_size); + + gtk_box_append(GTK_BOX(target_widget), gl_area); + gtk_widget_show(GTK_WIDGET(gl_area)); + + // Create sliders + for(int i = 0; i < N_AXIS; i++) + gtk_box_append(GTK_BOX(target_widget), create_axis_slider(i)); + + return true; +} diff --git a/gg/application.c b/gg/application.c new file mode 100644 index 0000000..11e5d47 --- /dev/null +++ b/gg/application.c @@ -0,0 +1,150 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: User interface 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/base.h" +#include "../../include/ui.h" + +struct _GemGraphClientApplication +{ + GtkApplication parent_instance; +}; + +G_DEFINE_TYPE (GemGraphClientApplication, + gem_graph_client_application, + GTK_TYPE_APPLICATION) + + +static GemGraphClientApplication *application; + +/* -------------------------------------------------------------------------- */ + +void ui_enable_action(const char *name) { + g_simple_action_set_enabled( + (GSimpleAction *)g_action_map_lookup_action( + G_ACTION_MAP(application), + name), + true); +} + +void ui_disable_action(const char *name) { + g_simple_action_set_enabled( + (GSimpleAction *)g_action_map_lookup_action( + G_ACTION_MAP(application), + name), + false); +} + +/* + * Window actual presentation on screen + * + */ +static void gem_graph_client_application_activate(GApplication *app) +{ + GtkWindow *window; + + g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(app)); + + window = gtk_application_get_active_window(GTK_APPLICATION (app)); + if (window == NULL) + window = g_object_new(GEM_GRAPH_CLIENT_TYPE_WINDOW, + "application", app, + NULL); + + ui_set_stack(HOME_MODE); + + gtk_window_present(window); +} + +/* + * Action records are registered here + * + */ +static void gem_graph_client_application_init(GemGraphClientApplication *self) +{ + g_action_map_add_action_entries(G_ACTION_MAP(self), + app_actions, + G_N_ELEMENTS(app_actions), + self); + + // Setup shortcuts + gtk_application_set_accels_for_action(GTK_APPLICATION(self), + "app.quit", + (const char *[]) { "q", NULL }); + gtk_application_set_accels_for_action(GTK_APPLICATION(self), + "app.editmode", + (const char *[]) { "e", NULL }); + gtk_application_set_accels_for_action(GTK_APPLICATION(self), + "app.runmode", + (const char *[]) { "r", NULL }); + gtk_application_set_accels_for_action(GTK_APPLICATION(self), + "app.presentmode", + (const char *[]) { "p", NULL }); + gtk_application_set_accels_for_action(GTK_APPLICATION(self), + "app.savefile", + (const char *[]) { "s", NULL }); + + application = self; + + // + // Disable unneeded/inoperant actions + // + ui_disable_action("savefile"); + ui_disable_action("closefile"); + ui_disable_action("editmode"); + ui_disable_action("runmode"); + ui_disable_action("presentmode"); + ui_disable_action("togglesidebar"); +} + +void ui_send_notification(const char *message) +{ + g_print("NOTIFICATION: %s\n", message); + + g_application_send_notification(G_APPLICATION(application), + "notification", + g_notification_new(message) + ); +} + +/* -------------------------------------------------------------------------- */ + +static void gem_graph_client_application_class_init( + GemGraphClientApplicationClass *klass) +{ + GApplicationClass *app_class = G_APPLICATION_CLASS(klass); + + app_class->activate = gem_graph_client_application_activate; +} + +GemGraphClientApplication *gem_graph_client_application_new( + const char *application_id, + GApplicationFlags flags) +{ + g_return_val_if_fail(application_id != NULL, NULL); + + return g_object_new(GEM_GRAPH_CLIENT_TYPE_APPLICATION, + "application-id", application_id, + "flags", flags, + NULL); +} diff --git a/gg/arrows.c b/gg/arrows.c new file mode 100644 index 0000000..56b0e5f --- /dev/null +++ b/gg/arrows.c @@ -0,0 +1,285 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: OpenGL utils header + * + * Copyright (C) 2023 Jean Sirmai + * Copyright (C) 2023 Arien Bourmault + * + * This file is part of Gem-graph. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#include "../../include/base.h" +#include "../../include/graphics.h" + +/* I'm standing on Earth (any planet or star or spinning spheroid, in fact) + * and looking towards its North pole + * + * X - X = EAST - WEST = rouge - cyan + * Y - Y = ZENITH - NADIR = vert - magenta + * Z - Z = NORTH - SOUTH = bleu - jaune + */ + +int draw_one_arrow_vertex (const int stack_id, + int space_X_int, + int space_Y_int, + int space_Z_int, + int weight, + int site, + int arrow_x, + int arrow_y, + int arrow_z) +{ + float max = fmax(space_X_int, space_Y_int); + max = fmax(max, space_Z_int); + + float i = arrow_x, j = arrow_y, k = arrow_z; + + float vx = (2 * i / space_X_int - 1) * space_X_int / max + (1 / max), + vy = (2 * j / space_Y_int - 1) * space_Y_int / max + (1 / max), + vz = (2 * k / space_Z_int - 1) * space_Z_int / max + (1 / max); + + graphics_draw_vertex(stack_id, vx, vy, vz); + graphics_draw_color(stack_id, 0.4f, 0.4f, 0.4f); + + // réduit légèrement les longueurs des flèches + // pour qu'elles s'arrêtent avant les faces des cubes + GLfloat arrow_tip_padding = (1 / max) / 10; + + switch(site){ + case EAST: + graphics_draw_vertex (stack_id, vx - (site % 2 - 1) * (1 / max) + (site % 2 - 1) * arrow_tip_padding, vy, vz); + graphics_draw_color (stack_id, 1.0f, 0.0f, 0.0f); + break; + case WEST: + graphics_draw_vertex (stack_id, vx - (site % 2) * (1 / max) + (site % 2) * arrow_tip_padding, vy, vz); + graphics_draw_color (stack_id, 0.0f, 1.0f, 1.0f); + break; + case ZENITH: + graphics_draw_vertex (stack_id, vx, vy - (site % 2 - 1) * (1 / max) + (site % 2 - 1) * arrow_tip_padding, vz); + graphics_draw_color(stack_id, 0.0f, 0.6f, 0.1f); + break; + case NADIR: + graphics_draw_vertex (stack_id, vx, vy - (site % 2) * (1 / max) + (site % 2) * arrow_tip_padding, vz); + graphics_draw_color(stack_id, 0.6f, 0.1f, 0.7f); + break; + case SOUTH: + graphics_draw_vertex (stack_id, vx, vy, vz - (site % 2 + 1) * (1 / max) + (site % 2 + 1) * arrow_tip_padding); + graphics_draw_color(stack_id, 0.05f, 0.4f, 1.0f); + break; + case NORTH: + graphics_draw_vertex (stack_id, vx, vy, vz - (site % 2 - 2) * (1 / max) + (site % 2 - 2) * arrow_tip_padding); + graphics_draw_color(stack_id, 1.0f, 1.0f, 0.0f); + break; + default: break; + } + + return 2*3; +} + + +int draw_one_arrow_line(const int stack_id, int offset_vertex) +{ + graphics_draw_line (stack_id, offset_vertex + 0, offset_vertex + 1); + return 2; +} + + +/* + * Depends on set_arrow() + * Exchanges current and required site values + * when the address of the arrow to be set is already occupied + */ +static int rewrite_arrow (const int stack_id, + int address, + int load, + int site, + int x, + int y, + int z) +{ + struct graphic_stack_t *stack = &graphic_stack[stack_id]; + printf("WARNING in rewrite_arrow() <> address or address / 5 ? (et pourquoi ?)\n"); + stack->arrows_ptr[address].load = load; + return 1; +} + +/* + * Depends on set_arrow() + * Creates the arrow to be set with the required load at the required address + */ +static inline int create_arrow (int stack_id, + int arrows_nb, + int space_X, + int space_Y, + int space_Z, + int load, + int site, + int x, + int y, + int z) +{ + struct graphic_stack_t *stack = &graphic_stack[stack_id]; + void *newptr = g_realloc(stack->arrows_ptr, (arrows_nb + 1) * sizeof(struct arrow_t)); + + if (newptr) + stack->arrows_ptr = newptr; + else + perror("In create arrow, can't allocate new arrow buffer !\n"); + + stack->arrows_ptr[arrows_nb].load = load; + stack->arrows_ptr[arrows_nb].site = site; + stack->arrows_ptr[arrows_nb].x = x; + stack->arrows_ptr[arrows_nb].y = y; + stack->arrows_ptr[arrows_nb].z = z; + + draw_one_arrow_vertex(stack_id, space_X, space_Y, space_Z, load, site, x, y, z); + draw_one_arrow_line (stack_id, stack->buffer_vertex_size / 3 - 2); + + arrows_nb ++; + + return arrows_nb; +} + +/* + * Depends on set_arrow() + * Erases the arrow at the required address + */ +static inline int erase_arrow (const int stack_id, + int arrows_nb, + int arrow_address_in_list, + GLuint site, + GLint x, + GLint y, + GLint z) +{ + struct graphic_stack_t *stack = &graphic_stack[stack_id]; + if (arrows_nb == 0) assert (stack->buffer_lines_size == + stack->buffer_lines_0_arrow); + if (arrows_nb == 0) { + stack->buffer_lines_size = + stack->buffer_lines_0_arrow; + return 0; + } + + assert (arrows_nb); + arrows_nb --; + + if (arrow_address_in_list < arrows_nb) + { + stack->arrows_ptr[arrow_address_in_list].load = + stack->arrows_ptr[arrows_nb].load; + stack->arrows_ptr[arrow_address_in_list].site = + stack->arrows_ptr[arrows_nb].site; + stack->arrows_ptr[arrow_address_in_list].x = + stack->arrows_ptr[arrows_nb].x; + stack->arrows_ptr[arrow_address_in_list].y = + stack->arrows_ptr[arrows_nb].y; + stack->arrows_ptr[arrow_address_in_list].z = + stack->arrows_ptr[arrows_nb].z; + } + + for (long i = 0; i < 6; i++) + stack->buffer_vertex_origin [stack->buffer_vertex_0_arrow + arrow_address_in_list * 6 + i] + = stack->buffer_vertex_origin [stack->buffer_vertex_size - 6 + i]; + + for (long i = 0; i < 6; i++) + stack->buffer_colors_origin [stack->buffer_colors_0_arrow + arrow_address_in_list * 6 + i] + = stack->buffer_colors_origin [stack->buffer_colors_size - 6 + i]; + + stack->buffer_vertex_size -= 6; // <<< l'inverse de ce qui est fait dans : graphics_draw_vertex() + stack->buffer_colors_size -= 6; // <<< l'inverse de ce qui est fait dans : graphics_draw_colors() + stack->buffer_lines_size -= 2; // <<< l'inverse de ce qui est fait dans : graphics_draw_line() + + void *new_arrows_vertex_ptr = g_realloc(stack->buffer_vertex_origin, stack->buffer_vertex_size * sizeof(GLfloat)); + if (new_arrows_vertex_ptr) stack->buffer_vertex_origin = new_arrows_vertex_ptr; + else perror("In graphics.erase_arrow(), can't re_allocate for arrows vertex buffer.\n"); + + void *new_arrows_colors_ptr = g_realloc(stack->buffer_colors_origin, stack->buffer_colors_size * sizeof(GLfloat)); + if (new_arrows_colors_ptr) stack->buffer_colors_origin = new_arrows_colors_ptr; + else perror("In graphics.erase_arrow(), can't re_allocate for arrows colors buffer.\n"); + + /* Il ne faut pas réécrire ce qui suit: ces lignes dessinent maintenant à partir d'autres vertex */ + /* void *new_arrows_lines_ptr = g_realloc(stack->buffer_lines_origin, stack->buffer_lines_size * sizeof(GLfloat)); */ + /* if (new_arrows_lines_ptr) stack->buffer_lines_origin = new_arrows_lines_ptr; */ + /* else perror("In graphics.erase_arrow(), can't re_allocate for arrows lines buffer.\n"); */ + + return arrows_nb; +} + + + +/* + * Creates or deletes an arrow or modify the load of an existing one + * Acts both by writing the list of arrows : (struct arrow_t *arrows_ptr, int arrows_nb) + * and by drawing in the global space + * + * @param arrows_ptr and arrows_nb before operation, + * required load and address (site, x, y, z) + * + * IF there is no arrow at the required address, + * AND IF the load is > 0, an arrow will be created. + * + * IF there is an arrow at the required address + * AND IF the load is = 0, the existing arrow will be deleted. + * + * IF there is an arrow at the required address + * AND IF the load is > 0, the load of the existing arrow will be modified. + * + * May not call any of these three functions IF : + * - Current_weight of an arrow located at the requested address == requested_weight + * - No arrow was found at the requested addres AND current_weight == requested_weight + * + * @return arrows_nb after operation + */ +int set_arrow (int stack_id, + int arrows_nb, + int space_X, + int space_Y, + int space_Z, + int requested_weight, + int site, + int arrow_x, + int arrow_y, + int arrow_z) +{ + struct graphic_stack_t *stack = &graphic_stack[stack_id]; + int address = -1, current_weight = -1; + + for (int i = 0; i < arrows_nb; i++) + if ((site == stack->arrows_ptr[i].site) + && (arrow_x == stack->arrows_ptr[i].x) + && (arrow_y == stack->arrows_ptr[i].y) + && (arrow_z == stack->arrows_ptr[i].z)) + { + address = i; + current_weight = stack->arrows_ptr[i].load; + break; + } + assert (address <= arrows_nb); + + if (address == -1 && requested_weight > 0) + return create_arrow (stack_id, arrows_nb, space_X, space_Y, space_Z, requested_weight, site, arrow_x, arrow_y, arrow_z); + if (address >= 0 && requested_weight == 0) // address >= 0 if and only if arrows_nb > 0 + return erase_arrow(stack_id, arrows_nb, address, site, arrow_x, arrow_y, arrow_z); + if (address >= 0 && current_weight != requested_weight) { + rewrite_arrow(stack_id, address, requested_weight, site, arrow_x, arrow_y, arrow_z); + return arrows_nb; + } + + return arrows_nb; +} + diff --git a/gg/base.h b/gg/base.h new file mode 100644 index 0000000..85d6d77 --- /dev/null +++ b/gg/base.h @@ -0,0 +1,119 @@ +/* + * 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 + +// Graphical axis +enum +{ + X_AXIS, + Y_AXIS, + Z_AXIS, + + N_AXIS +}; + +// Gem-graph modes +enum +{ + HOME_MODE, + RUN_MODE, + EDIT_MODE, + PRESENTATION_MODE, + + N_MODE +}; + +/* + * Structure describing an arrow + */ +struct arrow_t { + uint load; + uint site; + uint x; + uint y; + uint z; +}; + +/* + * Read a file from filename into a provided buffer + * + * @param filename, file name + * contents, target ptr + * + * @return void + */ +static inline char *read_file(char *filename) +{ + int fd; + int filesize; + char *contents; + + fd = open(filename, O_RDONLY); + if(fd < 0) { + printf("Couldn't read file: %s\n",filename); + return NULL; + } + + filesize = lseek(fd, 0, SEEK_END) + 1 ; + contents = g_malloc(filesize * sizeof(char)); + assert (contents); + + lseek(fd, 0, SEEK_SET); + read(fd,contents,filesize); + + contents[filesize-1] = '\0'; + + close(fd); + + return contents; +} + +/* I'm standing on Earth (any planet or star or spinning spheroid, in fact) + * and looking towards its North pole + * + * X - X = EAST - WEST = rouge - cyan + * Y - Y = ZENITH - NADIR = vert - magenta + * Z - Z = NORTH - SOUTH = bleu - jaune + */ + +#define EAST 0 // + x rouge +#define WEST 1 // - x cyan +#define ZENITH 2 // + y vert +#define NADIR 3 // - y magenta +#define SOUTH 4 // + z bleu +#define NORTH 5 // - z jaune diff --git a/gg/displays.c b/gg/displays.c new file mode 100644 index 0000000..fee294c --- /dev/null +++ b/gg/displays.c @@ -0,0 +1,295 @@ +/* + * 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 . + */ + +#include +#include +#include "../../include/graphics.h" + +/* Prints the arrows[] array + * + * For each arrow the following parameters are displayed : + * - rank in the array + * - load (or weight) + * - coordinates in space (site, x, y, z) + */ +void print_arrows_array (struct arrow_t *arrows, int arrows_nb, int invoked_by) +{ + printf(" [rank] load | site x y z ("); + switch (invoked_by) { + case 0: printf("after deletion) arrows_nb : %d", arrows_nb); break; + case 1: printf("after creation) arrows_nb : %d", arrows_nb); break; + case 2: printf("after modification) arrows_nb : %d", arrows_nb); break; + case 3: printf("address >= 0 && current_weight == requested_weight)"); break; + case 4: printf("address == -1 && requested_weight == 0)"); break; + case 5: printf("print_user_choices)"); break; + case 6: printf("print_evolution)"); break; + case 7: printf("before deletion) arrows_nb : %d", arrows_nb); break; + } + for (int i = 0; i < arrows_nb; i++) + printf("\n [%4d] = %2d | %2d, %2d, %2d, %2d", i, arrows[i].load,\ + arrows[i].site, arrows[i].x, arrows[i].y, arrows[i].z); + if (arrows_nb == 0) printf("\n [NULL] ---- | ---- --- --- ---"); + printf("\n"); +} + + +/* Prints the initial user choices : + * - space dimension size and appearance (grids) + * - arrows[] array + * NB The space may be empty or saturated with arrows or any value in between + * Only one arrow per possible coordinates with a load max equal to ? TODO + */ +void print_user_choices(struct arrow_t *arrows, int max_arrows_nb, int arrows_nb, + int space_size_x, int space_size_y, int space_size_z, + int show_array, int show_space_design) +{ + printf("model + user constraints :\tspace size x,y,z (%d,%d,%d)\tinitial (max) arrows nb : %d",\ + space_size_x, space_size_y, space_size_z, max_arrows_nb); + + if (show_space_design) printf(" (grilles alternées)"); + printf("\n"); + + if (show_array) print_arrows_array (arrows, arrows_nb, 5); +} + +/* Prints the evolution after adding / removing arrows : + * - arrows[] array + * NB The space may be empty or saturated with arrows or any value in between + * Only one arrow per possible coordinates with a load max equal to ? TODO + * + * + * print_evolution (arrows, added, mem, deleted, print_arrows_data); + */ +void print_evolution (struct arrow_t *arrows, int arrows_nb, int modified, int deleted, int show_array) +{ + printf("evolution\t\t\t\t\t\t\tarrows nb > %6d\t (%d added / %d deleted) (modified : %d)\n",\ + arrows_nb + modified - deleted * 2, modified - deleted, deleted, modified); + if (show_array) print_arrows_array (arrows, arrows_nb, 6); +} + +/* + * Prints the arrows[] array + * + * For each arrow the following parameters are displayed : + * - rank in the array + * - weight (or load) + * - coordinates in space (site, x, y, z) + */ +void show_arrows_array_head(int one_batch_size, long nb_batches_specified, int verbose) { + printf("\n [rank] load | site x y z"); + if (verbose) printf(" one batch size = %d nb_batches_specified = %ld",\ + one_batch_size, nb_batches_specified); +} +void show_one_arrow_in_array(struct arrow_t *arrows, int i) { + printf("\n [%4d] = %2d | %2d, %2d, %2d, %2d",\ + i, arrows[i].load, arrows[i].site, arrows[i].x, arrows[i].y, arrows[i].z); +} +void show_empty_arrows_array() {printf("\n [NULL] ---- | ---- --- --- ---");} + +void show_arrows_array (struct arrow_t *arrows, int arrows_nb, int x, int y, int z) +{ + show_arrows_array_head (0,0,0); + for (int i = 0; i < arrows_nb; i++) + show_one_arrow_in_array(arrows, i); + if (arrows_nb == 0) show_empty_arrows_array(); +} + + + +/* + * Prints the initial user choices : + * - space dimension size and appearance (grids) + * - arrows[] array + * NB The space may be empty or saturated with arrows or any value in between + * To assert : Only one arrow per possible coordinates with a load max equal to ? + */ +void show_user_choices(long copy_nb_arrows_specified, + int space_size_x, int space_size_y, int space_size_z, + int prefer, int arbitrary, int one_batch_size) +{ + printf("\nnb arrows specified = %ld", copy_nb_arrows_specified); + printf(" space size (x,y,z) = (%d,%d,%d)", space_size_x, space_size_y, space_size_z); + printf(" arbitrary = %d one_batch_size = %d", arbitrary, one_batch_size); + if (prefer == 0) printf(" prefer = %d <> show all grids", prefer); + if (prefer == 1) printf(" prefer = %d <> show no grid", prefer); + if (prefer > 1) printf(" show grids according rule (%d)", prefer); +} + + +/* + * Prints the result of the function set_arrow() + * and indicates the reasons of the choice (call) this function makes (see this function) + */ +#define TEST 0 +void show_user_action(struct arrow_t *arrows, int arrows_nb, int address, int requested_weight, + int current_weight, int site, int x, int y, int z) +{ + if (address == -1 && requested_weight > 0) { // *(arrows + i * 5 + 0) + printf("no such arrow found (%2d,%2d,%2d,%2d)", site, x, y, z); //arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4]); + if (! TEST) printf("\n "); else printf(" "); + printf("=> CREATE"); return;} + + if (address >= 0 && requested_weight == 0) { + printf("arrow (%2d,%2d,%2d,%2d) found at address %2d; current_weight = %2d;", site, x, y, z, address, current_weight); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4], address/5, current_weight); + if (! TEST) printf("\n "); else printf(" "); + printf("=> ERASE"); return;} + + if (address >= 0 && current_weight != requested_weight) { + printf("arrow (%2d,%2d,%2d,%2d) found at address %2d; current_weight = %2d;", site, x, y, z, address, current_weight); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4], address/5, current_weight); + if (! TEST) printf("\n "); else printf(" "); + printf("=> MODIFY"); return;} + + if (address >= 0 && current_weight == requested_weight){ + printf("arrow (%2d,%2d,%2d,%2d) found at address %2d;", site, x, y, z, address); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4], address/5); + if (! TEST) printf("\n "); else printf(" "); + printf("requested_weight == current_weight => END"); return;} + + if (address == -1 && requested_weight == 0) { + printf("no such arrow found (%2d,%2d,%2d,%2d)", site, x, y, z); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4]); + if (! TEST) printf("\n "); else printf(" "); + printf("=> END"); return;} +} + + + +/* + * Prints vertex and lines buffers_states (sizes) at major one_batch_sizes and at the end of a session. + * Major one_batch_sizes are creation of grids and creation of arrows + * Arithmetic verification is provided at each one_batch_size + */ +void show_buffers_states(int space_X, int space_Y, int space_Z, + long nb_batches_specified, int one_batch_size, + int offset_after_grids, int buffer_vertex_size, + int buffer_lines_size_after_cubes, int buffer_lines_size) +{ + int offset_after_arrows = buffer_vertex_size / 3, difference = offset_after_arrows - offset_after_grids; + + printf("\n - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + + printf("\n buffer_vertex_offset_after grids = %9d\t%9d = (x+1)*(y+1)*(z+1); <--> (x,y,z = %d,%d,%d)",\ + offset_after_grids, (space_X + 1)*(space_Y + 1)*(space_Z + 1), space_X, space_Y, space_Z); + + printf("\n buffer_vertex_offset_after arrows = %9d\t%9d = %d + %d; <--> %d = 12 x %d (%d cubes)",\ + offset_after_arrows, offset_after_arrows, offset_after_grids,\ + difference, difference, difference / 12, difference / 12); + + printf("\n buffer_lines_offset after cubes = %9d\t%9d = 2 * (%dx%d + %dx%d + %dx%d); <--> 2 * (x*y + x*z + y*z)",\ + buffer_lines_size_after_cubes, ((space_X+1) * (space_Y+1) + (space_X+1) * (space_Z+1) + (space_Y+1) * (space_Z+1)) * 2, + space_X+1, space_Y+1, space_X+1, space_Z+1, space_Y+1, space_Z+1); + + printf("\n buffer_lines_offset after arrows = %9d\t%9d = %d + %d; <--> %d = 14 x %d (%d arrows drawned)",\ + buffer_lines_size, buffer_lines_size, buffer_lines_size_after_cubes,\ + buffer_lines_size - buffer_lines_size_after_cubes,\ + buffer_lines_size - buffer_lines_size_after_cubes, (buffer_lines_size - buffer_lines_size_after_cubes) / 14,\ + (buffer_lines_size - buffer_lines_size_after_cubes) / 14); + + if (nb_batches_specified * one_batch_size == 0) printf("\n"); + else printf("\n WARNING Arrows of the same address, whatever their weight, are drawn in superimposition. Check their list."); + + printf("\n It happens that NOT all the specified arrows (%ld) = (%ld x %d) are drawned (%d) ! WHY ? (d = %ld)\n",\ + nb_batches_specified * one_batch_size, nb_batches_specified, one_batch_size, (buffer_lines_size - buffer_lines_size_after_cubes) / 14,\ + nb_batches_specified * one_batch_size - (buffer_lines_size - buffer_lines_size_after_cubes) / 14); +} + + + +/* + * Prints the result of the function set_arrow() + * and indicates the reasons of the choice (call) this function makes (see this function) + */ +void print_user_action(struct arrow_t *arrows, int arrows_nb, int address, int requested_weight, + int current_weight, int site, int x, int y, int z) +{ + if (address == -1 && requested_weight > 0) { // *(arrows + i * 5 + 0) + printf("no such arrow found (%2d,%2d,%2d,%2d)", site, x, y, z); //arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4]); + if (! TEST) printf("\n "); else printf(" "); + printf("=> CREATE"); return;} + + if (address >= 0 && requested_weight == 0) { + printf("arrow (%2d,%2d,%2d,%2d) found at address %2d; current_weight = %2d;", site, x, y, z, address, current_weight); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4], address/5, current_weight); + if (! TEST) printf("\n "); else printf(" "); + printf("=> ERASE"); return;} + + if (address >= 0 && current_weight != requested_weight) { + printf("arrow (%2d,%2d,%2d,%2d) found at address %2d; current_weight = %2d;", site, x, y, z, address, current_weight); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4], address/5, current_weight); + if (! TEST) printf("\n "); else printf(" "); + printf("=> MODIFY"); return;} + + if (address >= 0 && current_weight == requested_weight){ + printf("arrow (%2d,%2d,%2d,%2d) found at address %2d;", site, x, y, z, address); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4], address/5); + if (! TEST) printf("\n "); else printf(" "); + printf("requested_weight == current_weight => END"); return;} + + if (address == -1 && requested_weight == 0) { + printf("no such arrow found (%2d,%2d,%2d,%2d)", site, x, y, z); // arrows[address + 1], arrows[address + 2], arrows[address + 3], arrows[address + 4]); + if (! TEST) printf("\n "); else printf(" "); + printf("=> END"); return;} +} + + + + + +static inline void print_buffers_array_head () {printf(" [rank] load | site x y z [address] buffer-vertex-1 buffer-vertex-2 buffer-lines\n");} +static inline void print_empty_buffers_array () {printf(" [NULL] ---- | ---- --- --- --- -1 --- --- ---\n");} + +static void print_one_arrow_in_buffers (struct arrow_t *arrows, + GLfloat *buffer_vertex_origin, long buffer_vertex_0_arrow, + GLfloat *buffer_lines_origin, long buffer_lines_0_arrow, + int i, int arrows_nb, int address) +{ + printf(" [%4d] = %2d | %2d, %2d, %2d, %2d, (%2d) %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %4f %4f\n",\ + i, + arrows[i].load, arrows[i].site, arrows[i].x, arrows[i].y, arrows[i].z, + address, + + buffer_vertex_origin [buffer_vertex_0_arrow + i * 6 + 0], + buffer_vertex_origin [buffer_vertex_0_arrow + i * 6 + 1], + buffer_vertex_origin [buffer_vertex_0_arrow + i * 6 + 2], + + buffer_vertex_origin [buffer_vertex_0_arrow + i * 6 + 3], + buffer_vertex_origin [buffer_vertex_0_arrow + i * 6 + 4], + buffer_vertex_origin [buffer_vertex_0_arrow + i * 6 + 5], + + buffer_lines_origin [buffer_lines_0_arrow + i * 2 + 0], + buffer_lines_origin [buffer_lines_0_arrow + i * 2 + 1]); +} + +void print_vertex_and_lines_buffers (struct arrow_t *arrows_ptr, int arrows_nb, + GLfloat *buffer_vertex_origin, long buffer_vertex_0_arrow, + GLfloat *buffer_lines_origin, long buffer_lines_0_arrow, + int address, int requested_weight, int current_weight, int site, int x, int y, int z) +{ + /* for (int i = 0; i < 6; i++) printf("%5.2f ", buffer_vertex_origin [buffer_vertex_0_arrow + i]); printf("\n"); */ + /* for (int i = 0; i < 6; i++) printf("%5.2f ", buffer_lines_origin [buffer_lines_0_arrow + i]); printf("\n"); */ + print_buffers_array_head (); + for (int i = 0; i < arrows_nb; i++) + print_one_arrow_in_buffers(arrows_ptr, buffer_vertex_origin, buffer_vertex_0_arrow, + buffer_lines_origin, buffer_lines_0_arrow, i, arrows_nb, address); + if (arrows_nb == 0) print_empty_buffers_array(); +} + + + + diff --git a/gg/draw.c b/gg/draw.c new file mode 100644 index 0000000..7b9732c --- /dev/null +++ b/gg/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 "../../include/base.h" +#include "../../include/ui.h" +#include "../../include/graphics.h" + +void graphics_draw_vertex (const int stack_id, + GLfloat x, + GLfloat y, + GLfloat z) +{ + //g_printerr("stack_id is %d\n", stack_id); + //g_printerr("stack_id is %d\n", stack_id); + //g_printerr("graphic_stack is at %p\n", graphic_stack); + //g_printerr("graphic_stack[stack_id] is at %p\n", graphic_stack + stack_id); + volatile struct graphic_stack_t *stack = &graphic_stack[stack_id]; + + //g_printerr("Currently stack->buffer_vertex_origin @ %p\n", stack->buffer_vertex_origin); + + //assert (stack->buffer_vertex_origin); + + stack->buffer_vertex_origin = + g_realloc (stack->buffer_vertex_origin, + (stack->buffer_vertex_size + 3) * sizeof(GLfloat)); + //print_stack(stack_id); + + stack->buffer_vertex_origin[stack->buffer_vertex_size + 0] = x; + stack->buffer_vertex_origin[stack->buffer_vertex_size + 1] = y; + stack->buffer_vertex_origin[stack->buffer_vertex_size + 2] = z; + + stack->buffer_vertex_size += 3; +} + +/* + * Writes values to describe a color (r,g,b) into the color buffer + * + * @param color GLfloat(r,g,b) + * + * @return void + */ +void graphics_draw_color (const int stack_id, + GLfloat r, + GLfloat g, + GLfloat b) +{ + struct graphic_stack_t *stack = &graphic_stack[stack_id]; + + stack->buffer_colors_origin = g_realloc (stack->buffer_colors_origin, + (stack->buffer_colors_size + 3) * sizeof(GLfloat)); + + assert (stack->buffer_colors_origin); + + stack->buffer_colors_origin[stack->buffer_colors_size + 0] = r; + stack->buffer_colors_origin[stack->buffer_colors_size + 1] = g; + stack->buffer_colors_origin[stack->buffer_colors_size + 2] = b; + + stack->buffer_colors_size += 3; +} + +/* + * Writes values to describe a line from a to b into the line buffer + * + * @param coords GLuint (a,b) + * + * @return void + */ +void graphics_draw_line (const int stack_id, + GLuint a, + GLuint b) +{ + struct graphic_stack_t *stack = &graphic_stack[stack_id]; + + stack->buffer_lines_origin = g_realloc (stack->buffer_lines_origin, + (stack->buffer_lines_size + 2) * sizeof(GLuint)); + + assert (stack->buffer_lines_origin); + + stack->buffer_lines_origin[stack->buffer_lines_size + 0] = a; + stack->buffer_lines_origin[stack->buffer_lines_size + 1] = b; + + stack->buffer_lines_size += 2; +} + +/* + * Writes values to describe an (a,b,c) plan (triangle) into the plan buffer + * + * @param coords GLuint (a,b,c) + * + * @return void + */ +void graphics_draw_plan (const int stack_id, + GLuint a, + GLuint b, + GLuint c) +{ + struct graphic_stack_t *stack = &graphic_stack[stack_id]; + + stack->buffer_plans_origin = g_realloc (stack->buffer_plans_origin, + (stack->buffer_plans_size + 3) * sizeof(GLuint)); + + assert (stack->buffer_plans_origin); + + stack->buffer_plans_origin[stack->buffer_plans_size + 0] = a; + stack->buffer_plans_origin[stack->buffer_plans_size + 1] = b; + stack->buffer_plans_origin[stack->buffer_plans_size + 2] = c; + + stack->buffer_plans_size += 3; +} + +/* + * Draws the current buffer to a gl_area + * + * @param gl_area, ptr to the gl_area widget + * + * @return void + */ +void graphics_draw(const int stack_id) +{ + struct graphic_stack_t *stack = &graphic_stack[stack_id]; + + //g_printerr("[debug] graphics_draw() started\n"); + + //print_stack(stack_id); + + GLint cur_viewport[4]; + glGetIntegerv(GL_VIEWPORT, cur_viewport); + + mat4 m = GLM_MAT4_IDENTITY_INIT; + glm_rotate_x(m, glm_rad(stack->rotation_angles[X_AXIS]), m); + glm_rotate_y(m, glm_rad(stack->rotation_angles[Y_AXIS]), m); + glm_rotate_z(m, glm_rad(stack->rotation_angles[Z_AXIS]), m); + + mat4 v = GLM_MAT4_IDENTITY_INIT; // XXX define zoom and translations here ? + + mat4 p = GLM_MAT4_IDENTITY_INIT; + //glm_ortho(-1.0f, +1.0f, -1.0f, +1.0f, -1.0f, +1.0f, p); + glm_ortho_default((float)cur_viewport[2] / (float)cur_viewport[3], p); + //glm_perspective_default((float)cur_viewport[2] / (float)cur_viewport[3], p); + + /* Use our shaders */ + glUseProgram(stack->program); + + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + /* Update the "mvp" matrix we use in the shader */ + glUniformMatrix4fv(stack->m, 1, GL_FALSE, (float *)m); + glUniformMatrix4fv(stack->v, 1, GL_FALSE, (float *)v); + glUniformMatrix4fv(stack->p, 1, GL_FALSE, (float *)p); + + /* Use the vertices in our buffer */ + glEnableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, stack->position_buffer); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0,(void*)0); + + // couleurs + glEnableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, stack->color_buffer); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0,(void*)0); + + //glEnable(GL_DEPTH_TEST); + + glDrawElements(GL_LINES, stack->buffer_lines_size, GL_UNSIGNED_INT, stack->buffer_lines_origin); + glDrawElements(GL_TRIANGLES, stack->buffer_plans_size, GL_UNSIGNED_INT, stack->buffer_plans_origin); + + /* We finished using the buffers and program */ + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glUseProgram(0); + + glFlush(); + //g_printerr("[debug] graphics_draw() ended\n"); +} diff --git a/gg/events.c b/gg/events.c new file mode 100644 index 0000000..90c69dc --- /dev/null +++ b/gg/events.c @@ -0,0 +1,369 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: User interface 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 "../../include/graphics.h" +#include "../../include/parsing.h" +#include "../../include/ui.h" + + + +void on_about_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + static const char *authors[] = { "Adrien Bourmault (neox@a-lec.org)", + "Jean Sirmai (jean@a-lec.org)", + "Arthur Menges (arthur.menges@a-lec.org)", + NULL}; + GemGraphClientApplication *self = user_data; + GtkWindow *window = NULL; + + g_assert (GEM_GRAPH_CLIENT_IS_APPLICATION(self)); + + window = gtk_application_get_active_window(GTK_APPLICATION (self)); + + gtk_show_about_dialog(window, + "program-name", "Gem-graph", + "logo-icon-name", "application-x-executable", + "authors", authors, + "version", "0.1.0", + "copyright", "Copyright © 2023 Libre en Communs", + NULL); +} + +void on_quit_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GemGraphClientApplication *self = user_data; + + g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self)); + + g_application_quit(G_APPLICATION(self)); +} + +void on_preferences_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GemGraphClientApplication *self = user_data; + + g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self)); + + ui_send_internal_notification("Not implemented !"); +} + +void on_togglesidebar_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GemGraphClientApplication *self = user_data; + + g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self)); + + ui_toggle_sidebar(); +} + +void on_editmode_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GemGraphClientApplication *self = user_data; + + g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self)); + + ui_set_stack(EDIT_MODE); +} + +void on_runmode_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GemGraphClientApplication *self = user_data; + + g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self)); + + ui_set_stack(RUN_MODE); +} + +void on_presentmode_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GemGraphClientApplication *self = user_data; + + g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self)); + + ui_set_stack(PRESENTATION_MODE); +} + +void on_openfile_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GemGraphClientApplication *self = user_data; + + g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self)); + + // Create a new file selection dialog, using the "open" mode + GtkFileChooserNative *native = + gtk_file_chooser_native_new("Open File", + GTK_WINDOW(self), + GTK_FILE_CHOOSER_ACTION_OPEN, + "_Open", + "_Cancel"); + + // Connect the "response" signal of the file selection dialog; + // this signal is emitted when the user selects a file, or when + // they cancel the operation + g_signal_connect (native, + "response", + G_CALLBACK(on_openfile_response), + self); + + // Present the dialog to the user + gtk_native_dialog_show (GTK_NATIVE_DIALOG (native)); +} + +void on_closefile_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GemGraphClientApplication *self = user_data; + + g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self)); + + model_shutdown(); + + ui_disable_action("closefile"); + ui_disable_action("savefile"); + ui_disable_action("runmode"); + ui_disable_action("editmode"); + ui_disable_action("presentmode"); + ui_disable_action("togglesidebar"); + ui_set_stack(HOME_MODE); +} + +void on_savefile_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GemGraphClientApplication *self = user_data; + + g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self)); + +} + +void on_toast_close_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GemGraphClientApplication *self = user_data; + + g_assert(GEM_GRAPH_CLIENT_IS_APPLICATION(self)); + + ui_close_internal_notification(); +} + +/* -------------------------------------------------------------------------- */ + +/* + * Graphical/view related events + */ + +void on_axis_value_change(GtkAdjustment *adjustment, gpointer data) +{ + + GtkWidget *slider = gtk_widget_get_parent(GTK_WIDGET(data)); + GtkWidget *container_widget = gtk_widget_get_parent(GTK_WIDGET(slider)); + + const gchar *label_text = gtk_label_get_label(GTK_LABEL(data)); + + // THANKS ASCIIIII/Unicode/Whateverrr ! + int axis = label_text[0] - 'X'; + + g_assert(axis >= 0 && axis < N_AXIS); + + /* Update the rotation angle */ + ui_update_axis_stack(container_widget, + axis, + gtk_adjustment_get_value(adjustment)); + + /* Update the contents of the GL drawing area */ +} + +gboolean on_glarea_render(GtkGLArea *area, GdkGLContext *context) +{ + // Check if the widget is a glarea + if(gtk_gl_area_get_error(area) != NULL) { + ui_send_internal_notification("An OpenGL error occured !"); + return false; + } + + if (ui_render_stack(gtk_widget_get_parent(GTK_WIDGET(area))) == false) { + ui_send_internal_notification( + "Failed to render corresponding graphic stack !"); + return false; + } + + return true; +} + + +/* We need to set up our state when we realize the GtkGLArea widget */ +void on_glarea_realize(GtkWidget *widget) +{ + GError *internal_error = NULL; + + // Make the GL context current to be able to call the GL API + gtk_gl_area_make_current(GTK_GL_AREA(widget)); + + // Check if the widget is a glarea + if(gtk_gl_area_get_error(GTK_GL_AREA(widget)) != NULL) { + ui_send_internal_notification("An OpenGL error occured !"); + return; + } + + // Link graphical stack to widget + if (ui_init_graphic_stack(gtk_widget_get_parent(widget), + internal_error) == false) { + ui_send_internal_notification( + "Failed to link the graphic stack to widgets !"); + return; + } + + gtk_gl_area_set_auto_render(GTK_GL_AREA(widget), true); +} + +/* We should tear down the state when unrealizing */ +void on_glarea_unrealize(GtkWidget *widget) +{ + GError *internal_error = NULL; + + // Make the GL context current to be able to call the GL API + gtk_gl_area_make_current(GTK_GL_AREA(widget)); + + // Check if the widget is a glarea + if(gtk_gl_area_get_error(GTK_GL_AREA(widget)) != NULL) { + ui_send_internal_notification("An OpenGL error occured !"); + return; + } + + // Destroy graphic stack + if (ui_shutdown_graphic_stack(gtk_widget_get_parent(widget), + internal_error) == false) { + ui_send_internal_notification( + "Failed to shutdown the graphic stack !"); + return; + } +} + +void on_close_window(GtkWidget *widget) +{ + + ui_shutdown_all_graphic_stacks(); + ui_clean_stack_index(); +} + +/* -------------------------------------------------------------------------- */ + +/* + * Responses + */ +void on_openfile_response(GtkNativeDialog *native, + int response, + GemGraphClientWindow *self) +{ + g_autoptr(GFile) file; + GtkFileChooser *chooser; + + if (response == GTK_RESPONSE_ACCEPT) { + chooser = GTK_FILE_CHOOSER(native); + file = gtk_file_chooser_get_file(chooser); + + // Load asynchroneously not to block control flow + g_file_load_contents_async (file, + NULL, + (GAsyncReadyCallback)ui_model_loading, + self); + } + + g_object_unref(native); +} + +void ui_model_loading(GObject *source_object, + GAsyncResult *result, + GemGraphClientWindow *self) +{ + GFile *file = G_FILE(source_object); + + char *content = NULL; + size_t length = 0; + + GError *error = NULL; + char *basename = g_file_get_basename(file); + + // Gives you the contents of the file as a byte array, or + // set the error argument + g_file_load_contents_finish(file, + result, + &content, + &length, + NULL, + &error); + + // In case of error, print a warning to the standard error output + if (error != NULL) { + g_printerr("Unable to open “%s”: %s\n", + g_file_peek_path(file), + error->message); + ui_send_internal_notification("Unable to open file !"); + g_free(error); + g_free(basename); + g_free(content); + return; + } + + if (model_init(content, length, basename) == false) { + ui_send_internal_notification("Error while loading the model"); + g_free(basename); + g_free(content); + return; + } + + ui_enable_action("closefile"); + ui_enable_action("savefile"); + ui_enable_action("runmode"); + ui_enable_action("editmode"); + ui_enable_action("presentmode"); + ui_enable_action("togglesidebar"); + ui_set_stack(RUN_MODE); + + g_free(basename); + g_free(content); +} + diff --git a/gg/graphics.c b/gg/graphics.c new file mode 100644 index 0000000..49e3d5a --- /dev/null +++ b/gg/graphics.c @@ -0,0 +1,328 @@ +/* + * 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 "../../include/base.h" +#include "../../include/ui.h" +#include "../../include/parsing.h" +#include "../../include/graphics.h" + +#define TEST 0 + +struct graphic_stack_t *graphic_stack = NULL; +size_t graphic_stack_size = 0; +int *free_stack_slot = NULL; +size_t free_stack_slot_size = 0; + +/* + * Prints verbose human-readable debug messages + * + * @param source, XXX + * type, XXX + * id, XXX + * severity, XXX + * length, XXX + * msg, XXX + * data, XXX + * + * @return void + */ +static void graphics_debug_callback(GLenum source, GLenum type, GLuint id, + GLenum severity, GLsizei length, + const GLchar *msg, const void *data) +{ + const char *errsource; + const char *errtype; + const char *errseverity; + const GLubyte *string; + GLenum code; + + switch (source) { + case GL_DEBUG_SOURCE_API: errsource = "API"; break; + case GL_DEBUG_SOURCE_WINDOW_SYSTEM: errsource = "WINDOW SYSTEM"; break; + case GL_DEBUG_SOURCE_SHADER_COMPILER: errsource = "SHADER COMPILER"; break; + case GL_DEBUG_SOURCE_THIRD_PARTY: errsource = "THIRD PARTY"; break; + case GL_DEBUG_SOURCE_APPLICATION: errsource = "APPLICATION"; break; + case GL_DEBUG_SOURCE_OTHER: errsource = "UNKNOWN"; break; + default: errsource = "UNKNOWN"; break; + } + + switch (type) { + case GL_DEBUG_TYPE_ERROR: errtype = "ERROR"; break; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: errtype = "DEPRECATED BEHAVIOR";break; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: errtype = "UNDEFINED BEHAVIOR"; break; + case GL_DEBUG_TYPE_PORTABILITY: errtype = "PORTABILITY"; break; + case GL_DEBUG_TYPE_PERFORMANCE: errtype = "PERFORMANCE"; break; + case GL_DEBUG_TYPE_OTHER: errtype = "OTHER"; break; + case GL_DEBUG_TYPE_MARKER: errtype = "MARKER"; break; + default: errtype = "UNKNOWN"; break; + } + + switch (severity) { + case GL_DEBUG_SEVERITY_HIGH: errseverity = "CRITICAL"; break; + case GL_DEBUG_SEVERITY_MEDIUM: errseverity = "ERROR"; break; + case GL_DEBUG_SEVERITY_LOW: errseverity = "WARNING"; break; + case GL_DEBUG_SEVERITY_NOTIFICATION: errseverity = "INFO"; break; + default: errseverity = "UNKNOWN"; break; + } + + code = glGetError(); + string = gluErrorString(code); + + g_printerr("[%s] %s (%s) from %s: %s\n", + errseverity, string, errtype, errsource, msg); +} + +/* -------------------------------------------------------------------------- */ + +/* + * Initializes graphical stack + * + * @param gl_area, ptr to the gl_area widget + * + * @return id if initialized + */ +int graphics_init(void *error_buffer) +{ + int cur_id = 0; + struct graphic_stack_t *stack; + + /* g_printerr("[debug] graphics_init()\n"); */ + + if (graphic_stack == NULL) { + graphic_stack = g_malloc0(sizeof(struct graphic_stack_t)); + graphic_stack_size = 1; + /* g_printerr("[debug] graphics_init(): init graphic_stack @ %p\n", graphic_stack); */ + } else { + // Check if there are free slots + if (free_stack_slot_size) { + // We get the last free slot registered + cur_id = free_stack_slot[free_stack_slot_size-1]; + // Unregister it (ofc) + free_stack_slot = g_realloc(free_stack_slot, + free_stack_slot_size-- * + sizeof(int)); + } else { + cur_id = graphic_stack_size; + graphic_stack = g_realloc(graphic_stack, + ++graphic_stack_size * + sizeof(struct graphic_stack_t)); + } + } + + memset(&graphic_stack[cur_id], 0, sizeof(struct graphic_stack_t)); + + /* g_printerr("[debug] graphics_init() : graphic_stack (@0x%p) has %ld elements\n", */ + /* graphic_stack, */ + /* graphic_stack_size); */ + + stack = &graphic_stack[cur_id]; + stack->id = cur_id; + + glEnable(GL_DEBUG_OUTPUT); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + glEnable(GL_MULTISAMPLE); + + if (!graphics_init_shaders(cur_id)) + return -1; + + //print_stack(cur_id); + + graphics_init_buffers(cur_id); + + glDebugMessageCallback(graphics_debug_callback, NULL); + + //print_stack(cur_id); + + return cur_id; +} + +/* + * Shutdowns a gl_area + * + * @param gl_area, ptr to the gl_area widget + * + * @return true if success + */ +bool graphics_shutdown(const int id, void *error_buffer) +{ + struct graphic_stack_t *stack; + + if (id >= graphic_stack_size || + graphic_stack_size == 0 || + graphic_stack == NULL) + return false; + + stack = &graphic_stack[id]; + + //XXX + free(stack->arrows_ptr); + stack->arrows_ptr = NULL; + stack->arrows_nb = 0; + + glDeleteBuffers(1, &stack->position_buffer); + glDeleteBuffers(1, &stack->color_buffer); + glDeleteProgram(stack->program); + + g_free(stack->buffer_vertex_origin); + g_free(stack->buffer_colors_origin); + g_free(stack->buffer_lines_origin); + g_free(stack->buffer_plans_origin); + + if (graphic_stack_size == 1) { + free(graphic_stack); + graphic_stack = NULL; + graphic_stack_size = 0; + } else { + memset(&graphic_stack[id], 0, sizeof(struct graphic_stack_t)); + free_stack_slot = g_realloc(free_stack_slot, + ++free_stack_slot_size * + sizeof(int)); + free_stack_slot[free_stack_slot_size-1] = id; + } + + return true; +} + +/* TODO + * #pragma omp parallel schedule(static, 12) + * void __attribute__((optimize("no-unroll-loops"))) main_test_graphics (void) {} + * +// assert : space dimensions (x,y,z) > 0 +// assert : arrows localization within space and sites +// assert : no more than one arrow per address +// notify : weights are replaced, NOT added (could be !) + * + * Init space and arrows (= initial state) + * and allows ulterior creations, suppressions or modifications of the arrows[] array + * + * draws the space() + * triggers set_arrows() that modifies the list () and draws arrows + * + * Initialisation du générateur pseudo-aléatoire + * Attention, les vertex centraux de chaque unité d'espace (cube) + * peuvent être redondants (max 6) +*/ +void graphics_model_setup (const int stack_id) +{ + /*------------------------------------------------------------------------*/ + + /* I N I T I A L D A T A S P E C I F I C A T I O N */ + + /*------------------------------------------------------------------------*/ + + struct graphic_stack_t *stack = &graphic_stack[stack_id]; + char dimension; + long space_X; + long space_Y; + long space_Z; + long announced_arrows_nb; + int density_max; + char multiplicity; + + dimension = model_get_dim(); + + g_print("[GRAPH DEBUG] dim = %d\n", dimension); + + space_X = 1; + space_Y = 1; + space_Z = 1; + + switch(dimension) { + case 3: + space_Z = model_get_dim_value("z"); + case 2: + space_Y = model_get_dim_value("y"); + + // even in 1D, we must be able to see a grid + if (!space_Y) + space_Y = 1; + case 1: + space_X = model_get_dim_value("x"); + if (!space_X) + space_X = 1; + default: + break; + } + + g_print("[GRAPH DEBUG] x = %ld\n", space_X); + g_print("[GRAPH DEBUG] y = %ld\n", space_Y); + g_print("[GRAPH DEBUG] z = %ld\n", space_Z); + + density_max = space_X * space_Y * space_Z; + stack->arrows_nb = 0; + + multiplicity = model_get_multiplicity(); + g_print("[GRAPH DEBUG] site_multiplicity = %ld\n", multiplicity); + + /*------------------------------------------------------------------------*/ + + /* S P A C E D R A W I N G */ + + /*------------------------------------------------------------------------*/ + + draw_space_ridges_vertex (stack_id, stack->buffer_vertex_size, + space_X, space_Y, space_Z); + draw_space_ridges_lines (stack_id); + draw_grids_on_space_faces_vertex (stack_id, space_X, space_Y, space_Z); + draw_grids_on_space_faces_lines (stack_id, stack->buffer_lines_size, + space_X, space_Y, space_Z); + + stack->buffer_vertex_0_arrow = stack->buffer_vertex_size; + stack->buffer_colors_0_arrow = stack->buffer_colors_size; + stack->buffer_lines_0_arrow = stack->buffer_lines_size; + + /*------------------------------------------------------------------------*/ + + /* A R R O W S D R A W I N G */ + + /*------------------------------------------------------------------------*/ + + char state_id[30] = {0}; + struct arrow_t arrow = {0}; + + assert(model_get_next_state(&state_id)); + + g_print("[GRAPH DEBUG] first state is = %s\n", state_id); + + announced_arrows_nb = model_get_state_arrows_count(state_id); + + g_print("[GRAPH DEBUG] announced_arrows_nb is = %ld\n", announced_arrows_nb); + + while (model_get_next_arrow(&arrow, &state_id, dimension)) { + g_print("[GRAPH DEBUG] cur arrow has x = %d\n", arrow.x); + stack->arrows_nb = + set_arrow (stack_id, stack->arrows_nb, space_X, space_Y, space_Z, + arrow.load, // load + arrow.site, // site + arrow.x, // x + arrow.y, // y + arrow.z); // z + } + + if (stack->arrows_nb != announced_arrows_nb) + g_printerr("ARGH : all the arrows have not been parsed !\n"); +} diff --git a/gg/graphics.h b/gg/graphics.h new file mode 100644 index 0000000..f30f7b1 --- /dev/null +++ b/gg/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 = %p\n", graphic_stack[stack_id].buffer_vertex_0_arrow); + printf("buffer_colors_0_arrow = %p\n", graphic_stack[stack_id].buffer_colors_0_arrow); + printf("buffer_lines_0_arrow = %p\n", graphic_stack[stack_id].buffer_lines_0_arrow); + printf("buffer_plans_0_arrow = %p\n", graphic_stack[stack_id].buffer_plans_0_arrow); + + printf("********************\n"); + n++; +} + + +void graphics_model_setup (const int stack_id); + +int draw_one_arrow_vertex (const int stack_id, + int space_X, + int space_Y, + int space_Z, + int weight, + int site, + int x, + int y, + int z); + +int draw_one_arrow_line(const int stack_id, + int offset_vertex); + +/* + * Writes grid ridges to vertex and color buffers + * + * @param coords long (x,y,z), step_x, step_y, step_z + * + * @return void + */ +int draw_space_ridges_vertex (const int stack_id, + long offset_vertex, + long x, + long y, + long z); + +int draw_space_ridges_lines (const int stack_id); + +/* + * Writes grid lines on space faces + * + * @param coords long (x,y,z) + * + * @return void + */ +long draw_grids_on_space_faces_vertex (const int stack_id, + long x, + long y, + long z); + +long draw_grids_on_space_faces_lines (const int stack_id, + long offset_vertex, + long x, + long y, + long z); + +int set_arrow (int stack_id, + int arrows_nb, + int space_X, + int space_Y, + int space_Z, + int requested_weight, + int site, + int arrow_x, + int arrow_y, + int arrow_z); + diff --git a/gg/grid.c b/gg/grid.c new file mode 100644 index 0000000..e0fad55 --- /dev/null +++ b/gg/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 "../../include/base.h" +#include "../../include/ui.h" +#include "../../include/graphics.h" + +int draw_space_ridges_vertex (const int stack_id, + long offset_vertex, + long x, + long y, + long z) +{ + GLfloat max = fmax(x, y); max = fmax(max, z); + + graphics_draw_vertex (stack_id, offset_vertex - x / max, offset_vertex - y / max, - z / max); + + graphics_draw_vertex (stack_id, offset_vertex + x / max, offset_vertex - y / max, - z / max); + graphics_draw_vertex (stack_id, offset_vertex - x / max, offset_vertex + y / max, - z / max); + graphics_draw_vertex (stack_id, offset_vertex - x / max, offset_vertex - y / max, + z / max); + + graphics_draw_vertex (stack_id, offset_vertex + x / max, offset_vertex + y / max, - z / max); + graphics_draw_vertex (stack_id, offset_vertex + x / max, offset_vertex - y / max, + z / max); + graphics_draw_vertex (stack_id, offset_vertex - x / max, offset_vertex + y / max, + z / max); + + graphics_draw_vertex (stack_id, offset_vertex + x / max, + y / max, + z / max); + + graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f); + graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f); + graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f); + graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f); + graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f); + graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f); + graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f); + graphics_draw_color (stack_id, 0.8f, 0.6f, 0.5f); + + return 8; +} + +int draw_space_ridges_lines (const int stack_id) +{ + graphics_draw_line (stack_id, 0, 1); graphics_draw_line (stack_id, 7, 4); + graphics_draw_line (stack_id, 0, 2); graphics_draw_line (stack_id, 7, 5); + graphics_draw_line (stack_id, 0, 3); graphics_draw_line (stack_id, 7, 6); + + graphics_draw_line (stack_id, 1, 4); graphics_draw_line (stack_id, 2, 4); + graphics_draw_line (stack_id, 1, 5); graphics_draw_line (stack_id, 3, 5); + graphics_draw_line (stack_id, 2, 6); graphics_draw_line (stack_id, 3, 6); + + return 12; +} + +long draw_grids_on_space_faces_vertex (const int stack_id, + long x, + long y, + long z) +{ + float i, max = fmax(x, y); max = fmax(max, z); + + for (i = 1; i < x; i++) { + + graphics_draw_vertex (stack_id, (2 * i / x - 1) * x / max, - y / max, - z / max); + graphics_draw_vertex (stack_id, (2 * i / x - 1) * x / max, - y / max, z / max); + graphics_draw_vertex (stack_id, (2 * i / x - 1) * x / max, y / max, z / max); + graphics_draw_vertex (stack_id, (2 * i / x - 1) * x / max, y / max, - z / max); + + graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f); + graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f); + graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f); + graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f); + } + + /* offset_vertex += (x - 1) * 4; */ /* offset_colors += (x - 1) * 4; */ + + for (i = 1; i < y; i++) { + + graphics_draw_vertex (stack_id, - x / max, (2 * i / y - 1) * y / max, - z / max); + graphics_draw_vertex (stack_id, - x / max, (2 * i / y - 1) * y / max, z / max); + graphics_draw_vertex (stack_id, x / max, (2 * i / y - 1) * y / max, z / max); + graphics_draw_vertex (stack_id, x / max, (2 * i / y - 1) * y / max, - z / max); + + graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f); + graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f); + graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f); + graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f); + } + + /* offset_vertex += (y - 1) * 4; */ /* offset_colors += (y - 1) * 4; */ + + for (i = 1; i < z; i++) { + + graphics_draw_vertex (stack_id, - x / max, - y / max, (2 * i / z - 1) * z / max); + graphics_draw_vertex (stack_id, - x / max, y / max, (2 * i / z - 1) * z / max); + graphics_draw_vertex (stack_id, x / max, y / max, (2 * i / z - 1) * z / max); + graphics_draw_vertex (stack_id, x / max, - y / max, (2 * i / z - 1) * z / max); + + graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f); + graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f); + graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f); + graphics_draw_color (stack_id, 0.55f, 0.55f, 0.55f); + } + + return (x + y + z - 3) * 3; +} + + +long draw_grids_on_space_faces_lines (const int stack_id, + long offset_vertex, + long x, + long y, + long z) +{ + offset_vertex = offset_vertex / 3; + + for (int i = 0; i < x - 1; i ++) { + + graphics_draw_line (stack_id, offset_vertex + i * 4 + 1, offset_vertex + i * 4 + 2); + graphics_draw_line (stack_id, offset_vertex + i * 4 + 2, offset_vertex + i * 4 + 3); + } + + offset_vertex += (x - 1) * 4; + + for (int i = 0; i < y - 1; i ++) { + + graphics_draw_line (stack_id, offset_vertex + i * 4 + 2, offset_vertex + i * 4 + 3); + graphics_draw_line (stack_id, offset_vertex + i * 4 + 3, offset_vertex + i * 4 + 0); + } + + offset_vertex += (y - 1) * 4; + + for (int i = 0; i < z - 1; i ++) { + + graphics_draw_line (stack_id, offset_vertex + i * 4 + 0, offset_vertex + i * 4 + 1); + graphics_draw_line (stack_id, offset_vertex + i * 4 + 3, offset_vertex + i * 4 + 0); + } + + return (x + y + z - 3) * 4; +} + diff --git a/gg/init.c b/gg/init.c new file mode 100644 index 0000000..8928f98 --- /dev/null +++ b/gg/init.c @@ -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 "../../include/base.h" +#include "../../include/ui.h" +#include "../../include/graphics.h" + +/* Initializes the buffer of a gl_area + * Calls according to the user preferences + * @param gl_area, ptr to the gl_area widget + * @return void + */ +void graphics_init_buffers(const int stack_id) +{ + struct graphic_stack_t *stack = &graphic_stack[stack_id]; + + //XXX + graphics_model_setup(stack_id); + + GLuint vao, vertex_buffer, color_buffer; + + glGenBuffers(1, &vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, + stack->buffer_vertex_size * + sizeof(stack->buffer_vertex_origin[0]), + stack->buffer_vertex_origin, + GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + + // colors + glGenBuffers(1, &color_buffer); + glBindBuffer(GL_ARRAY_BUFFER, color_buffer); + glBufferData(GL_ARRAY_BUFFER, stack->buffer_colors_size * + sizeof(stack->buffer_colors_origin[0]), + stack->buffer_colors_origin, + GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // We only use one VAO, so we always keep it bound + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + stack->vao = vao; + stack->position_buffer = vertex_buffer; + stack->color_buffer = color_buffer; +} + +/* + * Initializes the shaders of a gl_area and link them to a program + * + * @param gl_area, ptr to the gl_area widget + * + * @return true if initialized + */ +bool graphics_init_shaders(const int stack_id) +{ + struct graphic_stack_t *stack = &graphic_stack[stack_id]; + char *vertex_shader; + char *fragment_shader; + int status; + GLuint vertex, fragment; + GLuint program = 0; + GLuint m = 0; + GLuint v = 0; + GLuint p = 0; + + // Load vertex shader file + vertex_shader = read_file(VERTEX_SHADER_FILE); + if (vertex_shader == NULL) + return false; + vertex = create_shader(stack_id, GL_VERTEX_SHADER, vertex_shader); + + if(vertex == 0) { + stack->program = 0; + g_free(vertex_shader); + return false; + } + + // Load fragment shader file + fragment_shader = read_file(FRAG_SHADER_FILE); + if (fragment_shader == NULL) + return false; + fragment = create_shader(stack_id, GL_FRAGMENT_SHADER, fragment_shader); + + if(fragment == 0) { + glDeleteShader(vertex); + stack->program = 0; + g_free(vertex_shader); + g_free(fragment_shader); + return false; + } + + // Link shaders to program + program = glCreateProgram(); + glAttachShader(program, vertex); + glAttachShader(program, fragment); + + glLinkProgram(program); + + glGetProgramiv(program, GL_LINK_STATUS, &status); + + if(status == GL_FALSE) { + int log_len; + char *buffer; + + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_len); + + buffer = g_malloc(log_len + 1); + assert(buffer); + glGetProgramInfoLog(program, log_len, NULL, buffer); + + g_warning("Linking failure:\n%s", buffer); + + g_free(buffer); + + glDeleteProgram(program); + program = 0; + + glDeleteShader(vertex); + glDeleteShader(fragment); + + g_free(vertex_shader); + g_free(fragment_shader); + + return false; + } + + /* Get the location of the "mvp" uniform */ + m = glGetUniformLocation(program, "model_matrix"); + v = glGetUniformLocation(program, "view_matrix"); + p = glGetUniformLocation(program, "projection_matrix"); + + glDetachShader(program, vertex); + glDetachShader(program, fragment); + + glDeleteShader(vertex); + glDeleteShader(fragment); + + stack->program = program; + stack->m = m; + stack->v = v; + stack->p = p; + + g_free(vertex_shader); + g_free(fragment_shader); + + return true; +} diff --git a/gg/parsing.c b/gg/parsing.c new file mode 100644 index 0000000..916fe85 --- /dev/null +++ b/gg/parsing.c @@ -0,0 +1,483 @@ +/* + * 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 "../../include/base.h" + +#define READ_SITE 1 << 0 +#define READ_WEIGHT 1 << 1 +#define READ_X 1 << 2 +#define READ_Y 1 << 3 +#define READ_Z 1 << 4 +#define SUCCESSFUL_READ_ARROW_X (READ_SITE | READ_WEIGHT | READ_X) +#define SUCCESSFUL_READ_ARROW_XY (READ_SITE | READ_WEIGHT | READ_X | READ_Y) +#define SUCCESSFUL_READ_ARROW_XYZ (READ_SITE | READ_WEIGHT | READ_X | READ_Y | READ_Z) + +static xmlDocPtr model; +static xmlHashTablePtr model_hashtable; + +bool model_init(const char *content, size_t length, const char *basename) +{ + xmlNode *node; + + /* + * this initialize the library and check potential ABI mismatches + * between the version it was compiled for and the actual shared + * library used. + */ + LIBXML_TEST_VERSION + + model = xmlReadMemory(content, length, basename, NULL, 0); + + if (model == NULL ) { + return false; + } + + node = xmlDocGetRootElement(model); + + if (node == NULL) { + g_printerr("Empty XML model !\n"); + xmlFreeDoc(model); + return false; + } + + if (xmlStrcmp(node->name, (xmlChar *) "gem-graph-model")) { + g_printerr("document of the wrong type, root node != gem-graph-model\n"); + xmlFreeDoc(model); + return false; + } + + model_hashtable = xmlHashCreate(0); + + if (model_hashtable == NULL) { + g_printerr("Can't create model hash table !\n"); + xmlFreeDoc(model); + return false; + } + + return true; +} + +bool model_shutdown(void) +{ + xmlFreeDoc(model); + xmlHashFree(model_hashtable, NULL); + + // Cleanup function for the XML library + xmlCleanupParser(); + + // This is to debug memory for regression tests + xmlMemoryDump(); + + return true; +} + +/******************************************************************************/ + +static inline xmlNodePtr getNextChild(xmlNodePtr node, xmlChar *last) +{ + while (node != NULL && xmlStrcmp(node->name, last)) { + // //printf(" <>--- line n°%lu <%s>\n", xmlGetLineNo(node), node->name); + node = node->next; + } + return node; +} + +static inline xmlChar* splitStrAtSlash(xmlChar *toSplit) +{ + toSplit = (xmlChar *)xmlStrchr(toSplit, '/'); + toSplit = xmlStrsub (toSplit, 1, xmlStrlen(toSplit)); + return toSplit; +} + +static inline xmlChar* getFirstTag(xmlChar *path) +{ + xmlChar *preop = path; + path = (xmlChar *)xmlStrchr(path, '/'); + path = xmlStrsub (path, 1, xmlStrlen(path)); + + //printf("%s = %s + / + %s\n", preop,\ + xmlStrsub (preop, 0, xmlStrlen(preop) - xmlStrlen(path) - 1), path); + + return xmlStrsub (preop, 0, xmlStrlen(preop) - xmlStrlen(path) - 1); +} + +static inline xmlChar* getLastTag(xmlChar *path) +{ + while ((ulong)xmlStrchr (path, '/')) + path = splitStrAtSlash((xmlChar *)path); + + // //printf("last tag in the path = <%s>\n", path); + return path; // which is no more the given path but only its last tag ! +} + +/******************************************************************************/ + +static xmlNodePtr model_get_node(xmlChar *path) +{ + xmlNodePtr node; + xmlChar *extrait; + xmlChar *reste, *last, *affich; + + // Lookup for node from path in hash table + node = xmlHashLookup(model_hashtable, path); + + // Found a node in hash table + if (node) { + return node; + + // no node found in hash table + } else { + reste = path; + affich = reste; + last = getLastTag(reste); + node = xmlDocGetRootElement(model); + + while (xmlStrchr (reste, '/')) { + extrait = getFirstTag(reste); + reste = splitStrAtSlash((xmlChar *)reste); + node = node->xmlChildrenNode; + node = getNextChild(node, extrait); + } + + if(node && xmlStrcmp(node->name, last)) { + node = node->xmlChildrenNode; + + while (node && xmlStrcmp(node->name, last)) { + node = node->next; + } + xmlHashAddEntry (model_hashtable, path, node); + } + + return node; + + } + + return NULL; +} + +/******************************************************************************/ + +static inline long model_get_node_long_attrib(xmlNodePtr node, char *id) +{ + xmlAttr *attribute; + xmlChar* value; + long ret_value; + + if (node && node->properties) { + attribute = node->properties; + while(attribute && attribute->name && attribute->children) { + if (!xmlStrcmp(attribute->name, (const xmlChar *)id)) { + value = xmlNodeListGetString(node->doc, attribute->children, 1); + ret_value = strtol((char *)value, NULL, 0); + xmlFree(value); + return ret_value; + } + attribute = attribute->next; + } + } + return 0; +} + +static inline bool model_get_node_str_attrib(xmlNodePtr node, + char *id, + char *dest) +{ + xmlAttr *attribute; + xmlChar* value; + + if (node && node->properties) { + attribute = node->properties; + while(attribute && attribute->name && attribute->children) { + if (!xmlStrcmp(attribute->name, (const xmlChar *)id)) { + value = xmlNodeListGetString(node->doc, attribute->children, 1); + strcpy(dest, value); + xmlFree(value); + return true; + } + attribute = attribute->next; + } + } + return false; +} + +/******************************************************************************/ + +char model_get_dim(void) +{ + xmlAttr *attribute; + xmlChar* value; + xmlNodePtr node = model_get_node( + (xmlChar *)"parameters/space-param/dimension"); + + if (xmlHasProp (node, (xmlChar *) "z")) return 3; + if (xmlHasProp (node, (xmlChar *) "y")) return 2; + if (xmlHasProp (node, (xmlChar *) "x")) return 1; + return 0; +} + +long model_get_dim_value(const char *axis) +{ + xmlAttr *attribute; + xmlChar *value; + long ret_value; + xmlNodePtr node = model_get_node( + (xmlChar *)"parameters/space-param/dimension"); + + return model_get_node_long_attrib(node, axis); +} + +char model_get_multiplicity(void) +{ + xmlAttr *attribute; + xmlChar* value; + xmlNodePtr node = model_get_node( + (xmlChar *)"parameters/space-param/site_multiplicity"); + + if (node->children) + if (node->children->content) + return (char)strtol((char *)node->children->content, NULL, 0); + + return 0; +} + +bool model_get_next_state(char *new_state_id) +{ + static xmlNodePtr cur_node = NULL; + xmlAttr *attribute; + xmlChar *value; + + if (cur_node == NULL) { + // Get first state + cur_node = model_get_node((xmlChar *)"savedstates/state"); + + } else { + // Get next state + if (cur_node->next) + cur_node = cur_node->next; + else + return false; + } + + // Lookup in properties + if (model_get_node_str_attrib(cur_node, "id", new_state_id)) + return true; + + cur_node = NULL; + return false; +} + +long model_get_state_arrows_count(const char *state_id) +{ + xmlNodePtr cur_node = NULL; + xmlAttr *attribute; + long value = 0; + bool found = false; + char temp_char[25]; + uint check = 0; // bit field checker + + //printf("NEW CALL : cur_node = %p\n", cur_node); + + assert(state_id); + + // Get first state node + cur_node = model_get_node((xmlChar *)"savedstates/state"); + + // Lookup in properties + while (cur_node && cur_node->properties) { + attribute = cur_node->properties; + + // Look for the id attribute + if (model_get_node_str_attrib(cur_node, "id", &temp_char)) { + if (!xmlStrcmp(temp_char, (const xmlChar *)state_id)) { + found = true; + break; + } + } + cur_node = cur_node->next; + } + + // Check if the state has been found + if (!found) { + cur_node = NULL; + return -1; + } + + + // Count arrows + if (cur_node->children) { + cur_node = cur_node->children; + while (cur_node) { + if (!xmlStrcmp(cur_node->name, (const xmlChar *)"arrow")) + value++; + cur_node = cur_node->next; + } + } else { + return -1; + } + return value; +} + +bool model_get_next_arrow(struct arrow_t *new_arrow, + const char *state_id, + char dimension) +{ + static xmlNodePtr cur_node = NULL; + xmlAttr *attribute; + xmlChar *value; + bool found = false; + char temp_char[25]; + uint check = 0; // bit field checker + + //printf("NEW CALL : cur_node = %p\n", cur_node); + + assert(new_arrow); + assert(state_id); + + if (cur_node == NULL) { + // Get first state node + cur_node = model_get_node((xmlChar *)"savedstates/state"); + + // Lookup in properties + while (cur_node && cur_node->properties) { + attribute = cur_node->properties; + + // Look for the id attribute + if (model_get_node_str_attrib(cur_node, "id", &temp_char)) { + if (!xmlStrcmp(temp_char, (const xmlChar *)state_id)) { + found = true; + break; + } + } + cur_node = cur_node->next; + } + + // Check if the state has been found + if (!found) { + cur_node = NULL; + return false; + } + + // Get first arrow + if (cur_node->children) { + cur_node = cur_node->children; + + found = false; + while (cur_node && cur_node->name) { + if (!xmlStrcmp(cur_node->name, (const xmlChar *)"arrow")) { + found = true; + break; + } + cur_node = cur_node->next; + } + } + + // Check if the state has been found + if (!found) { + cur_node = NULL; + return false; + } + + } else { + // Get next arrow + found = false; + while (cur_node->next) { + cur_node = cur_node->next; + if (!xmlStrcmp(cur_node->name, (const xmlChar *)"arrow")) { + found = true; + break; + } + } + + // Check if the state has been found + if (!found) { + cur_node = NULL; + return false; + } + } + + //printf("DURING CALL : cur_node = %p\n", cur_node); + //printf("DURING CALL : cur_node->name = %s\n", cur_node->name); + + // Lookup in properties + if (cur_node && cur_node->properties) { + attribute = cur_node->properties; + + while(attribute && attribute->name && attribute->children) { + //printf("attr name : %s\n", attribute->name); + if (!xmlStrcmp(attribute->name, (const xmlChar *)"site")) { + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); + new_arrow->site = strtol((char *)value, NULL, 0); + xmlFree(value); + check |= READ_SITE; + } + if (!xmlStrcmp(attribute->name, (const xmlChar *)"weight")) { + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); + new_arrow->load = strtol((char *)value, NULL, 0); + xmlFree(value); + check |= READ_WEIGHT; + } + if (!xmlStrcmp(attribute->name, (const xmlChar *)"x")) { + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); + new_arrow->x = strtol((char *)value, NULL, 0); + xmlFree(value); + check |= READ_X; + } + if (!xmlStrcmp(attribute->name, (const xmlChar *)"y")) { + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); + new_arrow->y = strtol((char *)value, NULL, 0); + xmlFree(value); + check |= READ_Y; + } + if (!xmlStrcmp(attribute->name, (const xmlChar *)"z")) { + value = xmlNodeListGetString(cur_node->doc, attribute->children, 1); + new_arrow->z = strtol((char *)value, NULL, 0); + xmlFree(value); + check |= READ_Z; + } + attribute = attribute->next; + } + + switch(dimension) { + case 3: + return (bool)(check & SUCCESSFUL_READ_ARROW_XYZ); + case 2: + return (bool)(check & SUCCESSFUL_READ_ARROW_XY); + case 1: + return (bool)(check & SUCCESSFUL_READ_ARROW_X); + } + } + cur_node = NULL; + return false; +} diff --git a/gg/parsing.h b/gg/parsing.h new file mode 100644 index 0000000..8ac296e --- /dev/null +++ b/gg/parsing.h @@ -0,0 +1,39 @@ +/* + * 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 "../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); diff --git a/gg/random_walk.xml b/gg/random_walk.xml new file mode 100644 index 0000000..12ae465 --- /dev/null +++ b/gg/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/gg/ui.h b/gg/ui.h new file mode 100644 index 0000000..343198b --- /dev/null +++ b/gg/ui.h @@ -0,0 +1,232 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: User interface 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/base.h" + +G_BEGIN_DECLS + +#define GEM_GRAPH_CLIENT_TYPE_WINDOW (gem_graph_client_window_get_type()) + +G_DECLARE_FINAL_TYPE (GemGraphClientWindow, + gem_graph_client_window, + GEM_GRAPH_CLIENT, + WINDOW, + GtkApplicationWindow) + +G_END_DECLS + +G_BEGIN_DECLS + +#define GEM_GRAPH_CLIENT_TYPE_APPLICATION (gem_graph_client_application_get_type()) + +G_DECLARE_FINAL_TYPE (GemGraphClientApplication, + gem_graph_client_application, + GEM_GRAPH_CLIENT, + APPLICATION, + GtkApplication) + +GemGraphClientApplication *gem_graph_client_application_new(const char *application_id, + GApplicationFlags flags); + +G_END_DECLS + + +void ui_enable_action(const char *name); + +void ui_disable_action(const char *name); + +// +// Actions +// +void on_about_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data); + +void on_quit_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data); + +void on_preferences_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data); + +void on_togglesidebar_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data); + +void on_editmode_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data); + +void on_runmode_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data); + +void on_presentmode_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data); + +void on_openfile_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data); + +void on_closefile_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data); + +void on_savefile_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data); + +void on_toast_close_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data); + + +static const GActionEntry app_actions[] = { + { "quit", on_quit_action, NULL, NULL, NULL }, + { "about", on_about_action, NULL, NULL, NULL }, + { "preferences", on_preferences_action, NULL, NULL, NULL }, + { "togglesidebar", on_togglesidebar_action, NULL, NULL, NULL }, + { "editmode", on_editmode_action, NULL, NULL, NULL }, + { "runmode", on_runmode_action, NULL, NULL, NULL }, + { "presentmode", on_presentmode_action, NULL, NULL, NULL }, + { "openfile", on_openfile_action, NULL, NULL, NULL }, + { "closefile", on_closefile_action, NULL, NULL, NULL }, + { "savefile", on_savefile_action, NULL, NULL, NULL }, + { "toastclose", on_toast_close_action, NULL, NULL, NULL }, +}; + +// +// Actions responses +// +void on_openfile_response(GtkNativeDialog *native, + int response, + GemGraphClientWindow *self); + +void ui_model_loading(GObject *source_object, + GAsyncResult *result, + GemGraphClientWindow *self); + +// +// General events +// +void on_axis_value_change(GtkAdjustment *adjustment, gpointer data); + +gboolean on_glarea_render(GtkGLArea * area, GdkGLContext * context); + +void on_glarea_realize(GtkWidget *widget); + +void on_glarea_unrealize(GtkWidget *widget); + +void on_close_window(GtkWidget *widget); + +/* -------------------------------------------------------------------------- */ + +// +// Window primitives +// + +void ui_set_stack(int mode); + +void ui_send_internal_notification(const char *message); +void ui_close_internal_notification(void); +void ui_toggle_sidebar(); + +// +// Graphical stuff +// + +/* + * Creates GLArea and indexes it + * + * @params target_mode, meaning which ui_stack we're on + * target_widget, meaning the box that will host the GLArea + * + * @returns bool, true if success + */ +bool ui_setup_glarea(int target_mode, GtkWidget *target_widget); + + +/* + * Look for stack entry and returns stack_id + * + * @params container_widget, generally the GtkBox that contains the GLArea + * + * @returns stack_id + */ +long ui_get_graphic_stack(void *container_widget); + +/* + * Look for stack entry and initializes OpenGL for it + * + * @params container_widget, generally the GtkBox that contains the GLArea + * + * @returns bool, true if success + */ +bool ui_init_graphic_stack(void *container_widget, GError *error_buffer); + +/* + * Look for stack entry and shutdowns OpenGL for it + * + * @params container_widget, generally the GtkBox that contains the GLArea + * + * @returns bool, true if success + */ +bool ui_shutdown_graphic_stack(void *container_widget, GError *error_buffer); + + +void ui_clean_stack_index(void); + +/* + * Look for stack entry and triggers OpenGL for drawing + * + * @params container_widget, generally the GtkBox that contains the GLArea + * + * @returns bool, true if success + */ +bool ui_render_stack(GtkWidget *container_widget); + +/* + * Look for every stack entry and shutdowns OpenGL for it + * + * @params void + * + * @returns bool, true if success + */ +void ui_shutdown_all_graphic_stacks(void); + +/* + * Look for stack entry and triggers OpenGL for drawing + * + * @params container_widget, generally the GtkBox that contains the GLArea + * + * @returns bool, true if success + */ +bool ui_update_axis_stack(GtkWidget *container_widget, int axis, int value); + diff --git a/gg/window.c b/gg/window.c new file mode 100644 index 0000000..a7ed883 --- /dev/null +++ b/gg/window.c @@ -0,0 +1,236 @@ +/* + * Gem-graph OpenGL experiments + * + * Desc: User interface 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 + +#include "../../include/base.h" +#include "../../include/ui.h" + +/* -------------------------------------------------------------------------- */ + +static GemGraphClientWindow *window; + +/* -------------------------------------------------------------------------- */ + +struct _GemGraphClientWindow +{ + GtkApplicationWindow parent_instance; + + /* Template widgets */ + GtkHeaderBar *main_titlebar; + GtkStack *main_stack; + GtkStack *side_stack; + GtkPaned *main_paned; + GtkMenuButton *main_button_mode; + GtkToggleButton *main_button_sidebar; + GtkRevealer *toast_revealer; + GtkToggleButton *toast_close_button; + GtkLabel *toast_text; + GtkBox *control_zone; + GtkBox *run_glarea_box; + GtkBox *edition_glarea_box; + GtkBox *presentation_glarea_box; +}; + +G_DEFINE_FINAL_TYPE (GemGraphClientWindow, + gem_graph_client_window, + GTK_TYPE_APPLICATION_WINDOW) + +static void gem_graph_client_window_class_init(GemGraphClientWindowClass *klass) +{ + gchar *contents; + gsize len; + GError *err; + GBytes *bytes; + + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + + if (g_file_get_contents("src/ui/gemgraph.ui", &contents, &len, &err) == FALSE) + g_error("error reading gemgraph.ui: %s", err->message); + + bytes = g_bytes_new_take(contents, len); + gtk_widget_class_set_template(GTK_WIDGET_CLASS(klass), bytes); + + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + main_titlebar); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + main_stack); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + side_stack); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + main_paned); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + main_button_mode); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + main_button_sidebar); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + toast_revealer); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + toast_close_button); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + toast_text); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + control_zone); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + run_glarea_box); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + edition_glarea_box); + gtk_widget_class_bind_template_child(widget_class, + GemGraphClientWindow, + presentation_glarea_box); +} + +static void gem_graph_client_window_init(GemGraphClientWindow *self) +{ + gtk_widget_init_template(GTK_WIDGET(self)); + window = self; + + // Launch with sidebar off + ui_toggle_sidebar(); +} + +/* -------------------------------------------------------------------------- */ + +void ui_set_stack(int mode) +{ + //g_printerr("[debug] ui_set_stack()\n"); + + if (window->main_stack == NULL) { + g_printerr("Can't find self->main_stack !\n"); + return; + } + if (window->side_stack == NULL) { + g_printerr("Can't find self->side_stack !\n"); + return; + } + + // Switch on the first letter of the mode, because switch is soooo simple :) + switch(mode) { + case EDIT_MODE: + gtk_stack_set_visible_child_full(window->main_stack, + "edition", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_stack_set_visible_child_full(window->side_stack, + "edition", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_menu_button_set_icon_name(window->main_button_mode, + "document-edit-symbolic"); + ui_setup_glarea(EDIT_MODE, GTK_WIDGET(window->edition_glarea_box)); + break; + case RUN_MODE: + gtk_stack_set_visible_child_full(window->main_stack, + "run", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_stack_set_visible_child_full(window->side_stack, + "run", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_menu_button_set_icon_name(window->main_button_mode, + "system-run-symbolic"); + ui_setup_glarea(RUN_MODE, GTK_WIDGET(window->run_glarea_box)); + break; + case PRESENTATION_MODE: + gtk_stack_set_visible_child_full(window->main_stack, + "presentation", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_stack_set_visible_child_full(window->side_stack, + "presentation", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_menu_button_set_icon_name(window->main_button_mode, + "x-office-presentation-symbolic"); + ui_setup_glarea(PRESENTATION_MODE, + GTK_WIDGET(window->presentation_glarea_box)); + break; + case HOME_MODE: + gtk_stack_set_visible_child_full(window->main_stack, + "home", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_stack_set_visible_child_full(window->side_stack, + "home", + GTK_STACK_TRANSITION_TYPE_CROSSFADE); + gtk_paned_set_position(window->main_paned, 0); + gtk_menu_button_set_icon_name(window->main_button_mode, + "user-home-symbolic"); + break; + default: + break; + } +} + +void ui_send_internal_notification(const char *message) +{ + if (window->toast_revealer == NULL) { + g_printerr("Can't find self->toast_overlay !\n"); + return; + } + + if (window->toast_text == NULL) { + g_printerr("Can't find self->toast_overlay !\n"); + return; + } + + gtk_label_set_label(window->toast_text, message); + gtk_revealer_set_reveal_child(window->toast_revealer, true); + g_printerr("%s\n", message); +} + +void ui_close_internal_notification(void) +{ + if (window->toast_revealer == NULL) { + g_printerr("Can't find self->toast_overlay !\n"); + return; + } + + if (window->toast_text == NULL) { + g_printerr("Can't find self->toast_overlay !\n"); + return; + } + + gtk_revealer_set_reveal_child(window->toast_revealer, false); +} + + +void ui_toggle_sidebar(void) +{ + int position = gtk_paned_get_position(window->main_paned); + + if (position != 0) { + gtk_paned_set_position(window->main_paned, 0); + } else { + gtk_paned_set_position(window->main_paned, 400); + } +} diff --git a/hot.c b/hot.c index b815275..36b92d9 100644 --- a/hot.c +++ b/hot.c @@ -5,29 +5,33 @@ #include "cold.h" GtkWidget *get_space_page_new(){ - GtkWidget *space_grid = gtk_grid_new(); +// https://docs.gtk.org/gtk4/visual_index.html < widgets gallery GtkScrolledWindow *scrolled = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new()); gtk_scrolled_window_set_min_content_width (scrolled, 600); gtk_scrolled_window_set_min_content_height (scrolled, 600); - GtkAdjustment *width = gtk_adjustment_new (600, 300, 1000, 1, 1, 1000); - GtkAdjustment *height = gtk_adjustment_new (600, 300, 1000, 1, 1, 1000); +// GtkAdjustment *width = gtk_adjustment_new (600, 300, 1000, 1, 1, 1000); +// GtkAdjustment *height = gtk_adjustment_new (600, 300, 1000, 1, 1, 1000); // (value, lower, upper, step_increment, page_increment, page_size) - GtkWidget *viewport = gtk_viewport_new (width, height); - gtk_scrolled_window_set_child (scrolled, viewport); + GtkWidget *GLarea = gtk_gl_area_new(); + gtk_scrolled_window_set_child (scrolled, GLarea); +// https://docs.gtk.org/gtk4/class.GLArea.html - GtkBox *controls_box = GTK_BOX(gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0)); // spacing = 2 + GtkBox *controls_box = GTK_BOX(gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0)); gtk_box_append (controls_box, gtk_button_new_with_label ("RUN / STOP")); gtk_box_append (controls_box, gtk_button_new_with_label ("slow down / speed up")); gtk_box_append (controls_box, gtk_button_new_with_label ("step by step")); - gtk_box_append (controls_box, gtk_button_new_with_label ("buffer")); +// GtkLevelBar *buffer = GTK_LEVEL_BAR (gtk_level_bar_new ()); +// GtkWidget *buffer = gtk_level_bar_new_for_interval (0, 100000); +// gtk_level_bar_set_mode (buffer, GTK_LEVEL_BAR_MODE_CONTINUOUS); //_DISCRETE + gtk_box_append (controls_box, gtk_button_new_with_label ("---- buffer ----")); GtkBox *XYZ_box = GTK_BOX(gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2)); // spacing = 2 // 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, 10, 0, 0); - GtkAdjustment *Y_adjust = gtk_adjustment_new (0, 0, 380, 10, 0, 0); - GtkAdjustment *Z_adjust = gtk_adjustment_new (0, 0, 380, 10, 0, 0); + GtkAdjustment *X_adjust = gtk_adjustment_new (0, 0, 380, 1, 0, 0); + GtkAdjustment *Y_adjust = gtk_adjustment_new (0, 0, 380, 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); @@ -36,12 +40,64 @@ GtkWidget *get_space_page_new(){ gtk_box_append (XYZ_box, scroll_Y); gtk_box_append (XYZ_box, scroll_Z); - gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET(scrolled), 0, 0, 2, 1); - gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET(controls_box), 0, 1, 1, 1); - gtk_grid_attach (GTK_GRID(space_grid), gtk_button_new_with_label ("Objects / Situations (transparences, styles)"), 0, 2, 1, 1); - gtk_grid_attach (GTK_GRID(space_grid), gtk_button_new_with_label ("zoom, +/- grid,\npresentation,\nstyles,..."), 1, 1, 1, 2); - gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET(XYZ_box), 2, 0, 1, 3); + GtkWidget *bottom_grid = gtk_grid_new(); + gtk_grid_attach (GTK_GRID(bottom_grid), GTK_WIDGET(controls_box), 0, 0, 1, 1); + gtk_grid_attach (GTK_GRID(bottom_grid), gtk_button_new_with_label ("Objects / Situations (transparences, styles)"), 0, 1, 1, 1); + gtk_grid_attach (GTK_GRID(bottom_grid), gtk_button_new_with_label ("zoom, +/- grid,\npresentation,\nstyles,..."), 1, 0, 1, 2); + + GtkWidget *space_grid = gtk_grid_new(); + gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET(scrolled), 0, 0, 1, 1); + gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET(XYZ_box), 1, 0, 1, 1); + gtk_grid_attach (GTK_GRID(space_grid), GTK_WIDGET(bottom_grid), 0, 1, 2, 1); // ?! échec x_size +// gtk_grid_attach (GTK_GRID(space_grid), gtk_button_new_with_label ("?"), 1, 1, 1, 1); + return space_grid; } - +/* +gg/draw.c: * Draws the current buffer to a gl_area +gg/draw.c: * @param gl_area, ptr to the gl_area widget +gg/init.c: * Initializes the buffer of a gl_area +gg/init.c: * @param gl_area, ptr to the gl_area widget +gg/init.c: * Initializes the shaders of a gl_area and link them to a program +gg/init.c: * @param gl_area, ptr to the gl_area widget +gg/graphics.c: * @param gl_area, ptr to the gl_area widget +gg/graphics.c: * Shutdowns a gl_area +gg/graphics.c: * @param gl_area, ptr to the gl_area widget +gg/GtkGLArea.c: void *gl_area; +gg/GtkGLArea.c: gtk_widget_queue_draw((GtkWidget*)(stack_index[i].gl_area)); +gg/GtkGLArea.c: GtkWidget *gl_area; +gg/GtkGLArea.c: gl_area = GTK_WIDGET(gtk_gl_area_new()); +gg/GtkGLArea.c: assert(gl_area); +gg/GtkGLArea.c: //gtk_widget_set_size_request(gl_area, 1000, 1000); +gg/GtkGLArea.c: gtk_gl_area_set_auto_render(GTK_GL_AREA(gl_area), true); +gg/GtkGLArea.c: gtk_widget_set_hexpand(gl_area, TRUE); +gg/GtkGLArea.c: gtk_widget_set_vexpand(gl_area, TRUE); +gg/GtkGLArea.c: //gtk_widget_set_halign(gl_area, GTK_ALIGN_CENTER); +gg/GtkGLArea.c: //gtk_widget_set_valign(gl_area, GTK_ALIGN_CENTER); +gg/GtkGLArea.c: g_signal_connect(GTK_GL_AREA(gl_area), +gg/GtkGLArea.c: g_signal_connect(gl_area, +gg/GtkGLArea.c: g_signal_connect(gl_area, +gg/GtkGLArea.c: stack_index[stack_index_size-1].gl_area = (void*)gl_area; +gg/GtkGLArea.c: gtk_box_append(GTK_BOX(target_widget), gl_area); +gg/GtkGLArea.c: gtk_widget_show(GTK_WIDGET(gl_area)); +gg/events.c: if(gtk_gl_area_get_error(area) != NULL) { +gg/events.c: gtk_gl_area_make_current(GTK_GL_AREA(widget)); +gg/events.c: if(gtk_gl_area_get_error(GTK_GL_AREA(widget)) != NULL) { +gg/events.c: gtk_gl_area_set_auto_render(GTK_GL_AREA(widget), true); +gg/events.c: gtk_gl_area_make_current(GTK_GL_AREA(widget)); +gg/events.c: if(gtk_gl_area_get_error(GTK_GL_AREA(widget)) != NULL) { +gg/graphics.h: * Structure describing a gl_area and its parameters, used to create a table +gg/graphics.h: * of Gem-graph client current gl_areas +gg/graphics.h: * Dynamic array of ptrs to dynamically allocated gl_area_entry +gg/graphics.h: * Initializes a gl_area +gg/graphics.h: * @param gl_area, ptr to the gl_area widget +gg/graphics.h: * Draws the current buffer to a gl_area +gg/graphics.h: * @param gl_area, ptr to the gl_area widget +gg/graphics.h: * Shutdowns a gl_area +gg/graphics.h: * @param gl_area, ptr to the gl_area widget +gg/graphics.h: * Initializes the shaders of a gl_area and link them to a program +gg/graphics.h: * @param gl_area, ptr to the gl_area widget +gg/graphics.h: * Initializes the buffer of a gl_area +gg/graphics.h: * @param gl_area, ptr to the gl_area widget +*/ diff --git a/warm.c b/warm.c index 6913140..99ce544 100644 --- a/warm.c +++ b/warm.c @@ -47,7 +47,7 @@ GtkWidget *get_rules_page_new(){ gtk_paned_set_start_child (GTK_PANED(hpaned), GTK_WIDGET (frame1)); gtk_paned_set_end_child (GTK_PANED(hpaned), GTK_WIDGET (frame2)); gtk_widget_set_size_request (hpaned, 600, 600); - gtk_widget_set_size_request (frame1, 300, 0); // < utile seulement pour la largeur min/max + gtk_widget_set_size_request (frame1, 100, 0); // < utile seulement pour la largeur min/max // gtk_widget_set_size_request (frame2, 50, 100); // gtk_grid_attach (GTK_GRID (rules_grid), hpaned, 0, 0, 1, 1);