/* * Gem-graph OpenGL experiments * * Desc: User interface functions * * Copyright (C) 2023 Adrien Bourmault * * This file is part of Gem-graph. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include #include #include #include "../../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; }