//***************************************************************************************** // Truevision - a 3d modeler for gnome and povray // // scene.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 "config.h" #include "include/scene.h" #include "include/interface.h" #include "include/dlgutils.h" #include "include/povfe.h" #include "include/tvio.h" #include "include/undo.h" #include "include/heightfield.h" #include "include/text.h" // Définitions const gchar *def_filename = N_("Untitled.tvs"); const char *scene_file_ext = ".tvs"; //*********************************************** // Constructeur //*********************************************** Scene::Scene( app_objs *appref ) { app_ref = appref; app_ref->scene = this; modified = false; load_file_size = -1; save_file_state = -1; filename = NULL; set_filename( def_filename ); default_path = NULL; objlist = new ObjectList( app_ref ); texlist = new MatList( app_ref ); filebox = NULL; tbw_save = NULL; mew_save = NULL; } //*********************************************** // Nom //*********************************************** void Scene::set_filename( const char *fname ) { if ( filename != NULL ) delete filename; int fname_len = strlen(fname); filename = new char[ strlen(fname) + 5 ]; strcpy( filename, fname ); if ( strcmp( filename + fname_len - 4, scene_file_ext ) ) strcat( filename, scene_file_ext ); set_win_title(); } void Scene::set_win_title() { INTERF_DEF if ( interf == NULL ) return; int filename_len = strlen( filename ); int path_len = filename_len; while ( path_len > 0 && filename[ --path_len ] != '/' ); char *title = new char[ strlen(APP_NAME) + filename_len - path_len + 5 ]; strcpy( title, APP_NAME ); strcat( title, " - " ); strcat( title, filename + (( path_len == 0 ) ? 0 : path_len+1 ) ); if ( modified ) strcat( title, "*" ); gtk_window_set_title( &(GNOME_APP(interf->get_gtkwin())->parent_object), title ); delete title; } void Scene::set_modified() { if ( modified == true ) return; modified = true; set_win_title(); save_widgets_active( TRUE ); } void Scene::save_widgets_active( gboolean var ) { //gtk_widget_set_sensitive( tbw_save, var ); //gtk_widget_set_sensitive( mew_save, var ); gtk_action_set_sensitive( save_menu_action, var ); } //*********************************************** // Output to povray //*********************************************** void Scene::output_to_povray( char *filename, char *ini_name ) { ofstream file( filename, ios::out ); if ( file == NULL ) { app_warning( _("Cannot open file : "), filename ); return; } file.setf( ios::fixed, ios::floatfield ); //file.setf( ios::showpoint, ios::floatfield ); file << "//---------------------------------------------\n"; file << "// Created with Truevision, version " << VERSION; file << "\n// Scene file from povray output filter"; file << "\n// Scene : " << filename; file << "\n//---------------------------------------------\n"; POVFE_DEF povfe->output_to_povray( file ); texlist->output_to_povray( file ); objlist->output_to_povray( file ); file.close(); if ( ini_name != NULL ) { ofstream file2( ini_name, ios::out ); if ( file2 == NULL ) { app_warning( _("Cannot open file : "), ini_name ); return; } file2.setf( ios::fixed, ios::floatfield ); file2 << "; ---------------------------------------------\n"; file2 << "; Created with Truevision, version " << VERSION; file2 << "\n; Ini file from povray output filter"; file2 << "\n; Scene : " << filename; file2 << "\n; ---------------------------------------------\n"; povfe->output_to_povray_ini( file2, filename ); file2.close(); } } char *Scene::get_temp_povray_file() { char *res = get_temp_filename(); output_to_povray( res ); return res; } //*********************************************** // Export to povray //*********************************************** void Scene::export_to_povray() { INTERF_DEF filebox = gtk_file_chooser_dialog_new( _("Export to..."), (GtkWindow*)interf->get_gtkwin(), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); // Try to guess filename if ( filename != NULL ) { int len = strlen(filename); char *guess = new char[ len+ 1 ]; int i = len; while ( filename[i] != '/' && i != 0 ) i--; if ( i != 0 ) i++; strncpy( guess, filename+i, len - i - 4 ); guess[ len - i - 4 ] = '\0'; strcat( guess, ".pov" ); gtk_file_chooser_set_current_name( GTK_FILE_CHOOSER(filebox), guess ); delete guess; } else gtk_file_chooser_set_current_name( GTK_FILE_CHOOSER(filebox), "export.pov" ); if ( default_path != NULL ) gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(filebox), default_path ); // Run the dialog box 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 ) return; // Get Both ini & pov filename from dilog return int len = strlen( fname ); char *pov_name, *ini_name; if ( !strncmp( fname+len-4, ".pov", 4 ) || !strncmp( fname+len-4, ".POV", 4 ) ) { pov_name = new char[ len + 1 ]; strcpy( pov_name, fname ); ini_name = new char[ len + 1 ]; strcpy( ini_name, fname ); strncpy( ini_name+len-4, ".ini", 4 ); } else { pov_name = new char[ len + 5 ]; strcpy( pov_name, fname ); strcat( pov_name, ".pov" ); ini_name = new char[ len + 5 ]; strcpy( ini_name, fname ); strcat( ini_name, ".ini" ); } // Check if ini or pov file already exists - Confirmation dialog ifstream file( pov_name ); ifstream file2( ini_name ); if ( file || file2 ) { file.close(); file2.close(); 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 ) { g_free( fname); interf->set_hourglass( false ); gtk_widget_destroy( filebox ); return; } } // Export interf->set_hourglass( true ); output_to_povray( pov_name, ini_name ); delete pov_name; delete ini_name; interf->set_hourglass( false ); g_free (fname); } gtk_widget_destroy( filebox ); } typedef struct _OBJ_FNAME { Object3D* obj; char* fname; } Obj_Fname; //*********************************************** // Export scene pack //*********************************************** void Scene::export_scene_pack() { INTERF_DEF filebox = gtk_file_chooser_dialog_new( _("Export to..."), (GtkWindow*)interf->get_gtkwin(), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); char *extracted_fname, *old_fname; char *exp_name, *tvs_name, *pov_name, *ini_name, *tmp_fname, *tmp_fname2 = NULL; int pid, len, n; char *args[256]; vectortmp_obj_list; Obj_Fname *of; Object3D *obj; unsigned int i; char cp_path[512]; // Try to guess filename if ( filename != NULL ) { int len = strlen(filename); char *guess = new char[ len+ 1 ]; int i = len; while ( filename[i] != '/' && i != 0 ) i--; if ( i != 0 ) i++; strncpy( guess, filename+i, len - i - 4 ); guess[ len - i - 4 ] = '\0'; strcat( guess, ".tar.gz" ); gtk_file_chooser_set_current_name( GTK_FILE_CHOOSER(filebox), guess ); delete guess; } else gtk_file_chooser_set_current_name( GTK_FILE_CHOOSER(filebox), "export.pov" ); if ( default_path != NULL ) gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(filebox), default_path ); // Run the dialog box 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 ) return; char *tmp_dir = NULL; tmp_dir = get_temp_directory(); if ( tmp_dir == NULL ) { printf("Could not create tmp_directory\n"); fflush(stdout);return; } // Get Both ini & pov filename from dilog return len = strlen( fname ); if ( ( ends_with(fname, ".tar.gz") == 0 ) && ( ends_with(fname,".tgz") == 0 ) ) { exp_name = new char[ len + 8 ]; strcpy( exp_name, fname ); strcat( exp_name, ".tar.gz" ); tmp_fname = extract_filename( fname ); } else { exp_name = new char[ len + 1 ]; strcpy( exp_name, fname ); int tail = 7; if ( ends_with(fname, ".tgz") == 1 ) tail = 4; tmp_fname2 = new char[ len + 5 - tail]; strncpy( tmp_fname2, fname, (len - tail) ); tmp_fname2[(len-tail)] = '\0'; tmp_fname = extract_filename( tmp_fname2 ); } pov_name = new char[ strlen( tmp_dir ) + strlen( tmp_fname ) + 5 ]; ini_name = new char[ strlen( tmp_dir ) + strlen( tmp_fname ) + 5 ]; tvs_name = new char[ strlen( tmp_dir ) + strlen( tmp_fname ) + 5 ]; strcpy( pov_name, tmp_dir ); strcpy( ini_name, tmp_dir ); strcpy( tvs_name, tmp_dir ); strcat( pov_name, tmp_fname ); strcat( ini_name, tmp_fname ); strcat( tvs_name, tmp_fname ); strcat( pov_name, ".pov" ); strcat( ini_name, ".ini" ); strcat( tvs_name, ".tvs" ); // Check if exp_file already exists - Confirmation dialog ifstream file( exp_name ); if ( file ) { file.close(); 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 ) { g_free( fname); return; } } // Export interf->set_hourglass( true ); char tar[]= TAR_PATH; char arg1[]="-czf"; char arg2[]="-C"; args[0] = tar; args[1] = arg1; args[2] = exp_name; args[3] = arg2; args[4] = tmp_dir; args[5] = extract_filename(pov_name); args[6] = extract_filename(ini_name); args[7] = extract_filename(tvs_name); int args_cnt = 8; for ( int w = 8 ; w < 256 ; w++ ) args[w] = NULL; for ( i = 0 ; i < (unsigned int)objlist->get_size() ; i++ ) { obj = (Object3D*)objlist->get_object( i ); if( obj == NULL ) continue; if ( obj->get_type() == TV_OBJ3D_TEXT ) { of = new Obj_Fname; of->fname = strdup(((Text*)obj)->get_font()); of->obj = obj; extracted_fname = extract_filename( of->fname ); ((Text*)obj)->set_font( extracted_fname ); tmp_obj_list.push_back( of ); sprintf(cp_path, "%s%s", tmp_dir, extracted_fname); cp(of->fname, cp_path); for ( n = 8 ; n < args_cnt +1; n++) { if ( args[n] != NULL ) if ( strcmp( extracted_fname, args[n] ) == 0 ) { n = -1; break; } } if ( n >= 0 ) args[args_cnt++] = extracted_fname; } /*else if ( obj->get_type() == TV_OBJ3D_HEIGHTFIELD ) { of = new Obj_Fname; of->fname = strdup(((Heightfield*)obj)->get_filename()); of->obj = obj; extracted_fname = extract_filename( of->fname ); ((Heightfield*)obj)->set_filename( extracted_fname ); tmp_obj_list.push_back( of ); sprintf(cp_path, "%s%s", tmp_dir, extracted_fname); cp(of->fname, cp_path); for ( n = 8 ; n < args_cnt + 1 ; n++) { if ( strcmp( extracted_fname, args[n] ) == 0 ) { n = -1; break; } } if ( n >= 0 ) args[args_cnt++] = extracted_fname; }*/ } args[args_cnt++] = '\0'; args[args_cnt] = NULL; output_to_povray( pov_name, ini_name ); old_fname = filename; filename = tvs_name; save(); filename = old_fname; for ( i = 0 ; i < tmp_obj_list.size() ; i++ ) { of = (Obj_Fname*)tmp_obj_list[i]; obj = (Object3D*)of->obj; if ( obj->get_type() == TV_OBJ3D_TEXT ) { ((Text*)obj)->set_font(of->fname); delete of; }/* else if ( obj->get_type() == TV_OBJ3D_HEIGHTFIELD ) { ((Heightfield*)obj)->set_filename(of->fname); delete of; }*/ } if (( pid = fork() ) < 0 ) app_fatal_err( N_("Scene pack export fork error") ); if ( pid == 0 ) { if ( !chdir(tmp_dir) ) { if ( execve( *args, args, app_ref->envp ) == -1) { printf("execve failed!\n"); fflush(stdout); } } exit(1); } delete exp_name; delete pov_name; delete ini_name; delete tvs_name; delete tmp_fname2; free(tmp_fname); for ( n = 5 ; n < args_cnt - 1 ; n++ ) { free(args[n]); } interf->set_hourglass( false ); g_free (fname); } gtk_widget_destroy( filebox ); } //******************************************* // Save //******************************************* void Scene::save() { if ( ! strcmp( def_filename, filename ) ) { save_as(); return; } ofstream file( filename, ios::out ); if ( file == NULL ) { app_warning( _("Cannot open file : "), filename ); return; } file.setf( ios::fixed, ios::floatfield ); // Statistics & progress bar INTERF_DEF interf->set_hourglass( true ); interf->set_status( _(" Saving..." ) ); save_file_state = 0; save_file_size = texlist->get_size() + objlist->get_size(); file << "TRUEVISION SCENE"; file << "\nVERSION " << VERSION; interf->save( file ); POVFE_DEF povfe->save( file ); texlist->save( file ); objlist->save( file ); file.close(); modified = false; set_win_title(); save_widgets_active( FALSE ); interf->set_progress( 0 ); interf->clear_status(); save_file_state = -1; interf->set_hourglass( false ); } void Scene::set_save_progress() { if ( save_file_state == -1 ) return; save_file_state++; float val = (float)save_file_state / (float)save_file_size; INTERF_DEF interf->set_progress( val ); } void Scene::save_as() { INTERF_DEF filebox = gtk_file_chooser_dialog_new( _("Save as..."), (GtkWindow*)interf->get_gtkwin(), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); if ( filename != NULL ) gtk_file_chooser_set_filename( GTK_FILE_CHOOSER(filebox), filename ); 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 ) return; ifstream file( fname ); if ( file ) { file.close(); 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 ) { g_free( fname ); interf->set_hourglass( false ); gtk_widget_destroy( filebox ); return; } } set_filename( fname ); save(); interf->recent_file_push( fname ); store_default_path( fname ); g_free (fname); } gtk_widget_destroy( filebox ); } //**************************************** // New //**************************************** void Scene::new_scene() { if ( modified ) { GtkWidget *dialog = gtk_message_dialog_new ( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("Current scene is unsaved, close anyway ?")); gint button = gtk_dialog_run( GTK_DIALOG(dialog)); gtk_widget_destroy( dialog ); if ( button == GTK_RESPONSE_NO ) return; } clear_scene(); modified = false; filename = NULL; set_filename( def_filename ); objlist->new_scene(); save_widgets_active( FALSE ); } void Scene::clear_scene() { INTERF_DEF interf->set_hourglass( true ); texlist->clear(); objlist->clear(); interf->clear(); POVFE_DEF povfe->reset_defaults(); UNDO_DEF undoman->init(); interf->set_hourglass( false ); } //*************************************** // Load //*************************************** void Scene::load_as() { GtkFileFilter *filter1 = gtk_file_filter_new(); gtk_file_filter_add_pattern( filter1, "*.tvs" ); gtk_file_filter_set_name( filter1, "Truevision scene file" ); GtkFileFilter *filter2 = gtk_file_filter_new(); gtk_file_filter_add_pattern( filter2, "*.*" ); gtk_file_filter_set_name( filter2, "All files" ); INTERF_DEF filebox = gtk_file_chooser_dialog_new( _("Open..."), (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 ); interf->set_hourglass( false ); gtk_widget_destroy( filebox ); return; } load( fname ); g_free (fname); } gtk_widget_destroy( filebox ); } void Scene::load( gchar *gname ) { VMAN_DEF INTERF_DEF interf->set_hourglass( true ); char *fname = new char[ strlen(gname) + 1 ]; strcpy( fname, gname ); store_default_path( gname ); ifstream file( fname, ios::binary ); if ( file == NULL ) { app_warning( _("Cannot open : "), fname ); delete fname; interf->recent_file_pop( gname ); interf->set_hourglass( false ); return; } if ( ! tvio_check_file_sig( file, "TRUEVISION SCENE" ) ) { app_warning( _("File type unknown : "), fname ); file.close(); delete fname; interf->recent_file_pop( gname ); interf->set_hourglass( false ); return; } tvio_get_soft_version( file ); if ( modified ) { GtkWidget *dialog = gtk_message_dialog_new ( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("Current scene is unsaved, close anyway ?")); gint button = gtk_dialog_run( GTK_DIALOG(dialog)); gtk_widget_destroy( dialog ); if ( button == GTK_RESPONSE_NO ) { interf->set_hourglass( false ); return; } } // Statistics interf->set_status( _(" Loading...") ); file.seekg( 0, ios::end ); load_file_size = file.tellg(); file.seekg( 0, ios::beg ); // Clear scene texlist->clear(); objlist->clear(); POVFE_DEF UNDO_DEF undoman->init(); povfe->reset_defaults(); invalid_font_path = false; // Load objects char * tag = NULL; do { tag = tvio_get_next_tag( file ); set_load_progress( file ); if ( tag == NULL ) { break; } if( interf->load( file, tag ) ) continue; if( povfe->load( file, tag ) ) continue; if( texlist->load( file, tag ) ) continue; if( objlist->load( file, tag ) ) continue; tvio_skip_section(file ); } while ( tag != NULL ); file.close(); modified = false; set_filename( fname ); delete fname; save_widgets_active( FALSE ); interf->clear_status(); interf->set_progress( 0 ); interf->recent_file_push( gname ); load_file_size = -1; //vmanager->invalidate(); vmanager->refresh(); interf->set_hourglass( false ); while ( gtk_events_pending() ) gtk_main_iteration(); //interf->jitter(); gtk_widget_queue_draw( interf->get_gtkwin() ); // If an invalid path to a font file was detected, warn the user if ( invalid_font_path ) { app_warning( "Scene uses font(s) that was not found on system, default font used instead" ); } } void Scene::set_load_progress( ifstream & file ) { if ( load_file_size == -1 ) return; int state = file.tellg(); float val = (float)state / (float)load_file_size; if ( val > 1.0 || val < 0 ) return; INTERF_DEF interf->set_progress( val ); } void Scene::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'; }