//***************************************************************************************** // Truevision - a 3d modeler for gnome and povray // // objectlist.cc // // Vincent LE PRINCE // Copyright (C) 2000-2005 Vincent LE PRINCE // This file is part of the TRUEVISION Package // 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 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ //******************************************************************************************* #include "include/objectlist.h" #include "include/viewmanager.h" #include "include/interface.h" #include "include/preferences.h" #include "include/obj3ddef.h" #include "include/proppanel.h" #include "include/scene.h" #include "include/tvio.h" #include "config.h" #include "include/undo.h" #include "include/lights.h" #include "include/box.h" #include "include/sphere.h" #include "include/cylinder.h" #include "include/cone.h" #include "include/atmosphere.h" #include "include/obj3dcsg.h" #include "include/plane.h" #include "include/torus.h" #include "include/disc.h" #include "include/heightfield.h" #include "include/superellipsoid.h" #include "include/fog.h" #include "include/blob.h" #include "include/text.h" #include "include/lathe.h" #include "include/linkobj.h" #include "include/prism.h" #include "include/isosurface.h" #include "include/julia.h" #include "include/parametric.h" #include "include/povscript.h" #include "include/spheresweep.h" #include "include/bicubic.h" #include "include/scriptobj.h" #include //************************************** // Constants //************************************** // Objects manipulation buttons definitions const char *select_buttons_icons[OBJ_BUTTONS] = { GTK_STOCK_DELETE, GTK_STOCK_COPY, GTK_STOCK_SAVE, GTK_STOCK_OPEN, GTK_STOCK_GO_BACK, GTK_STOCK_GO_UP, GTK_STOCK_GO_DOWN, GTK_STOCK_CUT, GTK_STOCK_COPY, GTK_STOCK_PASTE }; const char *select_buttons_tooltips[OBJ_BUTTONS] = { N_("Delete"), N_("Duplicate"), N_("Save"), N_("Load"), N_("Unparent"), N_("Up"), N_("Down"), N_("Cut"), N_("Copy"), N_("Paste") }; // Layers manipulation buttons definitions const char *select_lbuttons_icons[LAY_BUTTONS] = { GTK_STOCK_NEW, GTK_STOCK_CLOSE, GTK_STOCK_COPY, GTK_STOCK_PROPERTIES, GTK_STOCK_GO_UP, GTK_STOCK_GO_DOWN }; const char *select_lbuttons_tooltips[LAY_BUTTONS] = { N_("New"), N_("Delete"), N_("Duplicate"), N_("Edit"), N_("Up"), N_("Down") }; // Default reference list const char *obj_ref_list_def[] = { N_("None") }; // Drag & Drop #define TV_DRAG_OBJECT_ID 194687685 GtkTargetEntry objects_source_target = { "TVOBJBIN", GTK_TARGET_SAME_APP, TV_DRAG_OBJECT_ID }; Object3D *draged_object3D; // OpenGL Lights #ifndef GL_LIGHT8 #define GL_LIGHT8 (GLenum)-1 #endif #ifndef GL_LIGHT9 #define GL_LIGHT9 (GLenum)-1 #endif #ifndef GL_LIGHT10 #define GL_LIGHT10 (GLenum)-1 #endif #ifndef GL_LIGHT10 #define GL_LIGHT10 (GLenum)-1 #endif #ifndef GL_LIGHT11 #define GL_LIGHT11 (GLenum)-1 #endif #ifndef GL_LIGHT12 #define GL_LIGHT12 (GLenum)-1 #endif #ifndef GL_LIGHT13 #define GL_LIGHT13 (GLenum)-1 #endif #ifndef GL_LIGHT14 #define GL_LIGHT14 (GLenum)-1 #endif #ifndef GL_LIGHT15 #define GL_LIGHT15 (GLenum)-1 #endif #ifndef GL_LIGHT16 #define GL_LIGHT16 (GLenum)-1 #endif #ifndef GL_LIGHT17 #define GL_LIGHT17 (GLenum)-1 #endif #ifndef GL_LIGHT18 #define GL_LIGHT18 (GLenum)-1 #endif #ifndef GL_LIGHT19 #define GL_LIGHT19 (GLenum)-1 #endif const int max_lights = 20; GLenum light_def[max_lights] = { GL_LIGHT0, GL_LIGHT1 ,GL_LIGHT2 ,GL_LIGHT3, GL_LIGHT4, GL_LIGHT5, GL_LIGHT6, GL_LIGHT7 ,GL_LIGHT8 ,GL_LIGHT9, GL_LIGHT10, GL_LIGHT11, GL_LIGHT13, GL_LIGHT14 ,GL_LIGHT15 ,GL_LIGHT16, GL_LIGHT17, GL_LIGHT18, GL_LIGHT19 }; // Unlinkable objects list const int UnlinkableObjects_num = 8; const Object3DType UnlinkableObject[ UnlinkableObjects_num ] = { TV_OBJ3D_CAMERA, TV_OBJ3D_LINK, TV_OBJ3D_BKGD, TV_OBJ3D_SKY, TV_OBJ3D_AMEDIA, TV_OBJ3D_BLOBSPHERE, TV_OBJ3D_BLOBCYLINDER, TV_OBJ3D_POVSCRIPT }; // Linkable test macros bool tvobj3d_is_linkable( Object3DType type ) { for ( int i = 0 ; i < UnlinkableObjects_num ; i++ ) if ( type == UnlinkableObject[i] ) return FALSE; return TRUE; } bool tvobj3d_is_linkable( Object3D *obj ) { return tvobj3d_is_linkable( obj->get_type() ); } //************************************************************** // Class ObjectList //************************************************************** //************************************************************** // Constructor // // Lists initialisation //************************************************************** ObjectList::ObjectList( app_objs *appref ) { // Initialisation app_ref = appref; app_ref->obj3dlist = this; cut_or_copied = NULL; is_cut = false; default_path = NULL; obj_name_list = NULL; current_ref = NULL; // OpenGL Lights // Mesa answers 0 lights at this time, disable test //glGetIntegerv( GL_MAX_LIGHTS, &light_num ); //cout << "\nmax lights = " << light_num; cout.flush(); light_num = 8; light_list = new bool[ light_num ]; for ( register int i = 0 ; i < light_num ; i++ ) light_list[i] = false; // Current object edit box edit_widget = NULL; edit_box = NULL; current = NULL; current_param = NULL; // Base Layer ObjectLayer *layer1 = new ObjectLayer( app_ref ); Layers.push_back( layer1 ); // Camera MainCamera = new Camera( app_ref ); layer1->add_object( MainCamera, NULL ); // Add a point light to default scene PointLight *lum = new PointLight( app_ref ); float loc[3] = { 0.6, 0.6, 0 }; lum->set_location( loc ); layer1->add_object( lum, NULL ); } //***************************************************************** // Add object // // Add an Object3D to the general list // Called from layers only //***************************************************************** void ObjectList::add_object( Object3D *obj ) { object_liste.push_back( obj ); update_ref_list(); } //***************************************************************** // Remove object // // Remove an object from the general list // Called from layers onlyénérale //***************************************************************** void ObjectList::remove_object( Object3D *obj ) { if ( obj->is_group() ) for ( int i = 0 ; i < obj->get_children_num() ; i++ ) remove_object( obj->get_children( i ) ); vector::iterator object; for ( object = object_liste.begin() ; object != object_liste.end() ; object++ ) { if ( *object != obj ) continue; object_liste.erase( object ); break; } update_ref_list(); } //**************************************************************** // Update ref list // // Update the references list // Shall be called at every list modification //***************************************************************** void ObjectList::update_ref_list() { if ( obj_name_list != NULL ) { for ( int i = 0 ; i < obj_name_list_size ; i++ ) delete obj_name_list[i]; delete obj_name_list; } obj_name_list = new char*[ object_liste.size() + 1 ]; obj_name_list[0] = new char[ strlen( obj_ref_list_def[0] ) + 1 ]; strcpy( obj_name_list[0], (char*)obj_ref_list_def[0] ); obj_name_list_size = 1; for ( unsigned int i = 0 ; i < object_liste.size() ; i ++ ) { if ( ! tvobj3d_is_linkable( object_liste[i] ) ) continue; char *str = object_liste[i]->get_name(); obj_name_list[obj_name_list_size] = new char[ strlen( str ) + 1 ]; strcpy( obj_name_list[obj_name_list_size], str ); obj_name_list_size++; } if ( current_ref !=NULL ) current_ref->update_ref_list(); } //**************************************************************** // Get index by pointer // // Return an index in reference list from an Object3D pointer // For object referencers only //***************************************************************** int ObjectList::get_index_by_pointer( Object3D *obj ) { int index = 0; for ( unsigned int i = 0 ; i < object_liste.size() ; i ++ ) { if ( object_liste[i] == obj ) return index; if ( ! tvobj3d_is_linkable( object_liste[i] ) ) continue; index++; } return -1; } //**************************************************************** // Get pointer by index // // Return a pointer to an Object3D from its index in reference list // For object referencers only //***************************************************************** Object3D * ObjectList::get_pointer_by_index( int index ) { int ind = 1; int size = object_liste.size(); for ( int i = 0 ; i < size ; i ++ ) { if ( ! tvobj3d_is_linkable( object_liste[i] ) ) continue; if ( index == ind ) { i++; while ( i < size && tvobj3d_is_linkable( object_liste[i] ) == FALSE ) i++; return object_liste[i]; } ind++; } return NULL; } //**************************************************************** // Get pointer by name // // Return a pointer to an Object3D from its name // For object referencers only //***************************************************************** Object3D * ObjectList::get_pointer_by_name( char *str ) { for ( unsigned int i = 0 ; i < object_liste.size() ; i ++ ) if ( ! strcmp( str, object_liste[i]->get_name() ) ) return object_liste[i]; return NULL; } //**************************************************************** // Create name // // Create a unique object name // Called from Object3D //***************************************************************** char *ObjectList::create_name( char *name ) { if ( !test_name_exist( name ) ) return NULL; int num = 2; int len = strlen(name); if ( ( name[len-1] >= 0x30 ) && ( name[len-1] <= 0x39 ) ) { int i; for ( i = len ; i > 0 ; i-- ) if ( name[i] == '#' ) break; if ( i > 0 ) { sscanf( name+i-1, "#%u", &num ); num++ ; len -= len - i; } } char buffer[ len + 30 ]; char num_buffer[30]; strcpy( buffer, name ); do { sprintf( num_buffer, "#%u", num++ ); memcpy( buffer+len, num_buffer, strlen(num_buffer)+1 ); } while ( test_name_exist(buffer) ); char *res = new char[ strlen(buffer) + 1 ]; strcpy( res, buffer ); return res; } //************************************** // Test name exists // // Check wether an object name already exists //************************************** bool ObjectList::test_name_exist( char *name ) { bool exist = false; char *res; for ( unsigned int i = 0 ; i < object_liste.size() ; i++ ) { res = object_liste[i]->get_name(); if ( res == NULL ) continue; if ( strcmp( res, name ) == 0 ) { exist = true; break; } } return exist; } //************************************** // Layer name exists // // Check wether a layer name already exists //************************************** bool ObjectList::layer_name_exist( char *name, ObjectLayer *layer ) { for ( unsigned int i = 0 ; i < Layers.size() ; i++ ) { if ( layer == Layers[i] ) continue; if ( ! Layers[i]->test_name( name ) ) return true; } return false; } //************************************** // Output to povray // // Output objects to povray scene file //************************************** void ObjectList::output_to_povray( ofstream & file ) { flush(); file << "\n\n//---------------------------------------------"; file << "\n// Objects declarations"; file << "\n//---------------------------------------------"; for ( unsigned int i = 0 ; i < Layers.size() ; i++ ) Layers[i]->output_to_povray_pass1( file ); file << "\n\n//---------------------------------------------"; file << "\n// Scene description"; file << "\n//---------------------------------------------"; for ( unsigned int i = 0 ; i < Layers.size() ; i++ ) Layers[i]->output_to_povray_pass2( file ); } //**************************************************** // Display // // Add every objects to the OpenGL preview //**************************************************** void ObjectList::display( glview *view ) { for ( unsigned int i = 0 ; i < Layers.size() ; i++ ) Layers[i]->display( view ); } //**************************************************** // Invalidate lists // // Call invalidate list for every object ( force refresh ) //**************************************************** void ObjectList::invalidate_lists() { for ( unsigned int i = 0 ; i < object_liste.size() ; i++ ) object_liste[i]->invalidate_list(); } //**************************************************** // Refresh edit // // Refresh the object edition panel //**************************************************** void ObjectList::refresh_edit() { if ( edit_widget == NULL ) return; if ( current != NULL ) { if ( edit_box != NULL ) current->destroy_editor(); edit_box = gtk_vbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(edit_widget), edit_box, TRUE, TRUE, 0 ); current->edit_widget(edit_box); } } //*********************************************************** // Set select widget // // Get the layer / object selection / manipulation panel //*********************************************************** void ObjectList::set_select_widget( GtkWidget *wid ) { PREF_DEF select_widget = wid; current_param = NULL; // Top level box GtkWidget *vbox = gtk_vbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(wid), vbox, TRUE, TRUE, 4 ); // Layer selection tree header GtkWidget *frame = gtk_frame_new(NULL); gtk_box_pack_start( GTK_BOX(vbox), frame, FALSE, TRUE, 0 ); GtkWidget *label = gtk_label_new( N_("Layers") ); gtk_container_add( GTK_CONTAINER(frame), label ); // Layers manipulation tree GtkWidget *scrolled = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_box_pack_start( GTK_BOX(vbox), scrolled, TRUE, TRUE, 4 ); layer_list_store = gtk_list_store_new( 5, GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER, -1 ); layer_list_view = gtk_tree_view_new_with_model( GTK_TREE_MODEL(layer_list_store) ); gtk_container_add( GTK_CONTAINER(scrolled), layer_list_view ); GtkCellRenderer *renderer1 = gtk_cell_renderer_pixbuf_new (); GtkCellRenderer *renderer2 = gtk_cell_renderer_text_new (); layer_list_column2 = gtk_tree_view_column_new_with_attributes ( NULL, renderer1, "pixbuf", 0, NULL); gtk_tree_view_column_set_fixed_width( layer_list_column2, 25 ); gtk_tree_view_column_set_sizing( layer_list_column2, GTK_TREE_VIEW_COLUMN_FIXED ); gtk_tree_view_append_column( GTK_TREE_VIEW(layer_list_view), layer_list_column2 ); layer_list_column3 = gtk_tree_view_column_new_with_attributes ( NULL, renderer1, "pixbuf", 1, NULL); gtk_tree_view_column_set_fixed_width( layer_list_column3, 25 ); gtk_tree_view_column_set_sizing( layer_list_column3, GTK_TREE_VIEW_COLUMN_FIXED ); gtk_tree_view_append_column( GTK_TREE_VIEW(layer_list_view), layer_list_column3 ); layer_list_column4 = gtk_tree_view_column_new_with_attributes ( NULL, renderer1, "pixbuf", 2, NULL); gtk_tree_view_column_set_fixed_width( layer_list_column4, 25 ); gtk_tree_view_column_set_sizing( layer_list_column4, GTK_TREE_VIEW_COLUMN_FIXED ); gtk_tree_view_append_column( GTK_TREE_VIEW(layer_list_view), layer_list_column4 ); GtkTreeViewColumn *column1 = gtk_tree_view_column_new_with_attributes( N_("Layer name"), renderer2, "text", 3, NULL); gtk_tree_view_append_column( GTK_TREE_VIEW(layer_list_view), column1 ); for ( unsigned int i = 0 ; i < Layers.size() ; i ++ ) Layers[i]->add_to_list( layer_list_store ); layer_list_selection = gtk_tree_view_get_selection( GTK_TREE_VIEW (layer_list_view) ); gtk_tree_selection_set_mode ( layer_list_selection, GTK_SELECTION_SINGLE ); g_signal_connect( G_OBJECT(layer_list_selection), "changed", G_CALLBACK(sign_layer_select), this ); gtk_signal_connect( GTK_OBJECT(layer_list_view), "button-press-event", GTK_SIGNAL_FUNC(sign_layer_view_clicked), (gpointer)this ); GtkTargetEntry targets[1] ={ objects_source_target }; gtk_drag_dest_set( layer_list_view, (GtkDestDefaults)(GTK_DEST_DEFAULT_ALL), targets, 1, (GdkDragAction)(GDK_ACTION_COPY | GDK_ACTION_MOVE) ); gtk_signal_connect( GTK_OBJECT(layer_list_view), "drag_data_received", GTK_SIGNAL_FUNC(sign_object_drop_on_layer), this ); gtk_signal_connect( GTK_OBJECT(layer_list_view), "drag_motion", GTK_SIGNAL_FUNC(sign_object_motion_on_layer), this ); // Layers manipulation buttons GtkWidget *hbox = gtk_hbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 2 ); GtkWidget *pix; for ( int i = 0 ; i < LAY_BUTTONS ; i ++ ) { select_lbuttons[i] = gtk_button_new(); gtk_button_set_relief( GTK_BUTTON(select_lbuttons[i]), GTK_RELIEF_NONE ); gtk_box_pack_start( GTK_BOX(hbox), select_lbuttons[i], TRUE, FALSE, 0 ); gtk_signal_connect( GTK_OBJECT(select_lbuttons[i]), "clicked", GTK_SIGNAL_FUNC(sign_select_lbuttons_clicked), this ); pix = gtk_image_new_from_stock( select_lbuttons_icons[i], GTK_ICON_SIZE_BUTTON ); gtk_container_add( GTK_CONTAINER(select_lbuttons[i]), pix ); select_ltooltips[i] = gtk_tooltips_new(); gtk_tooltips_set_tip( select_ltooltips[i], select_lbuttons[i], select_lbuttons_tooltips[i], NULL ); if ( !pref->tooltips->value() ) gtk_tooltips_disable( select_ltooltips[i] ); } // Object selection tree header frame = gtk_frame_new(NULL); gtk_box_pack_start( GTK_BOX(vbox), frame, FALSE, TRUE, 0 ); label = gtk_label_new( N_("Objects") ); gtk_container_add( GTK_CONTAINER(frame), label ); // Objects manipulation tree scrolled = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_box_pack_start( GTK_BOX(vbox), scrolled, TRUE, TRUE, 4 ); object_tree_store = gtk_tree_store_new( 6, GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, -1 ); object_tree_view = gtk_tree_view_new_with_model( GTK_TREE_MODEL(object_tree_store) ); gtk_container_add( GTK_CONTAINER(scrolled), object_tree_view ); GtkTreeViewColumn *object_tree_column3 = gtk_tree_view_column_new_with_attributes ( NULL, renderer1, "pixbuf", 0, NULL); gtk_tree_view_append_column( GTK_TREE_VIEW(object_tree_view), object_tree_column3 ); object_tree_column1 = gtk_tree_view_column_new_with_attributes ( NULL, renderer1, "pixbuf", 1, NULL); gtk_tree_view_column_set_fixed_width( object_tree_column1, 25 ); gtk_tree_view_column_set_sizing( object_tree_column1, GTK_TREE_VIEW_COLUMN_FIXED ); gtk_tree_view_append_column( GTK_TREE_VIEW(object_tree_view), object_tree_column1 ); object_tree_column2 = gtk_tree_view_column_new_with_attributes ( NULL, renderer1, "pixbuf", 2, NULL); gtk_tree_view_column_set_fixed_width( object_tree_column2, 25 ); gtk_tree_view_column_set_sizing( object_tree_column2, GTK_TREE_VIEW_COLUMN_FIXED ); gtk_tree_view_append_column( GTK_TREE_VIEW(object_tree_view), object_tree_column2 ); GtkTreeViewColumn *column5 = gtk_tree_view_column_new_with_attributes( N_("Type"), renderer2, "text", 3, NULL); gtk_tree_view_append_column( GTK_TREE_VIEW(object_tree_view), column5 ); GtkTreeViewColumn *column6 = gtk_tree_view_column_new_with_attributes( N_("Object name"), renderer2, "text", 4, NULL); gtk_tree_view_append_column( GTK_TREE_VIEW(object_tree_view), column6 ); object_tree_selection = gtk_tree_view_get_selection( GTK_TREE_VIEW (object_tree_view) ); gtk_tree_selection_set_mode ( object_tree_selection, GTK_SELECTION_SINGLE ); gtk_signal_connect( GTK_OBJECT(object_tree_view), "button-press-event", GTK_SIGNAL_FUNC(sign_object_view_clicked), (gpointer)this ); gtk_signal_connect( GTK_OBJECT(object_tree_view), "row-activated", GTK_SIGNAL_FUNC(sign_object_view_double_clicked), (gpointer)this ); gtk_drag_source_set( object_tree_view, GDK_BUTTON1_MASK, targets, 1, (GdkDragAction)(GDK_ACTION_COPY | GDK_ACTION_MOVE) ); gtk_signal_connect( GTK_OBJECT(object_tree_view), "drag_data_get", GTK_SIGNAL_FUNC(sign_object_drag), this ); gtk_drag_dest_set( object_tree_view, (GtkDestDefaults)(GTK_DEST_DEFAULT_ALL), targets, 1, (GdkDragAction)(GDK_ACTION_COPY | GDK_ACTION_MOVE) ); gtk_signal_connect( GTK_OBJECT(object_tree_view), "drag_data_received", GTK_SIGNAL_FUNC(sign_object_drop_on_tree), this ); gtk_signal_connect( GTK_OBJECT(object_tree_view), "drag_motion", GTK_SIGNAL_FUNC(sign_object_motion_on_tree), this ); selected_layer = NULL; select_layer_in_list( 0 ); if ( selected_layer == NULL ) selected_layer = Layers[0]; g_signal_connect( G_OBJECT( object_tree_selection), "changed", G_CALLBACK(sign_object_select), this ); edit_box = gtk_vbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(edit_widget), edit_box, TRUE, TRUE, 0 ); current = selected_layer->get_first_object(); current->select(); current->edit_widget(edit_box); // Objects manipulation buttons hbox = gtk_hbox_new( FALSE, 0 ); //GtkWidget *hbox2 = gtk_hbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 2 ); //gtk_box_pack_start( GTK_BOX(vbox), hbox2, FALSE, FALSE, 1 ); for ( int i = 0 ; i < OBJ_BUTTONS ; i ++ ) { select_buttons[i] = gtk_button_new(); gtk_button_set_relief( GTK_BUTTON(select_buttons[i]), GTK_RELIEF_NONE ); //gtk_box_pack_start( GTK_BOX( ( i < 6 ) ? hbox : hbox2 ), select_buttons[i], TRUE, FALSE, 0 ); gtk_box_pack_start( GTK_BOX(hbox), select_buttons[i], TRUE, FALSE, 0 ); gtk_signal_connect( GTK_OBJECT(select_buttons[i]), "clicked", GTK_SIGNAL_FUNC(sign_select_buttons_clicked), this ); pix = gtk_image_new_from_stock( select_buttons_icons[i], GTK_ICON_SIZE_BUTTON ); gtk_container_add( GTK_CONTAINER(select_buttons[i]), pix ); select_tooltips[i] = gtk_tooltips_new(); gtk_tooltips_set_tip( select_tooltips[i], select_buttons[i], select_buttons_tooltips[i], NULL ); if ( !pref->tooltips->value() ) gtk_tooltips_disable( select_tooltips[i] ); } // Add some accelerators INTERF_DEF gtk_widget_add_accelerator( select_buttons[0], "clicked", interf->get_accels(), GDK_Delete, (GdkModifierType)0, (GtkAccelFlags)0 ); gtk_widget_show_all( wid ); } //****************************************************** // Select layer // // Layer selection changed callback //****************************************************** void ObjectList::select_layer( GtkTreeSelection *selection ) { GtkTreeIter iter; GtkTreeModel *model; gpointer layer_pointer = NULL; if (gtk_tree_selection_get_selected (selection, &model, &iter)) gtk_tree_model_get (model, &iter, 4, &layer_pointer, -1); if ( layer_pointer == NULL ) return; if ( selected_layer != NULL ) selected_layer->save_tree(); selected_layer = (ObjectLayer*)layer_pointer; Object3D *old = current; unselect_object(); if ( old != NULL ) { VMAN_DEF vmanager->refresh(); } gtk_tree_store_clear( object_tree_store ); selected_layer->display_content( object_tree_view, object_tree_store, object_tree_selection ); current = selected_layer->get_first_object(); gtk_widget_queue_draw( object_tree_view ); } //****************************************************** // Layer view clicked // // Layer tree button press callback //****************************************************** void ObjectList::layer_view_clicked( GdkEventButton *ev ) { if ( selected_layer == NULL ) return; GtkTreeViewColumn *column; GtkTreePath *path; gtk_tree_view_get_path_at_pos( GTK_TREE_VIEW(layer_list_view),(gint) ev->x, (gint)ev->y, &path, &column, NULL, NULL ); if ( path == NULL ) return; gint *indices = gtk_tree_path_get_indices( path ); if ( selected_layer != Layers[ indices[0] ] ) return; if ( column == layer_list_column2 ) selected_layer->toggle_property( 1 ); if ( column == layer_list_column3 ) selected_layer->toggle_property( 2 ); if ( column == layer_list_column4 ) selected_layer->toggle_property( 3 ); } //****************************************************** // Layer buttons clicked // // Layer tree button press callback //****************************************************** void ObjectList::layers_buttons_clicked( GtkWidget *wid ) { int button = -1; for ( int i = 0 ; i < OBJ_BUTTONS ; i ++ ) if ( wid == select_lbuttons[i] ) { button = i; break; } SCENE_DEF UNDO_DEF if ( button == -1 ) return; switch( button ) { // Create new layer case 0: { scene->set_modified(); ObjectLayer *new_layer = new ObjectLayer( app_ref ); Layers.push_back( new_layer ); new_layer->add_to_list( layer_list_store ); select_layer_in_list( Layers.size() - 1 ); undoman->push( TV_UNDO_LAYER_CREATE, new_layer ); } break; // Delete layer case 1: { scene->set_modified(); undoman->push( TV_UNDO_LAYER_DELETE, selected_layer, get_layer_index(selected_layer) ); remove_layer( selected_layer ); } break; // Duplicate case 2: { scene->set_modified(); vector::iterator layer; unsigned int i = 0; for ( layer = Layers.begin() ; layer != Layers.end() ; layer++ ) { i++; if ( *layer != selected_layer ) continue; ObjectLayer *target = *layer++; ObjectLayer *copy = new ObjectLayer( *target ); Layers.insert( layer, copy ); copy->add_to_list( layer_list_store, i ); undoman->push( TV_UNDO_LAYER_CREATE, copy ); break; } select_layer_in_list( i ); } break; // Edit layer properties : case 3: { scene->set_modified(); vector::iterator layer; for ( layer = Layers.begin() ; layer != Layers.end() ; layer++ ) { if ( *layer != selected_layer ) continue; ObjectLayer *target = *layer; target->raise_edit_box(); break; } } break; // Move Up case 4: { scene->set_modified(); undoman->push( TV_UNDO_LAYER_MOVE, selected_layer, 2 ); move_layer( selected_layer, 1 ); } break; // Move Down case 5: { scene->set_modified(); undoman->push( TV_UNDO_LAYER_MOVE, selected_layer, 1 ); move_layer( selected_layer, 2 ); } break; default: break; } } //********************************************************** // Move layer // // Move a layer in list // 1 -> up // 2 -> down //********************************************************** void ObjectList::move_layer( ObjectLayer *lay, int sens ) { vector::iterator layer; unsigned int i = 0; for ( layer = Layers.begin() ; layer != Layers.end() ; layer++ ) { i++; if ( *layer != lay ) continue; if ( sens == 1 && i == 1 ) return; if ( sens == 2 && i == Layers.size() ) return; ObjectLayer *target = *layer; if ( sens == 1 ) { GtkTreeIter *iter = Layers[i-2]->get_node_iter(); target->move_before_in_list( iter ); } else { GtkTreeIter *iter = Layers[i]->get_node_iter(); target->move_after_in_list( iter ); } vector::iterator layer2 = layer; if ( sens == 1 ) layer2--; else layer2++; Layers.erase( layer ); Layers.insert( layer2, target ); break; } } //********************************************************** // Remove layer // // Remove a layer //********************************************************** void ObjectList::remove_layer( ObjectLayer *lay ) { // Find layer in list vector::iterator layer; unsigned int i = 0; for ( layer = Layers.begin() ; layer != Layers.end() ; layer++ ) { i++; if ( *layer != lay ) continue; ObjectLayer *target = *layer; if ( ! target->can_be_destroyed() ) { app_warning( _("Cannot destroy the layer owning the camera !") ); return; } target->remove_from_layer_list(); Layers.erase( layer ); //delete target; break; } // Managing tree current = NULL; selected_layer = NULL; if ( i < 0 ) i = 0; if ( i > Layers.size() - 1 ) i = Layers.size() - 1; select_layer_in_list( 0 ); } //********************************************************** // Insert layer // // insert a layer at given position //********************************************************** void ObjectList::insert_layer( ObjectLayer *lay, int position ) { // Find layer vector::iterator layer; int i = 0; for ( layer = Layers.begin() ; i < position ; layer++ ) i++; if ( i == (int)Layers.size() ) i = -1; // Add layer and select it if ( i != -1 ) Layers.insert( ++layer, lay ); else Layers.push_back( lay ); lay->add_to_list( layer_list_store, i ); select_layer_in_list( position ); } //********************************************************** // Get layer index // // get a layer position //********************************************************** gint ObjectList::get_layer_index( ObjectLayer *layer ) { vector::iterator target; unsigned int i = 0; for ( target = Layers.begin() ; target != Layers.end() ; target++ ) { i++; if ( *target == layer ) return i; } return -1; } //*************************************** // Select object // // Object tree selection callback //*************************************** void ObjectList::select_object( GtkTreeSelection *selection ) { VMAN_DEF GtkTreeIter iter; GtkTreeModel *model; gpointer object_pointer = NULL; if (gtk_tree_selection_get_selected (selection, &model, &iter)) gtk_tree_model_get (model, &iter, 5, &object_pointer, -1); if ( object_pointer == current ) return; if ( current_param != NULL ) { current_param = NULL; vmanager->set_pointer_mode( TV_PMODE_TRACKBALL ); } if ( current != NULL ) { current->unselect(); if ( edit_box != NULL ) current->destroy_editor(); current = NULL; } if ( object_pointer == NULL ) return; edit_box = gtk_vbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(edit_widget), edit_box, TRUE, TRUE, 0 ); current = (Object3D*)object_pointer; current->select(); current->edit_widget(edit_box); vmanager->refresh(); // Set Help on menu.. if ( GTK_IS_BIN(help_on_obj_wid) ) { GtkWidget *lab = gtk_bin_get_child( GTK_BIN(help_on_obj_wid) ); char *obj_str = current->get_type_name(); char *str = new char[ 20 + strlen( obj_str) ]; sprintf( str, N_("Help on %s ..."), obj_str ); gtk_label_set_text( GTK_LABEL(lab), str ); delete str; } } //*************************************** // Object view clicked // // Object tree button press event callback //*************************************** void ObjectList::object_view_clicked( GdkEventButton *ev ) { if ( current == NULL ) return; GtkTreeViewColumn *column; GtkTreePath *path; gtk_tree_view_get_path_at_pos( GTK_TREE_VIEW(object_tree_view),(gint) ev->x, (gint)ev->y, &path, &column, NULL, NULL ); if ( path == NULL ) return; GtkTreePath *current_path = gtk_tree_model_get_path( GTK_TREE_MODEL(object_tree_store), current->get_node() ); if ( gtk_tree_path_compare( path, current_path ) != 0 ) { gtk_tree_path_free( current_path ); return; } gtk_tree_path_free( current_path ); VMAN_DEF SCENE_DEF if ( column == object_tree_column1 ) { current->toggle_visibility(); scene->set_modified(); vmanager->refresh(); } if ( column == object_tree_column2 ) { current->toggle_render(); scene->set_modified(); } } //*********************************************************** // Object view double clicked // // Object tree activate event callback //*********************************************************** void ObjectList::object_view_double_clicked() { PROPPANEL_DEF proppanel->set_page(0); } //*************************************** // Select button clicked // // Object manipulation buttons callback //*************************************** void ObjectList::select_buttons_clicked( GtkWidget *wid ) { // Get the calling button number int button = -1; for ( int i = 0 ; i < OBJ_BUTTONS ; i ++ ) if ( wid == select_buttons[i] ) { button = i; break; } SCENE_DEF UNDO_DEF if ( button == -1 ) return; // Action switch( button ) { // Delete case 0: if ( current == NULL ) break; scene->set_modified(); undoman->push( TV_UNDO_OBJ_DELETE, current, selected_layer ); if ( edit_box != NULL ) { current->destroy_editor(); edit_box = NULL; } selected_layer->delete_object( current ); break; // Duplicate case 1: scene->set_modified(); selected_layer->duplicate_object( current ); break; // Save case 2: save_object(); break; // Load object case 3: load_object(); break; // Unparent case 4: scene->set_modified(); undoman->push( TV_UNDO_OBJ_MOVE, current, selected_layer ); selected_layer->unparent_object( current ); break; // Move object up case 5: scene->set_modified(); undoman->push( TV_UNDO_OBJ_MOVE, current, selected_layer ); selected_layer->move_object_up( current ); break; // Move object down case 6: scene->set_modified(); undoman->push( TV_UNDO_OBJ_MOVE, current, selected_layer ); selected_layer->move_object_down( current ); break; // Cut case 7: scene->set_modified(); if ( current->get_type() == TV_OBJ3D_CAMERA || current->get_category() == TV_OBJ3D_ATMOS1 ) { app_warning( _("Cannot cut this object.") ); break; } if ( is_cut && cut_or_copied != NULL ) delete cut_or_copied; cut_or_copied = current; is_cut = true; selected_layer->remove_object( current ); break; // Copy case 8: scene->set_modified(); if ( current->get_type() == TV_OBJ3D_CAMERA || current->get_category() == TV_OBJ3D_ATMOS1 ) { app_warning( _("Cannot copy this object.") ); break; } if ( is_cut && cut_or_copied != NULL ) delete cut_or_copied; if ( current != NULL ) cut_or_copied = current->duplicate_yourself(); is_cut = false; break; // Paste case 9: if ( cut_or_copied == NULL ) break; selected_layer->paste_object( cut_or_copied, current ); is_cut = false; cut_or_copied = cut_or_copied->duplicate_yourself(); break; default: break; } VMAN_DEF vmanager->refresh(); } //*********************************************************** // Unselect object // // unselect current object ( selection changed ) //*********************************************************** void ObjectList::unselect_object() { if ( current != NULL ) { current->unselect(); if ( edit_box != NULL ) current->destroy_editor(); } current = NULL; current_param = NULL; } //*********************************************************** // Set current param // // Set the current param, ie the selected Objparam // ( if interactive ) for current object //*********************************************************** void ObjectList::set_current_param( ObjParam* param ) { current_param = param; VMAN_DEF vmanager->refresh(); } //************************************************************ // Object drag // // Object drag from tree callback //************************************************************ void ObjectList::object_drag( GdkDragContext *dc, GtkSelectionData *selection_data ) { draged_object3D = current; guint data_size = sizeof( Object3D* ); gtk_selection_data_set( selection_data, GDK_SELECTION_TYPE_STRING, 8, (guchar*)draged_object3D, data_size ); } //************************************************************ // Object drop on layer // // Object drop on layer callback //************************************************************ void ObjectList::object_drop_on_layer( GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info ) { // Check is dropped object is valid if ( info != TV_DRAG_OBJECT_ID ) return; if ( selection_data == NULL ) return; if ( selection_data->length != sizeof(Object3D*) ) return; if ( draged_object3D->get_type() == TV_OBJ3D_CAMERA ) return; SCENE_DEF UNDO_DEF scene->set_modified(); // Get layer GtkTreePath *path; GtkTreeViewDropPosition pos; gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW(layer_list_view), x, y, &path, &pos); if ( path == NULL ) return; gint *indices = gtk_tree_path_get_indices( path ); gint row = indices[0]; if ( selected_layer == Layers[row] ) return; bool move = ( dc->action == GDK_ACTION_COPY ) ? false : true; // LMove or copy object ti this layer if ( move ) { undoman->push( TV_UNDO_OBJ_MOVE, draged_object3D, selected_layer ); selected_layer->remove_object( draged_object3D ); if ( selected_layer == Layers[row] ) selected_layer->append_object( draged_object3D ); else Layers[row]->add_object( draged_object3D, NULL ); } // copy else { Object3D *newobj = draged_object3D->duplicate_yourself(); if ( selected_layer == Layers[row] ) selected_layer->append_object( newobj ); else Layers[row]->add_object( newobj, NULL ); undoman->push( TV_UNDO_OBJ_CREATE, newobj, Layers[row] ); } } //************************************************************ // Object motion on layer // // DND motion on layer callback //************************************************************ void ObjectList::object_motion_on_layer( GdkDragContext *dc, gint x, gint y ) { GtkTreePath *path; GtkTreeViewDropPosition pos; gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW(layer_list_view), x, y, &path, &pos); if ( path == NULL ) return; gtk_tree_view_set_drag_dest_row ( GTK_TREE_VIEW(layer_list_view), path, pos ); } //**************************************************************************** // Object drop on tree // // An object was dropped on the object tree view //**************************************************************************** void ObjectList::object_drop_on_tree( GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info ) { if ( info != TV_DRAG_OBJECT_ID ) return; if ( selection_data == NULL ) return; if ( selection_data->length != sizeof(Object3D*) ) return; SCENE_DEF UNDO_DEF scene->set_modified(); // Get destination ( if dropped on a group ) GtkTreePath *path; GtkTreeViewDropPosition pos; gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW(object_tree_view), x, y, &path, &pos); gpointer object_pointer = NULL; if ( path != NULL ) { GtkTreeIter iter; gtk_tree_model_get_iter( GTK_TREE_MODEL(object_tree_store), &iter, path ); gtk_tree_model_get (GTK_TREE_MODEL(object_tree_store), &iter, 5, &object_pointer, -1); } Object3D *destination = (Object3D*)object_pointer; // Check if destination is valid, otherwise drop on root bool drop_on_root = false; if ( destination == NULL ) drop_on_root = true; else if (destination->is_group() == false ) drop_on_root = true; // Check if dropped object is valid, otherwise return if ( destination == draged_object3D ) return; if ( draged_object3D->get_type() == TV_OBJ3D_CAMERA ) return; if ( destination != NULL ) if ( destination->has_as_ancester( draged_object3D ) ) return; bool move = ( dc->action == GDK_ACTION_COPY ) ? false : true; if ( move ) { undoman->push( TV_UNDO_OBJ_MOVE, draged_object3D, selected_layer ); selected_layer->remove_object( draged_object3D ); if ( drop_on_root ) selected_layer->add_object( draged_object3D, NULL ); else destination->paste_object( draged_object3D ); } else { Object3D *newobj = draged_object3D->duplicate_yourself(); undoman->push( TV_UNDO_OBJ_CREATE, newobj, selected_layer ); if ( drop_on_root ) selected_layer->add_object( newobj, NULL ); else destination->paste_object( newobj ); } } //************************************************************ // Object motion on tree // // DND motion on object tree callback //************************************************************ void ObjectList::object_motion_on_tree( GdkDragContext *dc, gint x, gint y ) { GtkTreePath *path; GtkTreeViewDropPosition pos; gtk_tree_view_get_dest_row_at_pos (GTK_TREE_VIEW(object_tree_view), x, y, &path, &pos); if ( path == NULL ) return; gtk_tree_view_set_drag_dest_row ( GTK_TREE_VIEW(object_tree_view), path, pos ); } //*************************************** // Pref Changed ! // // Preferences changed app signal //*************************************** void ObjectList::pref_changed() { PREF_DEF for ( unsigned int i = 0 ; i < object_liste.size() ; i++ ) object_liste[i]->pref_changed(); bool tt = pref->tooltips->value(); for ( int i = 0 ; i < OBJ_BUTTONS ; i ++ ) if ( tt ) gtk_tooltips_enable( select_tooltips[i] ); else gtk_tooltips_disable( select_tooltips[i] ); } //*************************************** // set create widget // // Get the object creation panel //*************************************** void ObjectList::set_create_widget( GtkWidget *wid ) { // Object creation tree header GtkWidget *frame = gtk_frame_new(NULL); gtk_box_pack_start( GTK_BOX(wid), frame, FALSE, TRUE, 0 ); GtkWidget *label = gtk_label_new( N_("Objects creation") ); gtk_container_add( GTK_CONTAINER(frame), label ); // Object creation tree GtkWidget *scrolled = gtk_scrolled_window_new( NULL, NULL ); gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); gtk_box_pack_start( GTK_BOX(wid), scrolled, TRUE, TRUE, 4 ); create_tree_store = gtk_tree_store_new( 3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER ); create_tree = gtk_tree_view_new_with_model( GTK_TREE_MODEL(create_tree_store) ); gtk_container_add( GTK_CONTAINER(scrolled), create_tree ); GtkCellRenderer *renderer1 = gtk_cell_renderer_pixbuf_new (); GtkCellRenderer *renderer2 = gtk_cell_renderer_text_new (); GtkTreeViewColumn *column1 = gtk_tree_view_column_new_with_attributes ( NULL, renderer1, "pixbuf", 0, NULL); GtkTreeViewColumn *column2 = gtk_tree_view_column_new_with_attributes ( N_("Name"), renderer2, "text", 1, NULL); gtk_tree_view_append_column( GTK_TREE_VIEW(create_tree), column1 ); gtk_tree_view_append_column( GTK_TREE_VIEW(create_tree), column2 ); create_tree_selection = gtk_tree_view_get_selection( GTK_TREE_VIEW (create_tree) ); gtk_tree_selection_set_mode ( create_tree_selection, GTK_SELECTION_SINGLE ); g_signal_connect( G_OBJECT(create_tree_selection), "changed", G_CALLBACK(sign_create_tree_select), this ); gtk_signal_connect( GTK_OBJECT(create_tree), "row-activated", GTK_SIGNAL_FUNC(sign_create_tree_click), this ); // Add objects definitions add_subtree( _("Atmospherics"), NULL, Atmos_tree, Atmos_tree_num ); add_subtree( _("Lights"), "object_light.xpm", Lights_tree, Lights_tree_num ); add_subtree( _("Infinite solid primitives"), "object_plane.xpm", ISP_tree, ISP_tree_num ); add_subtree( _("Finite solid primitives"), "object_box.xpm", FSP_tree, FSP_tree_num ); add_subtree( _("Finite patch primitives"), NULL, FPP_tree, FPP_tree_num ); add_subtree( _("CSG operators"), "object_csg.xpm", CSG_tree, CSG_tree_num ); add_subtree( _("Misc objects"), "object_default.xpm", Misc_tree, Misc_tree_num ); GtkWidget *button = gtk_button_new_with_label( _("Create") ); gtk_box_pack_start( GTK_BOX(wid), button, FALSE, FALSE, 4 ); gtk_signal_connect( GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(sign_create_button_clicked), this ); gtk_widget_show_all( wid ); } //**************************************** // Add subtree // // Add an object category to the tree //**************************************** void ObjectList::add_subtree( const char *name, const char *icon, Object3DDef *defs, const int def_num ) { // Get the category pixmap GdkPixbuf *pixbuf = NULL; char *pixmap = NULL; if ( icon == NULL ) pixmap = tv_get_pixmap( "object_default.xpm" ); else pixmap = tv_get_pixmap( (char*)icon ); pixbuf = gdk_pixbuf_new_from_file( pixmap, NULL ); delete pixmap; GtkTreeIter iter; gtk_tree_store_append( create_tree_store, &iter, NULL ); gtk_tree_store_set( create_tree_store, &iter, 0, pixbuf, 1, name, 2, NULL, -1 ); // Add objects definitions for ( int i = 0 ; i < def_num ; i++ ) { GdkPixbuf *pixbuf = NULL; char *pixmap = NULL; if ( defs[i].icon == NULL ) pixmap = tv_get_pixmap( "object_default.xpm" ); else pixmap = tv_get_pixmap( (char*)defs[i].icon ); pixbuf = gdk_pixbuf_new_from_file( pixmap, NULL ); delete pixmap; GtkTreeIter iter2; gtk_tree_store_append( create_tree_store, &iter2, &iter ); gtk_tree_store_set( create_tree_store, &iter2, 0, pixbuf, 1, defs[i].name, 2, (gpointer)&defs[i], -1 ); } } //*************************************************** // Create tree select // // crete tree selection changed callbacks //*************************************************** void ObjectList::create_tree_select( GtkTreeSelection *selection ) { GtkTreeIter iter; GtkTreeModel *model; gpointer objdef_ptr; if (gtk_tree_selection_get_selected (selection, &model, &iter)) gtk_tree_model_get (model, &iter, 2, &objdef_ptr, -1); if ( objdef_ptr != NULL ) current_objdef = (Object3DDef*)objdef_ptr; else current_objdef = NULL; } //*********************************************** // Create tree double clicked // // double click on the create tree callback //*********************************************** void ObjectList::create_tree_click() { if ( current_objdef != NULL ) create_button_clicked(); else { GtkTreeIter iter; GtkTreeModel *model; gtk_tree_selection_get_selected (create_tree_selection, &model, &iter); GtkTreePath *path = gtk_tree_model_get_path( model, &iter ); bool isexp = gtk_tree_view_row_expanded( GTK_TREE_VIEW(create_tree), path ); if ( isexp ) gtk_tree_view_collapse_row( GTK_TREE_VIEW(create_tree), path ); else gtk_tree_view_expand_row( GTK_TREE_VIEW(create_tree), path, FALSE ); } } //**************************************** // Create button clicked // // create button callback //**************************************** void ObjectList::create_button_clicked() { if ( current_objdef == NULL ) return; Object3D *newbie; switch( current_objdef->type ) { case TV_OBJ3D_POINTLIGHT: newbie = new PointLight( app_ref ); break; case TV_OBJ3D_SPOTLIGHT: newbie = new SpotLight( app_ref ); break; case TV_OBJ3D_CYLLIGHT: newbie = new CylindricalLight( app_ref ); break; case TV_OBJ3D_AREALIGHT: newbie = new AreaLight( app_ref ); break; case TV_OBJ3D_BOX: newbie = new Box( app_ref ); break; case TV_OBJ3D_SPHERE: newbie = new Sphere( app_ref ); break; case TV_OBJ3D_CYLINDER: newbie = new Cylinder( app_ref ); break; case TV_OBJ3D_CONE: newbie = new Cone( app_ref ); break; case TV_OBJ3D_PLANE: newbie = new Plane( app_ref ); break; case TV_OBJ3D_TORUS: newbie = new Torus( app_ref ); break; case TV_OBJ3D_BKGD: { bool exist = false; for ( unsigned int i = 0 ; i < object_liste.size() ; i++ ) if ( object_liste[i]->get_type() == TV_OBJ3D_BKGD ) { exist = true; break; } if ( exist == true ) newbie = NULL; else newbie = new Background( app_ref ); } break; case TV_OBJ3D_SKY: { bool exist = false; for ( unsigned int i = 0 ; i < object_liste.size() ; i++ ) if ( object_liste[i]->get_type() == TV_OBJ3D_SKY ) { exist = true; break; } if ( exist == true ) newbie = NULL; else newbie = new SkySphere( app_ref ); } break; case TV_OBJ3D_AMEDIA: newbie = new AtmosMedia( app_ref ); break; case TV_OBJ3D_DISC: newbie = new Disc( app_ref ); break; case TV_OBJ3D_HEIGHTFIELD: newbie = new Heightfield( app_ref ); break; case TV_OBJ3D_SUPERELLIPSOID: newbie = new Superellipsoid( app_ref ); break; case TV_OBJ3D_FOG: newbie = new Fog( app_ref ); break; case TV_OBJ3D_CSGUNION: newbie = new CsgUnion( app_ref ); break; case TV_OBJ3D_CSGMERGE: newbie = new CsgMerge( app_ref ); break; case TV_OBJ3D_CSGINTERSECTION: newbie = new CsgIntersection( app_ref ); break; case TV_OBJ3D_CSGDIFFERENCE: newbie = new CsgDifference( app_ref ); break; case TV_OBJ3D_LIGHTGROUP: newbie = new LightGroup( app_ref ); break; case TV_OBJ3D_BLOB: newbie = new Blob( app_ref ); break; case TV_OBJ3D_TEXT: newbie = new Text( app_ref ); break; case TV_OBJ3D_LATHE: newbie = new Lathe( app_ref ); break; case TV_OBJ3D_PRISM: newbie = new Prism( app_ref ); break; case TV_OBJ3D_LINK: newbie = new LinkObj( app_ref ); break; case TV_OBJ3D_GROUP: newbie = new CsgGroup( app_ref ); break; case TV_OBJ3D_ISOSURFACE: newbie = new IsoSurface( app_ref ); break; case TV_OBJ3D_PARAMETRIC: newbie = new Parametric( app_ref ); break; case TV_OBJ3D_JULIA: newbie = new Julia( app_ref ); break; case TV_OBJ3D_POVSCRIPT: newbie = new PovScript( app_ref ); break; case TV_OBJ3D_SPHERESWEEP: newbie = new SphereSweep( app_ref ); break; case TV_OBJ3D_BICUBIC: newbie = new Bicubic( app_ref ); break; default: newbie = NULL; } if ( newbie == NULL ) return; selected_layer->add_object( newbie, current ); SCENE_DEF scene->set_modified(); UNDO_DEF undoman->push( TV_UNDO_OBJ_CREATE, newbie, selected_layer ); PREF_DEF if ( pref->auto_obj_edit->value() ) { PROPPANEL_DEF proppanel->set_page( 0 ); } } //************************************************************************ // Create Object // // Create an object from its tag name //************************************************************************ Object3D *ObjectList::create_object( char *tag ) { if ( ! strcmp( tag, "BOX" ) ) return new Box( app_ref ); if ( ! strcmp( tag, "CAMERA" ) ) return new Camera( app_ref ); if ( ! strcmp( tag, "SPHERE" ) ) return new Sphere( app_ref ); if ( ! strcmp( tag, "POINTLIGHT" ) ) return new PointLight( app_ref ); if ( ! strcmp( tag, "CYLINDERLIGHT" ) ) return new CylindricalLight( app_ref ); if ( ! strcmp( tag, "SPOTLIGHT" ) ) return new SpotLight( app_ref ); if ( ! strcmp( tag, "CONE" ) ) return new Cone( app_ref ); if ( ! strcmp( tag, "CYLINDER" ) ) return new Cylinder( app_ref ); if ( ! strcmp( tag, "CSGUNION" ) ) return new CsgUnion( app_ref ); if ( ! strcmp( tag, "CSGMERGE" ) ) return new CsgMerge( app_ref ); if ( ! strcmp( tag, "CSGDIFF" ) ) return new CsgDifference( app_ref ); if ( ! strcmp( tag, "CSGINTER" ) ) return new CsgIntersection( app_ref ); if ( ! strcmp( tag, "PLANE" ) ) return new Plane( app_ref ); if ( ! strcmp( tag, "AREALIGHT" ) ) return new AreaLight( app_ref ); if ( ! strcmp( tag, "TORUS" ) ) return new Torus( app_ref ); if ( ! strcmp( tag, "AMEDIA" ) ) return new AtmosMedia( app_ref ); if ( ! strcmp( tag, "DISC" ) ) return new Disc( app_ref ); if ( ! strcmp( tag, "HEIGHTFIELD" ) ) return new Heightfield( app_ref ); if ( ! strcmp( tag, "SUPERELLIPSOID" ) ) return new Superellipsoid( app_ref ); if ( ! strcmp( tag, "FOG" ) ) return new Fog( app_ref ); if ( ! strcmp( tag, "LIGHTGROUP" ) ) return new LightGroup( app_ref ); if ( ! strcmp( tag, "BLOB" ) ) return new Blob( app_ref ); if ( ! strcmp( tag, "BLOBSPHERE" ) ) return new BlobSphere( app_ref ); if ( ! strcmp( tag, "BLOBCYLINDER" ) ) return new BlobCylinder( app_ref ); if ( ! strcmp( tag, "TEXT" ) ) return new Text( app_ref ); if ( ! strcmp( tag, "LATHE" ) ) return new Lathe( app_ref ); if ( ! strcmp( tag, "LINK" ) ) return new LinkObj( app_ref ); if ( ! strcmp( tag, "GROUP" ) ) return new CsgGroup( app_ref ); if ( ! strcmp( tag, "PRISM" ) ) return new Prism( app_ref ); if ( ! strcmp( tag, "ISOSURFACE" ) ) return new IsoSurface( app_ref ); if ( ! strcmp( tag, "JULIA" ) ) return new IsoSurface( app_ref ); if ( ! strcmp( tag, "PARAMETRIC" ) ) return new Parametric( app_ref ); if ( ! strcmp( tag, "POVSCRIPT" ) ) return new PovScript( app_ref ); if ( ! strcmp( tag, "SPHERESWEEP" ) ) return new SphereSweep( app_ref ); if ( ! strcmp( tag, "BICUBIC" ) ) return new Bicubic( app_ref ); if ( ! strcmp( tag, "SCRIPTOBJ" ) ) return new ScriptObj( app_ref ); if ( ! strcmp( tag, "SKY" ) ) { bool exist = false; for ( unsigned int i = 0 ; i < object_liste.size() ; i++ ) if ( object_liste[i]->get_type() == TV_OBJ3D_SKY ) { exist = true; break; } if ( exist == true ) return NULL; else return new SkySphere( app_ref ); } if ( ! strcmp( tag, "BACKGROUND" ) ) { bool exist = false; for ( unsigned int i = 0 ; i < object_liste.size() ; i++ ) if ( object_liste[i]->get_type() == TV_OBJ3D_BKGD ) { exist = true; break; } if ( exist == true ) return NULL; else return new Background( app_ref ); } return NULL; } //**************************************** // Save // // save object list to a tv scene file //**************************************** void ObjectList::save( ofstream & file ) { if ( current != NULL ) current->flush(); if ( selected_layer != NULL ) selected_layer->save_tree(); file << "\nOBJECTS{"; for ( unsigned int i = 0 ; i < Layers.size() ; i++ ) { file << "\n"; Layers[i]->save( file ); } file << "\n}\n"; } //**************************************** // Load // // load object list from a tv scene file //**************************************** bool ObjectList::load( ifstream & file, char *ltag ) { if ( strcmp( ltag, "OBJECTS" ) ) return false; char * tag = NULL; do { tag = tvio_get_next_tag( file ); if ( tag == NULL ) break; ObjectLayer *layer = new ObjectLayer( app_ref ); if ( layer->load( file, tag ) ) { Layers.push_back( layer ); layer->add_to_list( layer_list_store ); continue; } else delete layer; tvio_skip_section(file ); } while ( tag != NULL ); current_ref = NULL; current = NULL; current_param = NULL; select_layer_in_list( 0 ); return true; } //**************************************** // Clear // // clear object list //**************************************** void ObjectList::clear() { for ( unsigned int i = 0 ; i < Layers.size() ; i++ ) delete Layers[i]; Layers.clear(); selected_layer = NULL; gtk_list_store_clear( layer_list_store ); gtk_tree_store_clear( object_tree_store ); MainCamera = NULL; object_liste.clear(); for ( register int i = 0 ; i < light_num ; i++ ) light_list[i] = false; } //**************************************** // New Scene // // clear object list and create deafault scene list //**************************************** void ObjectList::new_scene() { for ( register int i = 1 ; i < light_num ; i++ ) light_list[i] = false; // Current object edit box current = NULL; current_param = NULL; // Base Layer ObjectLayer *layer1 = new ObjectLayer( app_ref ); Layers.push_back( layer1 ); layer1->add_to_list( layer_list_store, -1 ); // Camera MainCamera = new Camera( app_ref ); layer1->add_object( MainCamera, NULL ); // Light PointLight *lum = new PointLight( app_ref ); layer1->add_object( lum, NULL ); select_layer_in_list( 0 ); VMAN_DEF vmanager->refresh(); } //**************************************** // Light request // // free opengl light number request // Called from light objects //**************************************** int ObjectList::light_request( ) { for ( register int i = 0 ; i < light_num ; i++ ) if ( ! light_list[i] ) { light_list[i] = true; return i; } return -1; } //**************************************** // Light set properties // // set opengl light properties // Called from light objects //**************************************** void ObjectList::light_set_properties( int lamp_id, float *location, float *color ) { GLfloat ambient[4]= { 0.00025, 0.00025, 0.00025, 0 }; GLfloat specular[4] = { 0.2, 0.2, 0.2, 0 }; GLfloat position[4] = { location[0], location[1], location[2], 1.0}; if ( lamp_id == -1 ) { return; } glLightfv( light_def[lamp_id], GL_POSITION, position ); glLightfv( light_def[lamp_id], GL_DIFFUSE, color ); glLightfv( light_def[lamp_id], GL_AMBIENT, ambient ); glLightfv( light_def[lamp_id], GL_SPECULAR, specular ); glLightf( light_def[lamp_id], GL_SPOT_CUTOFF, 180.0 ); } // For light spots void ObjectList::light_set_properties( int lamp_id, float *location, float *pointat, float cutoff, float *color ) { if ( lamp_id == -1 ) return; float direction[] = { pointat[0] - location[0], pointat[1] - location[1], pointat[2] - location[2] }; glLightfv( light_def[lamp_id], GL_POSITION, location ); glLightf( light_def[lamp_id], GL_SPOT_CUTOFF, cutoff ); glLightfv( light_def[lamp_id], GL_SPOT_DIRECTION, direction ); glLightfv( light_def[lamp_id], GL_DIFFUSE, color ); glLightfv( light_def[lamp_id], GL_SPECULAR, color ); } //**************************************** // Light enable / disable // // set light on / off //**************************************** void ObjectList::light_enable( int lamp_id ) { if ( lamp_id != -1 ) glEnable( light_def[lamp_id] );} void ObjectList::light_disable( int lamp_id ) { if ( lamp_id != -1 ) glDisable( light_def[lamp_id] );} void ObjectList::light_disable_all() { for ( int i = 0 ; i < light_num ; i++ ) glDisable( light_def[ i ] ); } //************************************************* // Load object // // Load object from a file // uses a file chooser to ask for file //************************************************* void ObjectList::load_object() { // file chooser filters GtkFileFilter *filter1 = gtk_file_filter_new(); gtk_file_filter_add_pattern( filter1, "*.tvo" ); gtk_file_filter_set_name( filter1, "Truevision object file" ); GtkFileFilter *filter2 = gtk_file_filter_new(); gtk_file_filter_add_pattern( filter2, "*.*" ); gtk_file_filter_set_name( filter2, "All files" ); // File chooser INTERF_DEF filebox = gtk_file_chooser_dialog_new( _("Load object..."), (GtkWindow*)interf->get_gtkwin(), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); if ( default_path != NULL ) gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(filebox), default_path ); gtk_file_chooser_add_filter( GTK_FILE_CHOOSER(filebox), filter1 ); gtk_file_chooser_add_filter( GTK_FILE_CHOOSER(filebox), filter2 ); if (gtk_dialog_run (GTK_DIALOG (filebox)) == GTK_RESPONSE_ACCEPT) { char *fname; fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filebox)); if ( fname == NULL ) { g_free( fname ); return; } store_default_path( fname ); // Open the object file ifstream file( fname, ios::binary ); if ( ! tvio_check_file_sig( file, "TRUEVISION OBJECT" ) ) { app_warning( _("File type unknown : "), fname ); gtk_widget_destroy( filebox ); g_free( fname ); return; } tvio_get_soft_version( file ); MATLIST_DEF vector mlist; char * tag = NULL; do { tag = tvio_get_next_tag( file ); if ( tag == NULL ) break; if ( ! strcmp( tag, "MATERIALS" ) ) { char * ltag = NULL; do { ltag = tvio_get_next_tag( file ); if ( ltag == NULL ) break; Material *tex = (Material*)(new PovMaterial( app_ref, "MATERIAL" )); if ( tex->load( file, ltag ) ) { mlist.push_back( tex ); continue; } else delete tex; tvio_skip_section(file ); } while ( ltag != NULL ); matlist->set_load_list( &mlist ); continue; } Object3D *obj = create_object( tag ); if ( obj != NULL ) { if ( obj->get_type() == TV_OBJ3D_CAMERA ) { app_warning( _("Cannot load a camera as a single object") ); delete obj; break; } if ( obj->load( file, tag ) ) { selected_layer->append_object( obj ); matlist->flush_load_list(); break; } else delete obj; } tvio_skip_section(file ); } while ( tag != NULL ); file.close(); SCENE_DEF scene->set_modified(); VMAN_DEF vmanager->refresh(); g_free (fname); } gtk_widget_destroy( filebox ); } //************************************************* // Save object // // save object in a tv object file // uses a file chooser to ask for file //************************************************* void ObjectList::save_object() { if ( current == NULL ) { app_warning( _("Please select an object to save...") ); return; } if ( current->get_type() == TV_OBJ3D_CAMERA ) { app_warning( _("Cannot save camera as a single object.") ); return; } // File chooser INTERF_DEF filebox = gtk_file_chooser_dialog_new( _("Save object..."), (GtkWindow*)interf->get_gtkwin(), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); if ( default_path != NULL ) gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(filebox), default_path ); if (gtk_dialog_run (GTK_DIALOG (filebox)) == GTK_RESPONSE_ACCEPT) { char *fname; fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filebox)); if ( fname == NULL ) { g_free( fname ); return; } store_default_path( fname ); // Create file name char *filename; bool added_ext = false; int offset = strlen( fname ) - 4; if ( offset < 1 || ( strcmp( fname + offset, ".tvo" ) && strcmp( fname + offset, ".TVO" ) ) ) { filename = new char[ offset + 9 ]; strcpy( filename, fname ); strcat( filename, ".tvo" ); added_ext = true; } else filename = fname; // Test name existence ifstream ifile( filename, ios::binary ); if ( ifile != NULL ) { GtkWidget *dialog = gtk_message_dialog_new ( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("File already exists, overwrite ?")); gint button = gtk_dialog_run( GTK_DIALOG(dialog)); gtk_widget_destroy( dialog ); if ( button == GTK_RESPONSE_NO ) { gtk_widget_destroy(filebox); g_free( fname ); return; } } ifile.close(); // Open file ( create ) ofstream file( filename, ios::out ); file.setf( ios::fixed, ios::floatfield ); if ( file == NULL ) { app_warning( _("Cannot open : "), filename ); gtk_widget_destroy(filebox); g_free( fname ); return; } // Write object to file file << "TRUEVISION OBJECT"; file << "\nVERSION " << VERSION; vector matlist; current->get_materials( matlist ); file << "\nMATERIALS{"; for ( unsigned int i = 0 ; i < matlist.size() ; i++ ) matlist[i]->save( file ); file << "\n}\n"; current->save( file ); file.close(); if ( added_ext ) delete filename; g_free (fname); } gtk_widget_destroy( filebox ); } //************************************************* // Store default path // // store ( for the session ) the path were user // load / save objects //************************************************* void ObjectList::store_default_path( char *path ) { if ( default_path != NULL ) delete default_path; int len = strlen( path ); while ( len > 0 && path[len] != '/' ) len--; if ( len == 0 ) return; default_path = new char[ len +2 ]; strncpy( default_path, path, len+1 ); default_path[len+1] = '\0'; } //**************************************** // Init pick names // // Reset pick names list // for opengl picking ( feedback ) system //**************************************** void ObjectList::init_pick_names() { current_pick_name = 1; glInitNames(); glPushName(0); } //**************************************** // select picked // // Get the selected object from the pick // name returned by OpenGL //**************************************** void ObjectList::select_picked( int name ) { Object3D *res = NULL; for ( unsigned int i = 0 ; i < object_liste.size() ; i++ ) { if ( object_liste[i]->pick_test( name ) ) { res = object_liste[i]; break; } } if ( res == NULL ) return; if ( res == current ) return; ObjectLayer *layer = res->get_layer(); if ( selected_layer != layer ) { GtkTreeIter *iter = layer->get_node_iter(); gtk_tree_selection_select_iter( layer_list_selection, iter ); } res->tree_node_select(); VMAN_DEF vmanager->refresh(); }