summaryrefslogtreecommitdiffstats
path: root/plug-ins/lighting/lighting-ui.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--plug-ins/lighting/lighting-ui.c1557
1 files changed, 1557 insertions, 0 deletions
diff --git a/plug-ins/lighting/lighting-ui.c b/plug-ins/lighting/lighting-ui.c
new file mode 100644
index 0000000..86b4e12
--- /dev/null
+++ b/plug-ins/lighting/lighting-ui.c
@@ -0,0 +1,1557 @@
+/* Lighting Effects - A plug-in for GIMP
+ *
+ * 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 <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "lighting-ui.h"
+#include "lighting-main.h"
+#include "lighting-image.h"
+#include "lighting-apply.h"
+#include "lighting-preview.h"
+#include "lighting-stock.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+
+extern LightingValues mapvals;
+
+static GtkWidget *appwin = NULL;
+static GtkNotebook *options_note_book = 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 GtkWidget *colorbutton;
+static GtkWidget *light_type_combo;
+static GtkWidget *lightselect_combo;
+static GtkWidget *spin_intensity;
+static GtkWidget *isolate_button;
+static gchar *lighting_effects_path = NULL;
+
+static void create_main_notebook (GtkWidget *container);
+
+static void toggle_update (GtkWidget *widget,
+ gpointer data);
+
+static void distance_update (GtkAdjustment *adj,
+ gpointer data);
+
+static gboolean bumpmap_constrain (gint32 image_id,
+ gint32 drawable_id,
+ gpointer data);
+static gboolean envmap_constrain (gint32 image_id,
+ gint32 drawable_id,
+ gpointer data);
+static void envmap_combo_callback (GtkWidget *widget,
+ gpointer data);
+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 lightselect_callback (GimpIntComboBox *combo,
+ gpointer data);
+static void apply_settings (GtkWidget *widget,
+ gpointer data);
+static void isolate_selected_light (GtkWidget *widget,
+ gpointer data);
+
+static GtkWidget * spin_button_new (GtkAdjustment **adjustment, /* return value */
+ gdouble value,
+ gdouble lower,
+ gdouble upper,
+ gdouble step_increment,
+ gdouble page_increment,
+ gdouble page_size,
+ gdouble climb_rate,
+ guint digits);
+
+/**********************/
+/* Std. toggle update */
+/**********************/
+
+static void
+toggle_update (GtkWidget *widget,
+ gpointer data)
+{
+ gimp_toggle_button_update (widget, data);
+
+ preview_compute ();
+ gtk_widget_queue_draw (previewarea);
+}
+
+
+static void
+distance_update (GtkAdjustment *adj,
+ gpointer data)
+{
+ mapvals.viewpoint.z = gtk_adjustment_get_value (adj);
+
+ preview_compute ();
+ gtk_widget_queue_draw (previewarea);
+}
+
+
+/*****************************************/
+/* Main window light type menu callback. */
+/*****************************************/
+
+static void
+apply_settings (GtkWidget *widget,
+ gpointer data)
+{
+ gint valid;
+ gint type;
+ gint k = mapvals.light_selected;
+
+ if (mapvals.update_enabled)
+ {
+ valid = gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (light_type_combo),
+ &type);
+ if (valid)
+ mapvals.lightsource[k].type = type;
+
+ gimp_color_button_get_color (GIMP_COLOR_BUTTON (colorbutton),
+ &mapvals.lightsource[k].color);
+
+ mapvals.lightsource[k].position.x
+ = gtk_spin_button_get_value (GTK_SPIN_BUTTON(spin_pos_x));
+ mapvals.lightsource[k].position.y
+ = gtk_spin_button_get_value (GTK_SPIN_BUTTON(spin_pos_y));
+ mapvals.lightsource[k].position.z
+ = gtk_spin_button_get_value (GTK_SPIN_BUTTON(spin_pos_z));
+
+ mapvals.lightsource[k].direction.x
+ = gtk_spin_button_get_value (GTK_SPIN_BUTTON(spin_dir_x));
+ mapvals.lightsource[k].direction.y
+ = gtk_spin_button_get_value (GTK_SPIN_BUTTON(spin_dir_y));
+ mapvals.lightsource[k].direction.z
+ = gtk_spin_button_get_value (GTK_SPIN_BUTTON(spin_dir_z));
+
+ mapvals.lightsource[k].intensity
+ = gtk_spin_button_get_value (GTK_SPIN_BUTTON(spin_intensity));
+
+ interactive_preview_callback(NULL);
+ }
+
+ if (widget == light_type_combo)
+ {
+ switch (mapvals.lightsource[k].type)
+ {
+ case NO_LIGHT:
+ gtk_widget_set_sensitive (spin_pos_x, FALSE);
+ gtk_widget_set_sensitive (spin_pos_y, FALSE);
+ gtk_widget_set_sensitive (spin_pos_z, FALSE);
+ gtk_widget_set_sensitive (spin_dir_x, FALSE);
+ gtk_widget_set_sensitive (spin_dir_y, FALSE);
+ gtk_widget_set_sensitive (spin_dir_z, FALSE);
+ break;
+ case POINT_LIGHT:
+ gtk_widget_set_sensitive (spin_pos_x, TRUE);
+ gtk_widget_set_sensitive (spin_pos_y, TRUE);
+ gtk_widget_set_sensitive (spin_pos_z, TRUE);
+ gtk_widget_set_sensitive (spin_dir_x, FALSE);
+ gtk_widget_set_sensitive (spin_dir_y, FALSE);
+ gtk_widget_set_sensitive (spin_dir_z, FALSE);
+ break;
+ case DIRECTIONAL_LIGHT:
+ gtk_widget_set_sensitive (spin_pos_x, FALSE);
+ gtk_widget_set_sensitive (spin_pos_y, FALSE);
+ gtk_widget_set_sensitive (spin_pos_z, FALSE);
+ gtk_widget_set_sensitive (spin_dir_x, TRUE);
+ gtk_widget_set_sensitive (spin_dir_y, TRUE);
+ gtk_widget_set_sensitive (spin_dir_z, TRUE);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void
+mapmenu2_callback (GtkWidget *widget,
+ gpointer data)
+{
+ gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget), (gint *) data);
+
+ preview_compute ();
+ gtk_widget_queue_draw (previewarea);
+}
+
+/******************************************/
+/* Main window "Preview!" button callback */
+/******************************************/
+
+static void
+preview_callback (GtkWidget *widget)
+{
+ preview_compute ();
+ gtk_widget_queue_draw (previewarea);
+}
+
+
+
+
+/*********************************************/
+/* Main window "-" (zoom in) button callback */
+/*********************************************/
+/*
+static void
+zoomout_callback (GtkWidget *widget)
+{
+ mapvals.preview_zoom_factor *= 0.5;
+ draw_preview_image (TRUE);
+}
+*/
+/*********************************************/
+/* Main window "+" (zoom out) button callback */
+/*********************************************/
+/*
+static void
+zoomin_callback (GtkWidget *widget)
+{
+ mapvals.preview_zoom_factor *= 2.0;
+ draw_preview_image (TRUE);
+}
+*/
+/**********************************************/
+/* Main window "Apply" button callback. */
+/* Render to GIMP image, close down and exit. */
+/**********************************************/
+
+static gint
+bumpmap_constrain (gint32 image_id,
+ gint32 drawable_id,
+ gpointer data)
+{
+ return ((gimp_drawable_width (drawable_id) ==
+ gimp_drawable_width (mapvals.drawable_id)) &&
+ (gimp_drawable_height (drawable_id) ==
+ gimp_drawable_height (mapvals.drawable_id)));
+}
+
+static gint
+envmap_constrain (gint32 image_id,
+ gint32 drawable_id,
+ gpointer data)
+{
+ return (!gimp_drawable_is_gray (drawable_id) &&
+ !gimp_drawable_has_alpha (drawable_id));
+}
+
+static void
+envmap_combo_callback (GtkWidget *widget,
+ gpointer data)
+{
+ gimp_int_combo_box_get_active (GIMP_INT_COMBO_BOX (widget),
+ &mapvals.envmap_id);
+
+ env_width = gimp_drawable_width (mapvals.envmap_id);
+ env_height = gimp_drawable_height (mapvals.envmap_id);
+}
+
+/***********************/
+/* Dialog constructors */
+/***********************/
+
+static GtkWidget *
+create_options_page (void)
+{
+ GtkWidget *page;
+ GtkWidget *frame;
+ GtkWidget *vbox;
+ GtkWidget *toggle;
+ GtkWidget *table;
+ GtkAdjustment *adj;
+
+ page = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (page), 12);
+
+ /* General options */
+
+ frame = gimp_frame_new (_("General Options"));
+ gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_container_add (GTK_CONTAINER (frame), vbox);
+ gtk_widget_show (vbox);
+
+ toggle = gtk_check_button_new_with_mnemonic (_("T_ransparent background"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
+ mapvals.transparent_background);
+ gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (toggle_update),
+ &mapvals.transparent_background);
+ gtk_widget_show (toggle);
+
+ gimp_help_set_help_data (toggle,
+ _("Make destination image transparent where bump "
+ "height is zero"),NULL);
+
+ toggle = gtk_check_button_new_with_mnemonic (_("Cre_ate new image"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
+ mapvals.create_new_image);
+ gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (gimp_toggle_button_update),
+ &mapvals.create_new_image);
+ gtk_widget_show (toggle);
+
+ gimp_help_set_help_data (toggle,
+ _("Create a new image when applying filter"), NULL);
+
+ toggle = gtk_check_button_new_with_mnemonic (_("High _quality preview"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
+ mapvals.previewquality);
+ gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (toggle_update),
+ &mapvals.previewquality);
+ gtk_widget_show (toggle);
+
+ gimp_help_set_help_data (toggle,
+ _("Enable/disable high quality preview"), NULL);
+
+ table = gtk_table_new (1, 3, FALSE);
+ gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 12);
+ gtk_widget_show (table);
+
+ adj = (GtkAdjustment *)
+ gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
+ _("Distance:"), 100, 6,
+ mapvals.viewpoint.z,
+ 0.0, 2.0, 0.01, 0.05,
+ 3, TRUE, 0.0, 0.0,
+ "Distance of observer from surface",
+ "plug-in-lighting");
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (distance_update),
+ NULL);
+
+ gtk_widget_show (page);
+
+ return page;
+}
+
+/******************************/
+/* Create light settings page */
+/******************************/
+
+static GtkWidget *
+create_light_page (void)
+{
+ GtkWidget *page;
+ GtkWidget *frame;
+ GtkWidget *table;
+ GtkWidget *button;
+ GtkAdjustment *adj;
+ GtkWidget *label;
+ gint k = mapvals.light_selected;
+
+ page = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (page), 12);
+
+ frame = gimp_frame_new (_("Light Settings"));
+ gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ table = gtk_table_new (8, 8, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_container_add (GTK_CONTAINER (frame), table);
+ gtk_widget_show (table);
+
+ gtk_table_set_col_spacing (GTK_TABLE (table), 1, 12);
+ gtk_table_set_col_spacing (GTK_TABLE (table), 3, 12);
+
+ lightselect_combo = gimp_int_combo_box_new (_("Light 1"), 0,
+ _("Light 2"), 1,
+ _("Light 3"), 2,
+ _("Light 4"), 3,
+ _("Light 5"), 4,
+ _("Light 6"), 5,
+ NULL);
+ gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (lightselect_combo), k);
+ gtk_table_attach_defaults (GTK_TABLE (table), lightselect_combo, 0, 2, 0, 1);
+ g_signal_connect (lightselect_combo, "changed",
+ G_CALLBACK (lightselect_callback), NULL);
+ gtk_widget_show (lightselect_combo);
+
+ /* row labels */
+ label = gtk_label_new (_("Type:"));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 1, 2);
+ gtk_widget_show (label);
+
+ label = gtk_label_new (_("Color:"));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 2, 3);
+ gtk_widget_show (label);
+
+ light_type_combo =
+ gimp_int_combo_box_new (C_("light-source", "None"), NO_LIGHT,
+ _("Directional"), DIRECTIONAL_LIGHT,
+ _("Point"), POINT_LIGHT,
+ /* _("Spot"), SPOT_LIGHT, */
+ NULL);
+ gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (light_type_combo),
+ mapvals.lightsource[k].type);
+ gtk_table_attach_defaults (GTK_TABLE (table), light_type_combo,
+ 1, 2, 1, 2);
+ gtk_widget_show (light_type_combo);
+
+ g_signal_connect (light_type_combo, "changed",
+ G_CALLBACK (apply_settings),
+ NULL);
+
+ gimp_help_set_help_data (light_type_combo,
+ _("Type of light source to apply"), NULL);
+
+ colorbutton = gimp_color_button_new (_("Select lightsource color"),
+ 64, 16,
+ &mapvals.lightsource[k].color,
+ GIMP_COLOR_AREA_FLAT);
+ gimp_color_button_set_update (GIMP_COLOR_BUTTON (colorbutton), TRUE);
+ gtk_widget_show (colorbutton);
+ gtk_table_attach_defaults (GTK_TABLE (table),
+ colorbutton, 1, 2, 2, 3);
+
+ g_signal_connect (colorbutton, "color-changed",
+ G_CALLBACK (apply_settings),
+ NULL);
+
+ gimp_help_set_help_data (colorbutton,
+ _("Set light source color"), NULL);
+
+
+ spin_intensity = spin_button_new (&adj,
+ mapvals.lightsource[k].intensity,
+ 0.0, 100.0,
+ 0.01, 0.1, 0.0, 0.0, 2);
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
+ _("_Intensity:"), 0.0, 0.5,
+ spin_intensity, 1, TRUE);
+
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (apply_settings),
+ NULL);
+
+ gimp_help_set_help_data (spin_intensity,
+ _("Light intensity"), NULL);
+
+
+ label = gtk_label_new (_("Position"));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ gtk_table_attach_defaults (GTK_TABLE (table), label, 3, 4, 0, 1);
+ gtk_widget_show (label);
+
+ spin_pos_x = spin_button_new (&adj,
+ mapvals.lightsource[k].position.x,
+ -100.0, 100.0,
+ 0.1, 1.0, 0.0, 0.0, 2);
+ gimp_table_attach_aligned (GTK_TABLE (table), 2, 1,
+ _("_X:"), 0.0, 0.5,
+ spin_pos_x, 1, TRUE);
+
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (apply_settings),
+ NULL);
+
+ gimp_help_set_help_data (spin_pos_x,
+ _("Light source X position in XYZ space"), NULL);
+
+ spin_pos_y = spin_button_new (&adj,
+ mapvals.lightsource[k].position.y,
+ -100.0, 100.0,
+ 0.1, 1.0, 0.0, 0.0, 2);
+ gimp_table_attach_aligned (GTK_TABLE (table), 2, 2,
+ _("_Y:"), 0.0, 0.5,
+ spin_pos_y, 1, TRUE);
+
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (apply_settings),
+ NULL);
+
+ gimp_help_set_help_data (spin_pos_y,
+ _("Light source Y position in XYZ space"), NULL);
+
+ spin_pos_z = spin_button_new (&adj,
+ mapvals.lightsource[k].position.z,
+ -100.0, 100.0,
+ 0.1, 1.0, 0.0, 0.0, 2);
+ gimp_table_attach_aligned (GTK_TABLE (table), 2, 3,
+ _("_Z:"), 0.0, 0.5,
+ spin_pos_z, 1, TRUE);
+
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (apply_settings),
+ NULL);
+
+ gimp_help_set_help_data (spin_pos_z,
+ _("Light source Z position in XYZ space"), NULL);
+
+
+ label = gtk_label_new (_("Direction"));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ gtk_table_attach_defaults (GTK_TABLE (table), label, 5, 6, 0, 1);
+ gtk_widget_show (label);
+
+ spin_dir_x = spin_button_new (&adj,
+ mapvals.lightsource[k].direction.x,
+ -100.0, 100.0, 0.1, 1.0, 0.0, 0.0, 2);
+ gimp_table_attach_aligned (GTK_TABLE (table), 4, 1,
+ _("X:"), 0.0, 0.5,
+ spin_dir_x, 1, TRUE);
+
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (apply_settings),
+ NULL);
+
+ gimp_help_set_help_data (spin_dir_x,
+ _("Light source X direction in XYZ space"), NULL);
+
+ spin_dir_y = spin_button_new (&adj,
+ mapvals.lightsource[k].direction.y,
+ -100.0, 100.0, 0.1, 1.0, 0.0, 0.0, 2);
+ gimp_table_attach_aligned (GTK_TABLE (table), 4, 2,
+ _("Y:"), 0.0, 0.5,
+ spin_dir_y, 1, TRUE);
+
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (apply_settings),
+ NULL);
+
+ gimp_help_set_help_data (spin_dir_y,
+ _("Light source Y direction in XYZ space"), NULL);
+
+ spin_dir_z = spin_button_new (&adj,
+ mapvals.lightsource[k].direction.z,
+ -100.0, 100.0, 0.1, 1.0, 0.0, 0.0, 2);
+ gimp_table_attach_aligned (GTK_TABLE (table), 4, 3,
+ _("Z:"), 0.0, 0.5,
+ spin_dir_z, 1, TRUE);
+
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (apply_settings),
+ NULL);
+
+ gimp_help_set_help_data (spin_dir_z,
+ _("Light source Z direction in XYZ space"),
+ NULL);
+
+ isolate_button = gtk_check_button_new_with_mnemonic (_("I_solate"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (isolate_button),
+ mapvals.light_isolated);
+ g_signal_connect (isolate_button, "toggled",
+ G_CALLBACK (isolate_selected_light),
+ NULL);
+ gtk_table_attach_defaults (GTK_TABLE (table), isolate_button, 0, 1, 5, 6);
+ gtk_widget_show (isolate_button);
+
+ label = gtk_label_new (_("Lighting preset:"));
+ gtk_label_set_xalign (GTK_LABEL (label), 1.0);
+ gtk_table_set_row_spacing (GTK_TABLE (table), 5, 12);
+ gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 2, 6, 7);
+ gtk_widget_show (label);
+
+ button = gtk_button_new_with_mnemonic (_("_Save"));
+ gtk_table_attach_defaults (GTK_TABLE (table), button, 2, 4, 6, 7);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (save_lighting_preset),
+ NULL);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_with_mnemonic (_("_Open"));
+ gtk_table_attach_defaults (GTK_TABLE (table), button, 4, 6, 6, 7);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (load_lighting_preset),
+ NULL);
+ gtk_widget_show (button);
+
+ gtk_widget_show (page);
+
+ return page;
+}
+
+/*********************************/
+/* Create material settings page */
+/*********************************/
+
+static GtkWidget *
+create_material_page (void)
+{
+ GtkSizeGroup *group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ GtkWidget *page;
+ GtkWidget *frame;
+ GtkWidget *table;
+ GtkWidget *label;
+ GtkWidget *hbox;
+ GtkWidget *spinbutton;
+ GtkWidget *image;
+ GtkWidget *button;
+ GtkAdjustment *adj;
+
+ page = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (page), 12);
+
+ frame = gimp_frame_new (_("Material Properties"));
+ gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_container_add (GTK_CONTAINER (frame), hbox);
+ gtk_widget_show (hbox);
+
+ table = gtk_table_new (5, 4, FALSE);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
+ gtk_widget_show (table);
+
+ /* Ambient intensity */
+
+ image = gtk_image_new_from_stock (STOCK_INTENSITY_AMBIENT_LOW,
+ GTK_ICON_SIZE_BUTTON);
+ label = gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
+ _("_Glowing:"), 0.0, 0.5,
+ image, 1, FALSE);
+ gtk_size_group_add_widget (group, label);
+
+ spinbutton = spin_button_new (&adj, mapvals.material.ambient_int,
+ 0, G_MAXFLOAT, 0.01, 0.1, 0.0, 0.0, 2);
+ gtk_table_attach (GTK_TABLE (table), spinbutton, 2, 3, 0, 1,
+ GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_widget_show (spinbutton);
+
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (gimp_double_adjustment_update),
+ &mapvals.material.ambient_int);
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (interactive_preview_callback),
+ NULL);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
+ gimp_help_set_help_data (spinbutton,
+ _("Amount of original color to show where no "
+ "direct light falls"), NULL);
+
+ image = gtk_image_new_from_stock (STOCK_INTENSITY_AMBIENT_HIGH,
+ GTK_ICON_SIZE_BUTTON);
+ gtk_table_attach (GTK_TABLE (table), image, 3, 4, 0, 1,
+ GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_widget_show (image);
+
+ /* Diffuse intensity */
+
+ image = gtk_image_new_from_stock (STOCK_INTENSITY_DIFFUSE_LOW,
+ GTK_ICON_SIZE_BUTTON);
+ label = gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
+ _("_Bright:"), 0.0, 0.5,
+ image, 1, FALSE);
+ gtk_size_group_add_widget (group, label);
+
+ spinbutton = spin_button_new (&adj, mapvals.material.diffuse_int,
+ 0, G_MAXFLOAT, 0.01, 0.1, 0.0, 0.0, 2);
+ gtk_table_attach (GTK_TABLE (table), spinbutton, 2, 3, 1, 2,
+ GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_widget_show (spinbutton);
+
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (gimp_double_adjustment_update),
+ &mapvals.material.diffuse_int);
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (interactive_preview_callback),
+ NULL);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
+ gimp_help_set_help_data (spinbutton,
+ _("Intensity of original color when lit by a light "
+ "source"), NULL);
+
+ image = gtk_image_new_from_stock (STOCK_INTENSITY_DIFFUSE_HIGH,
+ GTK_ICON_SIZE_BUTTON);
+ gtk_table_attach (GTK_TABLE (table), image, 3, 4, 1, 2,
+ GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_widget_show (image);
+
+ /* Specular reflection */
+
+ image = gtk_image_new_from_stock (STOCK_REFLECTIVITY_SPECULAR_LOW,
+ GTK_ICON_SIZE_BUTTON);
+ label = gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
+ _("_Shiny:"), 0.0, 0.5,
+ image, 1, FALSE);
+ gtk_size_group_add_widget (group, label);
+
+ spinbutton = spin_button_new (&adj, mapvals.material.specular_ref,
+ 0, G_MAXFLOAT, 0.01, 0.1, 0.0, 0.0, 2);
+ gtk_table_attach (GTK_TABLE (table), spinbutton, 2, 3, 2, 3,
+ GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_widget_show (spinbutton);
+
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (gimp_double_adjustment_update),
+ &mapvals.material.specular_ref);
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (interactive_preview_callback),
+ NULL);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
+ gimp_help_set_help_data (spinbutton,
+ _("Controls how intense the highlights will be"),
+ NULL);
+
+ image = gtk_image_new_from_stock (STOCK_REFLECTIVITY_SPECULAR_HIGH,
+ GTK_ICON_SIZE_BUTTON);
+ gtk_table_attach (GTK_TABLE (table), image, 3, 4, 2, 3,
+ GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_widget_show (image);
+
+ /* Highlight */
+ image = gtk_image_new_from_stock (STOCK_REFLECTIVITY_HIGHLIGHT_LOW,
+ GTK_ICON_SIZE_BUTTON);
+ label = gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
+ _("_Polished:"), 0.0, 0.5,
+ image, 1, FALSE);
+ gtk_size_group_add_widget (group, label);
+
+ spinbutton = spin_button_new (&adj, mapvals.material.highlight,
+ 0, G_MAXFLOAT, 0.01, 0.1, 0.0, 0.0, 2);
+ gtk_table_attach (GTK_TABLE (table), spinbutton, 2, 3, 3, 4,
+ GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_widget_show (spinbutton);
+
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (gimp_double_adjustment_update),
+ &mapvals.material.highlight);
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (interactive_preview_callback),
+ NULL);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
+ gimp_help_set_help_data (spinbutton,
+ _("Higher values makes the highlights more focused"),
+ NULL);
+
+ image = gtk_image_new_from_stock (STOCK_REFLECTIVITY_HIGHLIGHT_HIGH,
+ GTK_ICON_SIZE_BUTTON);
+ gtk_table_attach (GTK_TABLE (table), image, 3, 4, 3, 4,
+ GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_widget_show (image);
+
+ /* Metallic */
+ button = gtk_check_button_new_with_mnemonic (_("_Metallic"));
+ gtk_table_attach (GTK_TABLE (table), button, 0, 3, 4, 5,
+ GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_widget_show (button);
+
+ g_signal_connect (button, "toggled",
+ G_CALLBACK (gimp_toggle_button_update),
+ &mapvals.material.metallic);
+ g_signal_connect (button, "toggled",
+ G_CALLBACK (interactive_preview_callback),
+ NULL);
+
+ gtk_widget_show (page);
+
+ return page;
+}
+
+/* Create Bump mapping page */
+
+static GtkWidget *
+create_bump_page (void)
+{
+ GtkWidget *page;
+ GtkWidget *toggle;
+ GtkWidget *frame;
+ GtkWidget *table;
+ GtkWidget *combo;
+ GtkWidget *spinbutton;
+ GtkAdjustment *adj;
+
+ page = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (page), 12);
+
+ frame = gimp_frame_new (NULL);
+ gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ toggle = gtk_check_button_new_with_mnemonic (_("E_nable bump mapping"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
+ mapvals.bump_mapped);
+ gtk_frame_set_label_widget (GTK_FRAME (frame), toggle);
+ gtk_widget_show (toggle);
+
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (gimp_toggle_button_update),
+ &mapvals.bump_mapped);
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (interactive_preview_callback),
+ NULL);
+
+ gimp_help_set_help_data (toggle,
+ _("Enable/disable bump-mapping (image depth)"),
+ NULL);
+
+ table = gtk_table_new (6, 2, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_container_add (GTK_CONTAINER (frame), table);
+ gtk_widget_show (table);
+
+ g_object_bind_property (toggle, "active",
+ table, "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ combo = gimp_drawable_combo_box_new (bumpmap_constrain, NULL);
+ gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), mapvals.bumpmap_id,
+ G_CALLBACK (gimp_int_combo_box_get_active),
+ &mapvals.bumpmap_id);
+
+ g_signal_connect (combo, "changed",
+ G_CALLBACK (mapmenu2_callback),
+ &mapvals.bumpmap_id);
+
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
+ _("Bumpm_ap image:"), 0.0, 0.5,
+ combo, 1, FALSE);
+
+ combo = gimp_int_combo_box_new (_("Linear"), LINEAR_MAP,
+ _("Logarithmic"), LOGARITHMIC_MAP,
+ _("Sinusoidal"), SINUSOIDAL_MAP,
+ _("Spherical"), SPHERICAL_MAP,
+ NULL);
+ gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (combo),
+ mapvals.bumpmaptype);
+
+ g_signal_connect (combo, "changed",
+ G_CALLBACK (mapmenu2_callback),
+ &mapvals.bumpmaptype);
+
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
+ _("Cu_rve:"), 0.0, 0.5, combo, 1, FALSE);
+
+ spinbutton = spin_button_new (&adj, mapvals.bumpmax,
+ 0, G_MAXFLOAT, 0.01, 0.1, 0.0, 0.0, 2);
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
+ _("Ma_ximum height:"), 0.0, 0.5,
+ spinbutton, 1, TRUE);
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (gimp_double_adjustment_update),
+ &mapvals.bumpmax);
+ g_signal_connect (adj, "value-changed",
+ G_CALLBACK (interactive_preview_callback),
+ NULL);
+
+ gimp_help_set_help_data (spinbutton,
+ _("Maximum height for bumps"),
+ NULL);
+
+ gtk_widget_show (page);
+
+ return page;
+}
+
+static GtkWidget *
+create_environment_page (void)
+{
+ GtkWidget *page;
+ GtkWidget *toggle;
+ GtkWidget *table;
+ GtkWidget *frame;
+ GtkWidget *combo;
+
+ page = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (page), 12);
+
+ frame = gimp_frame_new (NULL);
+ gtk_box_pack_start (GTK_BOX (page), frame, FALSE, FALSE, 0);
+ gtk_widget_show (frame);
+
+ toggle = gtk_check_button_new_with_mnemonic (_("E_nable environment mapping"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
+ mapvals.env_mapped);
+ gtk_frame_set_label_widget (GTK_FRAME (frame), toggle);
+ gtk_widget_show (toggle);
+
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (gimp_toggle_button_update),
+ &mapvals.env_mapped);
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (interactive_preview_callback),
+ NULL);
+
+ gimp_help_set_help_data (toggle,
+ _("Enable/disable environment-mapping (reflection)"),
+ NULL);
+
+ table = gtk_table_new (3, 2, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_container_add (GTK_CONTAINER (frame), table);
+ gtk_widget_show (table);
+
+ g_object_bind_property (toggle, "active",
+ table, "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ combo = gimp_drawable_combo_box_new (envmap_constrain, NULL);
+ gimp_int_combo_box_connect (GIMP_INT_COMBO_BOX (combo), mapvals.envmap_id,
+ G_CALLBACK (envmap_combo_callback),
+ NULL);
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
+ _("En_vironment image:"), 0.0, 0.5,
+ combo, 1, FALSE);
+
+ gimp_help_set_help_data (combo, _("Environment image to use"), NULL);
+
+ gtk_widget_show (page);
+
+ return page;
+}
+
+/*****************************/
+/* Create notebook and pages */
+/*****************************/
+
+static void
+create_main_notebook (GtkWidget *container)
+{
+ GtkWidget *page;
+
+ options_note_book = GTK_NOTEBOOK (gtk_notebook_new ());
+ gtk_container_add (GTK_CONTAINER (container),
+ GTK_WIDGET (options_note_book));
+
+ page = create_options_page ();
+ gtk_notebook_append_page (options_note_book, page,
+ gtk_label_new_with_mnemonic (_("Op_tions")));
+
+ page = create_light_page ();
+ gtk_notebook_append_page (options_note_book, page,
+ gtk_label_new_with_mnemonic (_("_Light")));
+
+ page = create_material_page ();
+ gtk_notebook_append_page (options_note_book, page,
+ gtk_label_new_with_mnemonic (_("_Material")));
+
+ page = create_bump_page ();
+ gtk_notebook_append_page (options_note_book, page,
+ gtk_label_new_with_mnemonic (_("_Bump Map")));
+
+ page = create_environment_page ();
+ gtk_notebook_append_page (options_note_book, page,
+ gtk_label_new_with_mnemonic (_("_Environment Map")));
+
+ /*
+ if (mapvals.bump_mapped == TRUE)
+ {
+ bump_page = create_bump_page ();
+ bump_page_pos = g_list_length (options_note_book->children);
+ gtk_notebook_append_page (options_note_book, bump_page,
+ gtk_label_new (_("Bumpmap")));
+ }
+
+ if (mapvals.env_mapped == TRUE)
+ {
+ env_page = create_environment_page ();
+ env_page_pos = g_list_length (options_note_book->children);
+ gtk_notebook_append_page (options_note_book, env_page,
+ gtk_label_new (_("Environment")));
+ }
+ */
+ gtk_widget_show (GTK_WIDGET (options_note_book));
+}
+
+/********************************/
+/* Create and show main dialog. */
+/********************************/
+
+gboolean
+main_dialog (gint32 drawable_id)
+{
+ GtkWidget *main_hbox;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+ GtkWidget *frame;
+ GtkWidget *button;
+ GtkWidget *toggle;
+ gchar *path;
+ gboolean run = FALSE;
+
+ /*
+ GtkWidget *image;
+ */
+
+ gimp_ui_init (PLUG_IN_BINARY, FALSE);
+
+ path = gimp_gimprc_query ("lighting-effects-path");
+ if (path)
+ {
+ lighting_effects_path = g_filename_from_utf8 (path, -1, NULL, NULL, NULL);
+ g_free (path);
+ }
+
+ lighting_stock_init ();
+
+ appwin = gimp_dialog_new (_("Lighting Effects"), PLUG_IN_ROLE,
+ NULL, 0,
+ gimp_standard_help_func, PLUG_IN_PROC,
+
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("_OK"), GTK_RESPONSE_OK,
+
+ NULL);
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (appwin),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ gimp_window_set_transient (GTK_WINDOW (appwin));
+
+ main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 12);
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (appwin))),
+ main_hbox, FALSE, FALSE, 0);
+ gtk_widget_show (main_hbox);
+
+ /* Create the Preview */
+ /* ================== */
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_box_pack_start (GTK_BOX (main_hbox), vbox, FALSE, FALSE, 0);
+ gtk_widget_show (vbox);
+
+ /* 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, "expose-event",
+ G_CALLBACK (preview_expose),
+ 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);
+
+ gimp_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 (gimp_toggle_button_update),
+ &mapvals.interactive_preview);
+ g_signal_connect (toggle, "toggled",
+ G_CALLBACK (interactive_preview_callback),
+ NULL);
+
+ gtk_widget_show (toggle);
+
+ gimp_help_set_help_data (toggle,
+ _("Enable/disable real time preview of changes"),
+ NULL);
+
+ create_main_notebook (main_hbox);
+
+ 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);
+ gdk_cursor_unref (cursor);
+ }
+
+ if (image_setup (drawable_id, TRUE))
+ preview_compute ();
+
+ if (gimp_dialog_run (GIMP_DIALOG (appwin)) == GTK_RESPONSE_OK)
+ run = TRUE;
+
+ 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);
+ gtk_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 = gimp_path_parse (lighting_effects_path, 256, FALSE, NULL);
+ dir = gimp_path_get_user_writable_dir (list);
+ gimp_path_free (list);
+
+ if (! dir)
+ dir = g_strdup (gimp_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);
+ gtk_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 = gimp_path_parse (lighting_effects_path, 256, FALSE, NULL);
+ dir = gimp_path_get_user_writable_dir (list);
+ gimp_path_free (list);
+
+ if (! dir)
+ dir = g_strdup (gimp_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);
+
+ lightselect_callback (GIMP_INT_COMBO_BOX (lightselect_combo), NULL);
+ }
+
+ gtk_widget_destroy (GTK_WIDGET (chooser));
+ interactive_preview_callback (GTK_WIDGET (chooser));
+}
+
+
+static void
+lightselect_callback (GimpIntComboBox *combo,
+ gpointer data)
+{
+ gint valid;
+ gint j, k;
+
+ valid = gimp_int_combo_box_get_active (combo, &k);
+
+ if (valid)
+ {
+ mapvals.update_enabled = FALSE; /* prevent apply_settings() */
+
+ mapvals.light_selected = k;
+ gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (light_type_combo),
+ mapvals.lightsource[k].type);
+ gimp_color_button_set_color (GIMP_COLOR_BUTTON (colorbutton),
+ &mapvals.lightsource[k].color);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin_pos_x),
+ mapvals.lightsource[k].position.x);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin_pos_y),
+ mapvals.lightsource[k].position.y);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin_pos_z),
+ mapvals.lightsource[k].position.z);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin_dir_x),
+ mapvals.lightsource[k].direction.x);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin_dir_y),
+ mapvals.lightsource[k].direction.y);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin_dir_z),
+ mapvals.lightsource[k].direction.z);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin_intensity),
+ mapvals.lightsource[k].intensity);
+
+ mapvals.update_enabled = TRUE;
+
+ /* if we are isolating a light, need to switch */
+ if (mapvals.light_isolated)
+ {
+ for (j = 0; j < NUM_LIGHTS; j++)
+ if (j == mapvals.light_selected)
+ mapvals.lightsource[j].active = TRUE;
+ else
+ mapvals.lightsource[j].active = FALSE;
+ }
+
+ interactive_preview_callback (NULL);
+ }
+}
+
+static void
+isolate_selected_light (GtkWidget *widget,
+ gpointer data)
+{
+ gint k;
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
+ {
+ mapvals.light_isolated = TRUE;
+
+ for (k = 0; k < NUM_LIGHTS; k++)
+ if (k == mapvals.light_selected)
+ mapvals.lightsource[k].active = TRUE;
+ else
+ mapvals.lightsource[k].active = FALSE;
+ }
+ else
+ {
+ mapvals.light_isolated = FALSE;
+
+ for (k = 0; k < NUM_LIGHTS; k++)
+ mapvals.lightsource[k].active = TRUE;
+ }
+
+ interactive_preview_callback (NULL);
+}
+
+static GtkWidget *
+spin_button_new (GtkAdjustment **adjustment, /* return value */
+ gdouble value,
+ gdouble lower,
+ gdouble upper,
+ gdouble step_increment,
+ gdouble page_increment,
+ gdouble page_size,
+ gdouble climb_rate,
+ guint digits)
+{
+ GtkWidget *spinbutton;
+
+ *adjustment = (GtkAdjustment *)
+ gtk_adjustment_new (value, lower, upper,
+ step_increment, page_increment, 0);
+
+ spinbutton = gimp_spin_button_new (GTK_ADJUSTMENT (*adjustment),
+ climb_rate, digits);
+
+ gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
+
+ return spinbutton;
+}