PIKApp/plug-ins/lighting/lighting-ui.c

1098 lines
43 KiB
C
Raw Normal View History

2023-09-26 00:35:21 +02:00
/* Lighting Effects - A plug-in for PIKA
*
* Dialog creation and updaters, callbacks and event-handlers
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <errno.h>
#include <glib/gstdio.h>
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "lighting-ui.h"
#include "lighting-main.h"
#include "lighting-icons.h"
#include "lighting-image.h"
#include "lighting-apply.h"
#include "lighting-preview.h"
#include "libpika/stdplugins-intl.h"
extern LightingValues mapvals;
static GtkWidget *appwin = NULL;
GtkWidget *previewarea = NULL;
GtkWidget *spin_pos_x = NULL;
GtkWidget *spin_pos_y = NULL;
GtkWidget *spin_pos_z = NULL;
GtkWidget *spin_dir_x = NULL;
GtkWidget *spin_dir_y = NULL;
GtkWidget *spin_dir_z = NULL;
static gchar *lighting_effects_path = NULL;
2023-10-30 23:55:30 +01:00
static void update_preview (PikaProcedureConfig *config);
static void save_lighting_preset (GtkWidget *widget,
gpointer data);
static void save_preset_response (GtkFileChooser *chooser,
gint response_id,
gpointer data);
static void load_lighting_preset (GtkWidget *widget,
gpointer data);
static void load_preset_response (GtkFileChooser *chooser,
gint response_id,
gpointer data);
static void light_source_changed (GtkWidget *widget,
gpointer data);
static void apply_settings (PikaProcedureConfig *config);
static void isolate_selected_light (PikaProcedureConfig *config);
2023-09-26 00:35:21 +02:00
/*****************************************/
/* Main window light type menu callback. */
/*****************************************/
static void
2023-10-30 23:55:30 +01:00
apply_settings (PikaProcedureConfig *config)
2023-09-26 00:35:21 +02:00
{
2023-10-30 23:55:30 +01:00
gint k = mapvals.light_selected;
gchar *pos_x = g_strdup_printf (("light-position-x-%d"), k + 1);
gchar *pos_y = g_strdup_printf (("light-position-y-%d"), k + 1);
gchar *pos_z = g_strdup_printf (("light-position-z-%d"), k + 1);
gchar *dir_x = g_strdup_printf (("light-direction-x-%d"), k + 1);
gchar *dir_y = g_strdup_printf (("light-direction-y-%d"), k + 1);
gchar *dir_z = g_strdup_printf (("light-direction-z-%d"), k + 1);
switch (mapvals.lightsource[k].type)
2023-09-26 00:35:21 +02:00
{
2023-10-30 23:55:30 +01:00
case NO_LIGHT:
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), pos_x,
FALSE, NULL, NULL, FALSE);
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), pos_y,
FALSE, NULL, NULL, FALSE);
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), pos_z,
FALSE, NULL, NULL, FALSE);
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), dir_x,
FALSE, NULL, NULL, FALSE);
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), dir_y,
FALSE, NULL, NULL, FALSE);
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), dir_z,
FALSE, NULL, NULL, FALSE);
break;
case POINT_LIGHT:
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), pos_x,
TRUE, NULL, NULL, FALSE);
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), pos_y,
TRUE, NULL, NULL, FALSE);
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), pos_z,
TRUE, NULL, NULL, FALSE);
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), dir_x,
FALSE, NULL, NULL, FALSE);
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), dir_y,
FALSE, NULL, NULL, FALSE);
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), dir_z,
FALSE, NULL, NULL, FALSE);
break;
case DIRECTIONAL_LIGHT:
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), pos_x,
FALSE, NULL, NULL, FALSE);
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), pos_y,
FALSE, NULL, NULL, FALSE);
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), pos_z,
FALSE, NULL, NULL, FALSE);
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), dir_x,
TRUE, NULL, NULL, FALSE);
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), dir_y,
TRUE, NULL, NULL, FALSE);
pika_procedure_dialog_set_sensitive (PIKA_PROCEDURE_DIALOG (appwin), dir_z,
TRUE, NULL, NULL, FALSE);
break;
default:
break;
2023-09-26 00:35:21 +02:00
}
2023-10-30 23:55:30 +01:00
g_free (pos_x);
g_free (pos_y);
g_free (pos_z);
g_free (dir_x);
g_free (dir_y);
g_free (dir_z);
2023-09-26 00:35:21 +02:00
}
/******************************************/
/* Main window "Preview!" button callback */
/******************************************/
static void
preview_callback (GtkWidget *widget)
{
preview_compute ();
gtk_widget_queue_draw (previewarea);
}
static void
2023-10-30 23:55:30 +01:00
update_preview (PikaProcedureConfig *config)
2023-09-26 00:35:21 +02:00
{
2023-10-30 23:55:30 +01:00
copy_from_config (config);
isolate_selected_light (config);
2023-09-26 00:35:21 +02:00
2023-10-30 23:55:30 +01:00
apply_settings (config);
2023-09-26 00:35:21 +02:00
2023-10-30 23:55:30 +01:00
preview_compute ();
gtk_widget_queue_draw (previewarea);
2023-09-26 00:35:21 +02:00
}
/********************************/
/* Create and show main dialog. */
/********************************/
gboolean
2023-10-30 23:55:30 +01:00
main_dialog (PikaProcedure *procedure,
PikaProcedureConfig *config,
PikaDrawable *drawable)
2023-09-26 00:35:21 +02:00
{
GtkWidget *main_hbox;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *frame;
GtkWidget *button;
GtkWidget *toggle;
2023-10-30 23:55:30 +01:00
GtkWidget *combo;
GtkWidget *image;
2023-09-26 00:35:21 +02:00
gchar *path;
gboolean run = FALSE;
/*
GtkWidget *image;
*/
pika_ui_init (PLUG_IN_BINARY);
path = pika_pikarc_query ("lighting-effects-path");
if (path)
{
lighting_effects_path = g_filename_from_utf8 (path, -1, NULL, NULL, NULL);
g_free (path);
}
lighting_icons_init ();
2023-10-30 23:55:30 +01:00
appwin = pika_procedure_dialog_new (procedure,
PIKA_PROCEDURE_CONFIG (config),
_("Lighting Effects"));
2023-09-26 00:35:21 +02:00
/* Create the Preview */
/* ================== */
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
2023-10-30 23:55:30 +01:00
gtk_widget_set_visible (vbox, TRUE);
2023-09-26 00:35:21 +02:00
/* Add preview widget and various buttons to the first part */
/* ======================================================== */
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
gtk_widget_realize (appwin);
previewarea = gtk_drawing_area_new ();
gtk_widget_set_size_request (previewarea, PREVIEW_WIDTH, PREVIEW_HEIGHT);
gtk_widget_set_events (previewarea, (GDK_EXPOSURE_MASK |
GDK_BUTTON1_MOTION_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK));
g_signal_connect (previewarea, "event",
G_CALLBACK (preview_events),
previewarea);
g_signal_connect (previewarea, "draw",
G_CALLBACK (preview_draw),
previewarea);
gtk_container_add (GTK_CONTAINER (frame), previewarea);
gtk_widget_show (previewarea);
/* create preview options, frame and vbox */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
button = gtk_button_new_with_mnemonic (_("_Update"));
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect (button, "clicked",
G_CALLBACK (preview_callback),
NULL);
gtk_widget_show (button);
pika_help_set_help_data (button, _("Recompute preview image"), NULL);
toggle = gtk_check_button_new_with_mnemonic (_("I_nteractive"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
mapvals.interactive_preview);
gtk_box_pack_start (GTK_BOX (hbox), toggle, TRUE, TRUE, 0);
g_signal_connect (toggle, "toggled",
G_CALLBACK (pika_toggle_button_update),
&mapvals.interactive_preview);
g_signal_connect (toggle, "toggled",
G_CALLBACK (interactive_preview_callback),
NULL);
gtk_widget_show (toggle);
pika_help_set_help_data (toggle,
_("Enable/disable real time preview of changes"),
NULL);
2023-10-30 23:55:30 +01:00
/* PikaProcedureDialog begins here */
pika_procedure_dialog_get_label (PIKA_PROCEDURE_DIALOG (appwin),
"options-tab", _("Op_tions"), FALSE, TRUE);
pika_procedure_dialog_get_label (PIKA_PROCEDURE_DIALOG (appwin),
"light-tab", _("_Light"), FALSE, TRUE);
pika_procedure_dialog_get_label (PIKA_PROCEDURE_DIALOG (appwin),
"material-tab", _("_Material"), FALSE, TRUE);
pika_procedure_dialog_get_label (PIKA_PROCEDURE_DIALOG (appwin),
"bump-map-tab", _("_Bump Map"), FALSE, TRUE);
pika_procedure_dialog_get_label (PIKA_PROCEDURE_DIALOG (appwin),
"environment-map-tab", _("_Environment Map"),
FALSE, TRUE);
/* Options tab */
pika_procedure_dialog_get_label (PIKA_PROCEDURE_DIALOG (appwin),
"general-options", _("General Options"),
FALSE, FALSE);
pika_procedure_dialog_get_scale_entry (PIKA_PROCEDURE_DIALOG (appwin),
"distance", 1.0);
pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), "general-box",
"transparent-background",
"new-image",
"antialiasing",
"distance",
NULL);
pika_procedure_dialog_fill_frame (PIKA_PROCEDURE_DIALOG (appwin),
"options-frame",
"general-options", FALSE,
"general-box");
pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), "options-box",
"options-frame", NULL);
g_signal_connect (config, "notify::transparent-background",
G_CALLBACK (update_preview),
config);
g_signal_connect (config, "notify::new-image",
G_CALLBACK (update_preview),
config);
g_signal_connect (config, "notify::antialiasing",
G_CALLBACK (update_preview),
config);
g_signal_connect (config, "notify::distance",
G_CALLBACK (update_preview),
config);
/* Light tab */
pika_procedure_dialog_get_label (PIKA_PROCEDURE_DIALOG (appwin),
"light-label", _("Light Settings"),
FALSE, FALSE);
for (gint i = 1; i <= 6; i++)
{
gchar *temp_box;
gchar *temp_label;
gchar *temp_field_1;
gchar *temp_field_2;
gchar *temp_field_3;
gchar *temp_notify;
temp_label = g_strdup_printf ("light-color-label-%d", i);
pika_procedure_dialog_get_label (PIKA_PROCEDURE_DIALOG (appwin),
temp_label, _("Color"),
FALSE, FALSE);
g_free (temp_label);
temp_label = g_strdup_printf ("light-position-label-%d", i);
pika_procedure_dialog_get_label (PIKA_PROCEDURE_DIALOG (appwin),
temp_label, _("Position"),
FALSE, FALSE);
g_free (temp_label);
temp_label = g_strdup_printf ("light-direction-label-%d", i);
pika_procedure_dialog_get_label (PIKA_PROCEDURE_DIALOG (appwin),
temp_label, _("Direction"),
FALSE, FALSE);
g_free (temp_label);
temp_box = g_strdup_printf ("light-color-vbox-%d", i);
temp_label = g_strdup_printf ("light-color-label-%d", i);
temp_field_1 = g_strdup_printf ("light-type-%d", i);
temp_field_2 = g_strdup_printf ("light-color-%d", i);
temp_field_3 = g_strdup_printf ("light-intensity-%d", i);
pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), temp_box,
temp_label,
temp_field_1,
temp_field_2,
temp_field_3,
NULL);
temp_notify = g_strdup_printf ("notify::%s", temp_field_1);
g_signal_connect (config, temp_notify,
G_CALLBACK (update_preview),
config);
g_free (temp_notify);
temp_notify = g_strdup_printf ("notify::%s", temp_field_2);
g_signal_connect (config, temp_notify,
G_CALLBACK (update_preview),
config);
g_free (temp_notify);
temp_notify = g_strdup_printf ("notify::%s", temp_field_3);
g_signal_connect (config, temp_notify,
G_CALLBACK (update_preview),
config);
g_free (temp_notify);
g_free (temp_box);
g_free (temp_label);
g_free (temp_field_1);
g_free (temp_field_2);
g_free (temp_field_3);
temp_box = g_strdup_printf ("light-position-vbox-%d", i);
temp_label = g_strdup_printf ("light-position-label-%d", i);
temp_field_1 = g_strdup_printf ("light-position-x-%d", i);
temp_field_2 = g_strdup_printf ("light-position-y-%d", i);
temp_field_3 = g_strdup_printf ("light-position-z-%d", i);
pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), temp_box,
temp_label,
temp_field_1,
temp_field_2,
temp_field_3,
NULL);
temp_notify = g_strdup_printf ("notify::%s", temp_field_1);
g_signal_connect (config, temp_notify,
G_CALLBACK (update_preview),
config);
g_free (temp_notify);
temp_notify = g_strdup_printf ("notify::%s", temp_field_2);
g_signal_connect (config, temp_notify,
G_CALLBACK (update_preview),
config);
g_free (temp_notify);
temp_notify = g_strdup_printf ("notify::%s", temp_field_3);
g_signal_connect (config, temp_notify,
G_CALLBACK (update_preview),
config);
g_free (temp_notify);
g_free (temp_box);
g_free (temp_label);
g_free (temp_field_1);
g_free (temp_field_2);
g_free (temp_field_3);
temp_box = g_strdup_printf ("light-direction-vbox-%d", i);
temp_label = g_strdup_printf ("light-direction-label-%d", i);
temp_field_1 = g_strdup_printf ("light-direction-x-%d", i);
temp_field_2 = g_strdup_printf ("light-direction-y-%d", i);
temp_field_3 = g_strdup_printf ("light-direction-z-%d", i);
pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), temp_box,
temp_label,
temp_field_1,
temp_field_2,
temp_field_3,
NULL);
temp_notify = g_strdup_printf ("notify::%s", temp_field_1);
g_signal_connect (config, temp_notify,
G_CALLBACK (update_preview),
config);
g_free (temp_notify);
temp_notify = g_strdup_printf ("notify::%s", temp_field_2);
g_signal_connect (config, temp_notify,
G_CALLBACK (update_preview),
config);
g_free (temp_notify);
temp_notify = g_strdup_printf ("notify::%s", temp_field_3);
g_signal_connect (config, temp_notify,
G_CALLBACK (update_preview),
config);
g_free (temp_notify);
g_free (temp_box);
g_free (temp_label);
g_free (temp_field_1);
g_free (temp_field_2);
g_free (temp_field_3);
temp_box = g_strdup_printf ("light-hbox-%d", i);
temp_field_1 = g_strdup_printf ("light-color-vbox-%d", i);
temp_field_2 = g_strdup_printf ("light-position-vbox-%d", i);
temp_field_3 = g_strdup_printf ("light-direction-vbox-%d", i);
hbox = pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), temp_box,
temp_field_1,
temp_field_2,
temp_field_3,
NULL);
g_free (temp_box);
g_free (temp_field_1);
g_free (temp_field_2);
g_free (temp_field_3);
gtk_orientable_set_orientation (GTK_ORIENTABLE (hbox),
GTK_ORIENTATION_HORIZONTAL);
}
combo = pika_procedure_dialog_get_widget (PIKA_PROCEDURE_DIALOG (appwin),
"which-light", G_TYPE_NONE);
pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), "light-settings-box",
"which-light",
"light-hbox-1",
"light-hbox-2",
"light-hbox-3",
"light-hbox-4",
"light-hbox-5",
"light-hbox-6",
"isolate",
NULL);
pika_procedure_dialog_fill_frame (PIKA_PROCEDURE_DIALOG (appwin),
"light-frame",
"light-label", FALSE,
"light-settings-box");
pika_procedure_dialog_get_label (PIKA_PROCEDURE_DIALOG (appwin),
"preset-label", _("Lighting presets: "),
FALSE, FALSE);
hbox = pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), "preset-hbox",
"preset-label", NULL);
gtk_orientable_set_orientation (GTK_ORIENTABLE (hbox),
GTK_ORIENTATION_HORIZONTAL);
gtk_widget_set_halign (hbox, GTK_ALIGN_END);
button = gtk_button_new_with_mnemonic (_("_Save"));
g_signal_connect (button, "clicked",
G_CALLBACK (save_lighting_preset),
NULL);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_set_visible (button, TRUE);
button = gtk_button_new_with_mnemonic (_("_Open"));
g_signal_connect (button, "clicked",
G_CALLBACK (load_lighting_preset),
NULL);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_set_visible (button, TRUE);
pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), "light-box",
"light-frame", "preset-hbox", NULL);
g_signal_connect (config, "notify::which-light",
G_CALLBACK (update_preview),
config);
g_signal_connect (config, "notify::isolate",
G_CALLBACK (update_preview),
config);
/* Material Tab */
pika_procedure_dialog_get_label (PIKA_PROCEDURE_DIALOG (appwin),
"material-label", _("Material Properties"),
FALSE, FALSE);
hbox = pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), "glowing-hbox",
"ambient-intensity",
NULL);
gtk_orientable_set_orientation (GTK_ORIENTABLE (hbox),
GTK_ORIENTATION_HORIZONTAL);
image = gtk_image_new_from_icon_name (LIGHTING_INTENSITY_AMBIENT_LOW,
GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_box_reorder_child (GTK_BOX (hbox), image, 0);
gtk_widget_set_visible (image, TRUE);
image = gtk_image_new_from_icon_name (LIGHTING_INTENSITY_AMBIENT_HIGH,
GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_widget_set_visible (image, TRUE);
hbox = pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), "bright-hbox",
"diffuse-intensity",
NULL);
gtk_orientable_set_orientation (GTK_ORIENTABLE (hbox),
GTK_ORIENTATION_HORIZONTAL);
image = gtk_image_new_from_icon_name (LIGHTING_INTENSITY_DIFFUSE_LOW,
GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_widget_set_visible (image, TRUE);
gtk_box_reorder_child (GTK_BOX (hbox), image, 0);
image = gtk_image_new_from_icon_name (LIGHTING_INTENSITY_DIFFUSE_HIGH,
GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_widget_set_visible (image, TRUE);
hbox = pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), "diffuse-reflect-hbox",
"diffuse-reflectivity",
NULL);
gtk_orientable_set_orientation (GTK_ORIENTABLE (hbox),
GTK_ORIENTATION_HORIZONTAL);
image = gtk_image_new_from_icon_name (LIGHTING_REFLECTIVITY_DIFFUSE_LOW,
GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_widget_set_visible (image, TRUE);
gtk_box_reorder_child (GTK_BOX (hbox), image, 0);
image = gtk_image_new_from_icon_name (LIGHTING_REFLECTIVITY_DIFFUSE_HIGH,
GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_widget_set_visible (image, TRUE);
hbox = pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), "shiny-hbox",
"specular-reflectivity",
NULL);
gtk_orientable_set_orientation (GTK_ORIENTABLE (hbox),
GTK_ORIENTATION_HORIZONTAL);
image = gtk_image_new_from_icon_name (LIGHTING_REFLECTIVITY_SPECULAR_LOW,
GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_widget_set_visible (image, TRUE);
gtk_box_reorder_child (GTK_BOX (hbox), image, 0);
image = gtk_image_new_from_icon_name (LIGHTING_REFLECTIVITY_SPECULAR_HIGH,
GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_widget_set_visible (image, TRUE);
hbox = pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), "polished-hbox",
"highlight",
NULL);
gtk_orientable_set_orientation (GTK_ORIENTABLE (hbox),
GTK_ORIENTATION_HORIZONTAL);
image = gtk_image_new_from_icon_name (LIGHTING_REFLECTIVITY_HIGHLIGHT_LOW,
GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_widget_set_visible (image, TRUE);
gtk_box_reorder_child (GTK_BOX (hbox), image, 0);
image = gtk_image_new_from_icon_name (LIGHTING_REFLECTIVITY_HIGHLIGHT_HIGH,
GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
gtk_widget_set_visible (image, TRUE);
pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), "material-values-box",
"glowing-hbox",
"bright-hbox",
"diffuse-reflect-hbox",
"shiny-hbox",
"polished-hbox",
"metallic",
NULL);
pika_procedure_dialog_fill_frame (PIKA_PROCEDURE_DIALOG (appwin),
"material-frame",
"material-label", FALSE,
"material-values-box");
pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), "material-box",
"material-frame", NULL);
g_signal_connect (config, "notify::ambient-intensity",
G_CALLBACK (update_preview),
config);
g_signal_connect (config, "notify::diffuse-intensity",
G_CALLBACK (update_preview),
config);
g_signal_connect (config, "notify::diffuse-reflectivity",
G_CALLBACK (update_preview),
config);
g_signal_connect (config, "notify::specular-reflectivity",
G_CALLBACK (update_preview),
config);
g_signal_connect (config, "notify::highlight",
G_CALLBACK (update_preview),
config);
g_signal_connect (config, "notify::metallic",
G_CALLBACK (update_preview),
config);
/* Bump Map Tab */
pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin),
"bump-map-options-box",
"bump-drawable",
"bumpmap-type",
"bumpmap-max-height",
NULL);
pika_procedure_dialog_fill_frame (PIKA_PROCEDURE_DIALOG (appwin),
"bump-map-frame",
"do-bumpmap", FALSE,
"bump-map-options-box");
pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin), "bump-map-box",
"bump-map-frame",
NULL);
g_signal_connect (config, "notify::do-bumpmap",
G_CALLBACK (update_preview),
config);
g_signal_connect (config, "notify::bump-drawable",
G_CALLBACK (update_preview),
config);
g_signal_connect (config, "notify::bumpmap-type",
G_CALLBACK (update_preview),
config);
g_signal_connect (config, "notify::bumpmap-max-height",
G_CALLBACK (update_preview),
config);
/* Environment Map Tab */
pika_procedure_dialog_fill_frame (PIKA_PROCEDURE_DIALOG (appwin),
"environment-map-frame",
"do-envmap", FALSE,
"env-drawable");
pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin),
"environment-map-box",
"environment-map-frame",
NULL);
g_signal_connect (config, "notify::do-envmap",
G_CALLBACK (update_preview),
config);
g_signal_connect (config, "notify::env-drawable",
G_CALLBACK (update_preview),
config);
/* Create Notebook */
pika_procedure_dialog_fill_notebook (PIKA_PROCEDURE_DIALOG (appwin),
"main-notebook",
"options-tab", "options-box",
"light-tab", "light-box",
"material-tab", "material-box",
"bump-map-tab", "bump-map-box",
"environment-map-tab", "environment-map-box",
NULL);
light_source_changed (combo, config);
/* Create overall layout */
main_hbox = pika_procedure_dialog_fill_box (PIKA_PROCEDURE_DIALOG (appwin),
"main-hbox",
"main-notebook",
NULL);
gtk_orientable_set_orientation (GTK_ORIENTABLE (main_hbox),
GTK_ORIENTATION_HORIZONTAL);
gtk_box_pack_start (GTK_BOX (main_hbox), vbox, FALSE, FALSE, 0);
gtk_box_reorder_child (GTK_BOX (main_hbox), vbox, 0);
pika_procedure_dialog_fill (PIKA_PROCEDURE_DIALOG (appwin), "main-hbox", NULL);
2023-09-26 00:35:21 +02:00
gtk_widget_show (appwin);
{
GdkCursor *cursor;
cursor = gdk_cursor_new_for_display (gtk_widget_get_display (previewarea),
GDK_HAND2);
gdk_window_set_cursor (gtk_widget_get_window (previewarea), cursor);
g_object_unref (cursor);
}
if (image_setup (drawable, TRUE))
preview_compute ();
2023-10-30 23:55:30 +01:00
g_signal_connect (combo, "value-changed",
G_CALLBACK (light_source_changed),
config);
run = pika_procedure_dialog_run (PIKA_PROCEDURE_DIALOG (appwin));
2023-09-26 00:35:21 +02:00
if (preview_rgb_data != NULL)
g_free (preview_rgb_data);
if (preview_surface != NULL)
cairo_surface_destroy (preview_surface);
gtk_widget_destroy (appwin);
return run;
}
static void
save_lighting_preset (GtkWidget *widget,
gpointer data)
{
static GtkWidget *window = NULL;
if (! window)
{
window =
gtk_file_chooser_dialog_new (_("Save Lighting Preset"),
GTK_WINDOW (appwin),
GTK_FILE_CHOOSER_ACTION_SAVE,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Save"), GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (window), GTK_RESPONSE_OK);
pika_dialog_set_alternative_button_order (GTK_DIALOG (window),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (window),
TRUE);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed),
&window);
g_signal_connect (window, "response",
G_CALLBACK (save_preset_response),
NULL);
}
if (lighting_effects_path)
{
GList *list;
gchar *dir;
list = pika_path_parse (lighting_effects_path, 256, FALSE, NULL);
dir = pika_path_get_user_writable_dir (list);
pika_path_free (list);
if (! dir)
dir = g_strdup (pika_directory ());
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (window), dir);
g_free (dir);
}
else
{
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (window),
g_get_tmp_dir ());
}
gtk_window_present (GTK_WINDOW (window));
}
static void
save_preset_response (GtkFileChooser *chooser,
gint response_id,
gpointer data)
{
FILE *fp;
gint num_lights = 0;
gint k;
LightSettings *source;
gchar buffer1[G_ASCII_DTOSTR_BUF_SIZE];
gchar buffer2[G_ASCII_DTOSTR_BUF_SIZE];
gchar buffer3[G_ASCII_DTOSTR_BUF_SIZE];
gint blen = G_ASCII_DTOSTR_BUF_SIZE;
if (response_id == GTK_RESPONSE_OK)
{
gchar *filename = gtk_file_chooser_get_filename (chooser);
fp = g_fopen (filename, "wb");
if (!fp)
{
g_message (_("Could not open '%s' for writing: %s"),
filename, g_strerror (errno));
}
else
{
for (k = 0; k < NUM_LIGHTS; k++)
if (mapvals.lightsource[k].type != NO_LIGHT)
++num_lights;
fprintf (fp, "Number of lights: %d\n", num_lights);
for (k = 0; k < NUM_LIGHTS; k++)
if (mapvals.lightsource[k].type != NO_LIGHT)
{
source = &mapvals.lightsource[k];
switch (source->type)
{
case POINT_LIGHT:
fprintf (fp, "Type: Point\n");
break;
case DIRECTIONAL_LIGHT:
fprintf (fp, "Type: Directional\n");
break;
case SPOT_LIGHT:
fprintf (fp, "Type: Spot\n");
break;
default:
g_warning ("Unknown light type: %d",
mapvals.lightsource[k].type);
continue;
}
fprintf (fp, "Position: %s %s %s\n",
g_ascii_dtostr (buffer1, blen, source->position.x),
g_ascii_dtostr (buffer2, blen, source->position.y),
g_ascii_dtostr (buffer3, blen, source->position.z));
fprintf (fp, "Direction: %s %s %s\n",
g_ascii_dtostr (buffer1, blen, source->direction.x),
g_ascii_dtostr (buffer2, blen, source->direction.y),
g_ascii_dtostr (buffer3, blen, source->direction.z));
fprintf (fp, "Color: %s %s %s\n",
g_ascii_dtostr (buffer1, blen, source->color.r),
g_ascii_dtostr (buffer2, blen, source->color.g),
g_ascii_dtostr (buffer3, blen, source->color.b));
fprintf (fp, "Intensity: %s\n",
g_ascii_dtostr (buffer1, blen, source->intensity));
}
fclose (fp);
}
g_free (filename);
}
gtk_widget_destroy (GTK_WIDGET (chooser));
}
static void
load_lighting_preset (GtkWidget *widget,
gpointer data)
{
static GtkWidget *window = NULL;
if (! window)
{
window =
gtk_file_chooser_dialog_new (_("Load Lighting Preset"),
GTK_WINDOW (appwin),
GTK_FILE_CHOOSER_ACTION_OPEN,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Open"), GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (window), GTK_RESPONSE_OK);
pika_dialog_set_alternative_button_order (GTK_DIALOG (window),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed),
&window);
g_signal_connect (window, "response",
G_CALLBACK (load_preset_response),
NULL);
}
if (lighting_effects_path)
{
GList *list;
gchar *dir;
list = pika_path_parse (lighting_effects_path, 256, FALSE, NULL);
dir = pika_path_get_user_writable_dir (list);
pika_path_free (list);
if (! dir)
dir = g_strdup (pika_directory ());
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (window), dir);
g_free (dir);
}
else
{
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (window),
g_get_tmp_dir ());
}
gtk_window_present (GTK_WINDOW (window));
}
static void
load_preset_response (GtkFileChooser *chooser,
gint response_id,
gpointer data)
{
FILE *fp;
gint num_lights;
gint k;
LightSettings *source;
gchar buffer1[G_ASCII_DTOSTR_BUF_SIZE];
gchar buffer2[G_ASCII_DTOSTR_BUF_SIZE];
gchar buffer3[G_ASCII_DTOSTR_BUF_SIZE];
gchar type_label[21];
gchar *endptr;
gchar fmt_str[32];
if (response_id == GTK_RESPONSE_OK)
{
gchar *filename = gtk_file_chooser_get_filename (chooser);
fp = g_fopen (filename, "rb");
if (!fp)
{
g_message (_("Could not open '%s' for reading: %s"),
filename, g_strerror (errno));
}
else
{
fscanf (fp, "Number of lights: %d", &num_lights);
/* initialize lights to off */
for (k = 0; k < NUM_LIGHTS; k++)
mapvals.lightsource[k].type = NO_LIGHT;
for (k = 0; k < num_lights; k++)
{
source = &mapvals.lightsource[k];
fscanf (fp, " Type: %20s", type_label);
if (!strcmp (type_label, "Point"))
source->type = POINT_LIGHT;
else if (!strcmp (type_label, "Directional"))
source->type = DIRECTIONAL_LIGHT;
else if (!strcmp (type_label, "Spot"))
source->type = SPOT_LIGHT;
else
{
g_warning ("Unknown light type: %s", type_label);
fclose (fp);
return;
}
snprintf (fmt_str, sizeof (fmt_str),
" Position: %%%" G_GSIZE_FORMAT "s %%%" G_GSIZE_FORMAT "s %%%" G_GSIZE_FORMAT "s",
sizeof (buffer1) - 1,
sizeof (buffer2) - 1,
sizeof (buffer3) - 1);
fscanf (fp, fmt_str, buffer1, buffer2, buffer3);
source->position.x = g_ascii_strtod (buffer1, &endptr);
source->position.y = g_ascii_strtod (buffer2, &endptr);
source->position.z = g_ascii_strtod (buffer3, &endptr);
snprintf (fmt_str, sizeof (fmt_str),
" Direction: %%%" G_GSIZE_FORMAT "s %%%" G_GSIZE_FORMAT "s %%%" G_GSIZE_FORMAT "s",
sizeof (buffer1) - 1,
sizeof (buffer2) - 1,
sizeof (buffer3) - 1);
fscanf (fp, fmt_str, buffer1, buffer2, buffer3);
source->direction.x = g_ascii_strtod (buffer1, &endptr);
source->direction.y = g_ascii_strtod (buffer2, &endptr);
source->direction.z = g_ascii_strtod (buffer3, &endptr);
snprintf (fmt_str, sizeof (fmt_str),
" Color: %%%" G_GSIZE_FORMAT "s %%%" G_GSIZE_FORMAT "s %%%" G_GSIZE_FORMAT "s",
sizeof (buffer1) - 1,
sizeof (buffer2) - 1,
sizeof (buffer3) - 1);
fscanf (fp, fmt_str, buffer1, buffer2, buffer3);
source->color.r = g_ascii_strtod (buffer1, &endptr);
source->color.g = g_ascii_strtod (buffer2, &endptr);
source->color.b = g_ascii_strtod (buffer3, &endptr);
source->color.a = 1.0;
snprintf (fmt_str, sizeof (fmt_str),
" Intensity: %%%" G_GSIZE_FORMAT "s",
sizeof (buffer1) - 1);
fscanf (fp, fmt_str, buffer1);
source->intensity = g_ascii_strtod (buffer1, &endptr);
}
fclose (fp);
}
g_free (filename);
}
gtk_widget_destroy (GTK_WIDGET (chooser));
interactive_preview_callback (GTK_WIDGET (chooser));
}
static void
2023-10-30 23:55:30 +01:00
light_source_changed (GtkWidget *widget,
gpointer data)
2023-09-26 00:35:21 +02:00
{
2023-10-30 23:55:30 +01:00
gint light_source;
gboolean isolate = FALSE;
PikaProcedureConfig *config = (PikaProcedureConfig *) data;
2023-09-26 00:35:21 +02:00
2023-10-30 23:55:30 +01:00
light_source = pika_procedure_config_get_choice_id (config, "which_light") + 1;
g_object_get (config,
"isolate", &isolate,
NULL);
2023-09-26 00:35:21 +02:00
2023-10-30 23:55:30 +01:00
for (gint i = 1; i <= 6; i++)
2023-09-26 00:35:21 +02:00
{
2023-10-30 23:55:30 +01:00
GtkWidget *hbox;
gchar *temp_box;
temp_box = g_strdup_printf ("light-hbox-%d", i);
hbox = pika_procedure_dialog_get_widget (PIKA_PROCEDURE_DIALOG (appwin),
temp_box, G_TYPE_NONE);
g_free (temp_box);
if (i == light_source)
gtk_widget_set_visible (hbox, TRUE);
else
gtk_widget_set_visible (hbox, FALSE);
if (isolate)
2023-09-26 00:35:21 +02:00
{
2023-10-30 23:55:30 +01:00
if (i == light_source)
mapvals.lightsource[i - 1].active = TRUE;
else
mapvals.lightsource[i - 1].active = FALSE;
2023-09-26 00:35:21 +02:00
}
}
2023-10-30 23:55:30 +01:00
mapvals.light_selected = pika_procedure_config_get_choice_id (config, "which-light");
apply_settings (config);
if (previewarea != NULL && GTK_IS_WIDGET (previewarea))
update_preview (config);
2023-09-26 00:35:21 +02:00
}
static void
2023-10-30 23:55:30 +01:00
isolate_selected_light (PikaProcedureConfig *config)
2023-09-26 00:35:21 +02:00
{
2023-10-30 23:55:30 +01:00
gint k;
gboolean isolate;
2023-09-26 00:35:21 +02:00
2023-10-30 23:55:30 +01:00
g_object_get (config,
"isolate", &isolate,
NULL);
2023-09-26 00:35:21 +02:00
2023-10-30 23:55:30 +01:00
if (isolate)
{
2023-09-26 00:35:21 +02:00
for (k = 0; k < NUM_LIGHTS; k++)
2023-10-30 23:55:30 +01:00
if (k == (mapvals.light_selected))
2023-09-26 00:35:21 +02:00
mapvals.lightsource[k].active = TRUE;
else
mapvals.lightsource[k].active = FALSE;
}
else
{
for (k = 0; k < NUM_LIGHTS; k++)
mapvals.lightsource[k].active = TRUE;
}
}