/* ----------------------------------------------------------------------------- This source file is part of OGRE (Object-oriented Graphics Rendering Engine) For the latest info, see http://www.ogre3d.org/ Copyright (c) 2000-2006 Torus Knot Software Ltd Also see acknowledgements in Readme.html This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to http://www.gnu.org/copyleft/lesser.txt. You may alternatively use this source under the terms of a specific version of the OGRE Unrestricted License provided you have obtained such a license from Torus Knot Software Ltd. ----------------------------------------------------------------------------- */ #include "OgreConfigDialog.h" #include "OgreException.h" #include "OgreLogManager.h" #include namespace Ogre { /** Backdrop image. This is an arbitrary PNG file encoded into a C array. You can easily generate your own backdrop with the following python script: #!/usr/bin/python import sys pngstring=open(sys.argv[2], "rb").read() print "static uint8 %s[%i]={%s};" % (sys.argv[1],len(pngstring), ",".join([str(ord(x)) for x in pngstring])) Call this with $ bintoheader.py GLX_backdrop_data GLX_backdrop.png > GLX_backdrop.h */ #include "GLX_backdrop.h" /* * A GTK+2 dialog window, making it possible to configure OGRE * in a graphical way. It uses plain C gtk+ bindings since gtk-- is not * part of most standard distributions while gtk+ itself is present * in every Linux distribution I ever seen. */ bool _OgrePrivate __gtk_init_once () { static bool gtk_already_initialized = false; if (gtk_already_initialized) return true; gtk_already_initialized = true; // Initialize gtk+ int argc = 0; char **argv = NULL; // Avoid gtk calling setlocale() otherwise // scanf("%f") won't work on some locales etc. // Leave this on application developer's responsability. gtk_disable_setlocale (); return gtk_init_check (&argc, &argv); } ConfigDialog::ConfigDialog () { } void ConfigDialog::rendererChanged (GtkComboBox *widget, gpointer data) { ConfigDialog *This = static_cast (data); gchar *renderer = gtk_combo_box_get_active_text (widget); RenderSystemList *renderers = Root::getSingleton ().getAvailableRenderers (); for (RenderSystemList::iterator r = renderers->begin(); r != renderers->end (); r++) if (strcmp (renderer, (*r)->getName ().c_str ()) == 0) { This->mSelectedRenderSystem = *r; This->setupRendererParams (); } } void ConfigDialog::optionChanged (GtkComboBox *widget, gpointer data) { ConfigDialog *This = static_cast (data); GtkWidget *ro_label = static_cast ( g_object_get_data (G_OBJECT (widget), "renderer-option")); This->mSelectedRenderSystem->setConfigOption ( gtk_label_get_text (GTK_LABEL (ro_label)), gtk_combo_box_get_active_text (widget)); } static void remove_all_callback (GtkWidget *widget, gpointer data) { GtkWidget *container = static_cast (data); gtk_container_remove (GTK_CONTAINER (container), widget); } void ConfigDialog::setupRendererParams () { // Remove all existing child widgets gtk_container_forall (GTK_CONTAINER (mParamTable), remove_all_callback, mParamTable); ConfigOptionMap options = mSelectedRenderSystem->getConfigOptions (); // Resize the table to hold as many options as we have gtk_table_resize (GTK_TABLE (mParamTable), options.size (), 2); uint row = 0; for (ConfigOptionMap::iterator i = options.begin (); i != options.end (); i++, row++) { GtkWidget *ro_label = gtk_label_new (i->second.name.c_str ()); gtk_widget_show (ro_label); gtk_table_attach (GTK_TABLE (mParamTable), ro_label, 0, 1, row, row + 1, GtkAttachOptions (GTK_EXPAND | GTK_FILL), GtkAttachOptions (0), 5, 0); gtk_label_set_justify (GTK_LABEL (ro_label), GTK_JUSTIFY_RIGHT); gtk_misc_set_alignment (GTK_MISC (ro_label), 1, 0.5); GtkWidget *ro_cb = gtk_combo_box_new_text (); gtk_widget_show (ro_cb); gtk_table_attach (GTK_TABLE (mParamTable), ro_cb, 1, 2, row, row + 1, GtkAttachOptions (GTK_EXPAND | GTK_FILL), GtkAttachOptions (0), 5, 0); // Set up a link from the combobox to the label g_object_set_data (G_OBJECT (ro_cb), "renderer-option", ro_label); StringVector::iterator opt_it; uint idx = 0; for (opt_it = i->second.possibleValues.begin (); opt_it != i->second.possibleValues.end (); opt_it++, idx++) { gtk_combo_box_append_text (GTK_COMBO_BOX (ro_cb), (*opt_it).c_str ()); if (strcmp (i->second.currentValue.c_str (), (*opt_it).c_str ()) == 0) gtk_combo_box_set_active (GTK_COMBO_BOX (ro_cb), idx); } g_signal_connect (G_OBJECT (ro_cb), "changed", G_CALLBACK (optionChanged), this); } } static void backdrop_destructor (guchar *pixels, gpointer data) { free (pixels); } bool ConfigDialog::createWindow () { // Create the dialog window mDialog = gtk_dialog_new_with_buttons ( "OGRE Engine Setup", NULL, GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gtk_window_set_position (GTK_WINDOW (mDialog), GTK_WIN_POS_CENTER); gtk_window_set_resizable (GTK_WINDOW (mDialog), FALSE); gtk_widget_show (GTK_DIALOG (mDialog)->vbox); GtkWidget *vbox = gtk_vbox_new (FALSE, 5); gtk_widget_show (vbox); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (mDialog)->vbox), vbox, TRUE, TRUE, 0); // Unpack the image and create a GtkImage object from it try { static String imgType ("png"); Image img; MemoryDataStream *imgStream; DataStreamPtr imgStreamPtr; imgStream = new MemoryDataStream (GLX_backdrop_data, sizeof (GLX_backdrop_data), false); imgStreamPtr = DataStreamPtr (imgStream); img.load (imgStreamPtr, imgType); PixelBox src = img.getPixelBox (0, 0); size_t width = img.getWidth (); size_t height = img.getHeight (); // Convert and copy image -- must be allocated with malloc uint8 *data = (uint8 *)malloc (width * height * 4); // Keep in mind that PixelBox does not free the data - this is ok // as gtk takes pixel data ownership in gdk_pixbuf_new_from_data PixelBox dst (src, PF_A8B8G8R8, data); PixelUtil::bulkPixelConversion (src, dst); GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data ( (const guchar *)dst.data, GDK_COLORSPACE_RGB, true, 8, width, height, width * 4, backdrop_destructor, NULL); GtkWidget *ogre_logo = gtk_image_new_from_pixbuf (pixbuf); gdk_pixbuf_unref (pixbuf); gtk_widget_show (ogre_logo); gtk_box_pack_start (GTK_BOX (vbox), ogre_logo, FALSE, FALSE, 0); } catch (Exception &e) { // Could not decode image; never mind LogManager::getSingleton().logMessage("WARNING: Failed to decode Ogre logo image"); } GtkWidget *rs_hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), rs_hbox, FALSE, TRUE, 0); GtkWidget *rs_label = gtk_label_new ("Rendering subsystem:"); gtk_widget_show (rs_label); gtk_box_pack_start (GTK_BOX (rs_hbox), rs_label, TRUE, TRUE, 5); gtk_label_set_justify (GTK_LABEL (rs_label), GTK_JUSTIFY_RIGHT); gtk_misc_set_alignment (GTK_MISC (rs_label), 1, 0.5); GtkWidget *rs_cb = gtk_combo_box_new_text (); gtk_widget_show (rs_cb); gtk_box_pack_start (GTK_BOX (rs_hbox), rs_cb, TRUE, TRUE, 5); g_signal_connect (G_OBJECT (rs_cb), "changed", G_CALLBACK (rendererChanged), this); // Add all available renderers to the combo box RenderSystemList *renderers = Root::getSingleton ().getAvailableRenderers (); uint idx = 0, sel_renderer_idx = 0; for (RenderSystemList::iterator r = renderers->begin(); r != renderers->end (); r++, idx++) { gtk_combo_box_append_text (GTK_COMBO_BOX (rs_cb), (*r)->getName ().c_str ()); if (mSelectedRenderSystem == *r) sel_renderer_idx = idx; } // Don't show the renderer choice combobox if there's just one renderer if (idx > 1) gtk_widget_show (rs_hbox); GtkWidget *ro_frame = gtk_frame_new (NULL); gtk_widget_show (ro_frame); gtk_box_pack_start (GTK_BOX (vbox), ro_frame, TRUE, TRUE, 0); GtkWidget *ro_label = gtk_label_new ("Renderer options:"); gtk_widget_show (ro_label); gtk_frame_set_label_widget (GTK_FRAME (ro_frame), ro_label); gtk_label_set_use_markup (GTK_LABEL (ro_label), TRUE); mParamTable = gtk_table_new (0, 0, FALSE); gtk_widget_show (mParamTable); gtk_container_add (GTK_CONTAINER (ro_frame), mParamTable); gtk_combo_box_set_active (GTK_COMBO_BOX (rs_cb), sel_renderer_idx); return true; } bool ConfigDialog::display () { if (!__gtk_init_once ()) return false; /* Select previously selected rendersystem */ mSelectedRenderSystem = Root::getSingleton ().getRenderSystem (); /* Attempt to create the window */ if (!createWindow ()) OGRE_EXCEPT (Exception::ERR_INTERNAL_ERROR, "Could not create configuration dialog", "ConfigDialog::display"); // Modal loop gint result = gtk_dialog_run (GTK_DIALOG (mDialog)); gtk_widget_destroy (mDialog); // Wait for all gtk events to be consumed ... while (gtk_events_pending ()) gtk_main_iteration_do (FALSE); if (result != GTK_RESPONSE_OK) return false; Root::getSingleton ().setRenderSystem (mSelectedRenderSystem); return true; } }