//***************************************************************************************** // Truevision - a 3d modeler for gnome and povray // // texnormal.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/texnormal.h" #include "include/dlgutils.h" #include "include/tvio.h" #include "include/matlist.h" #include "include/preferences.h" //************************************** // Définitions //************************************** const int normal_type_num = 4; const char *normal_type_list[normal_type_num] = { N_("Plain"), N_("Normal list"), N_("Normal map"), N_("Bump map") }; //************************************** // Constructeurs & Destructeurs //************************************** PovTexNormal::PovTexNormal( app_objs *appref, char *tagname, bool mother ) : MaterialItem( app_ref, tagname ) { set_name( _("Normal") ); item_type = TV_MITEM_NORMAL; is_mother = mother; changing_box1 = changing_box2 = NULL; normal1 = normal2 = normal3 = NULL; pattern = NULL; blendmod = NULL; blockpattern = NULL; mapedit = NULL; bumpmap = new TvWidget_bumpmap( N_("Bump map"), "BUMPMAP", NULL, app_ref ); use = new TvWidget_bool_activator( N_("Use normal"), "USED", NULL, app_ref, !is_mother ); type = new TvWidget_option_combo( N_("Type"), "TYPE", NULL, app_ref ); type->set_list( normal_type_list, normal_type_num, 0 ); bump_depth = new TvWidget_float( N_("Bump_depth"), "BUMP", NULL, app_ref, 0.5 ); bump_depth->set_range( 100, -100, 0.1, 3 ); no_bump_scale = new TvWidget_bool( N_("No bump scale"), "NOSCALE", NULL, app_ref, false ); transform = new TvWidget_transformation_rb( _("Transformation"), "TRANSFO", NULL, app_ref ); noise = new TvWidget_noise_rb( N_("Noise"), "NOISE", NULL, app_ref ); warp = new TvWidget_warp_rb( N_("Warp"), "WARP", NULL, app_ref ); slopemap = new TvWidget_slopemap_rb( N_("Slope map"), "SMAP", NULL, app_ref ); accuracy = new TvWidget_float( N_("Accuracy"), "ACCUR", NULL, app_ref, 0.02 ); accuracy->set_range( 100, 0, 0.01, 3 ); } PovTexNormal::PovTexNormal( PovTexNormal & ref ) : MaterialItem( ref ) { if ( &ref == NULL ) return; set_name( ref.get_name() ); item_type = TV_MITEM_NORMAL; is_mother = true; changing_box1 = changing_box2 = NULL; use = new TvWidget_bool_activator( *ref.use ); type = new TvWidget_option_combo( *ref.type ); bump_depth = new TvWidget_float( *ref.bump_depth ); no_bump_scale = new TvWidget_bool( *ref.no_bump_scale ); transform = new TvWidget_transformation_rb( *ref.transform ); noise = new TvWidget_noise_rb( *ref.noise ); warp = new TvWidget_warp_rb( *ref.warp ); slopemap = new TvWidget_slopemap_rb( *ref.slopemap ); accuracy = new TvWidget_float( *ref.accuracy ); bumpmap = new TvWidget_bumpmap( *ref.bumpmap ); if ( ref.pattern != NULL ) pattern = new TvWidget_blendmap( *ref.pattern ); else pattern = NULL; if ( ref.mapedit != NULL ) mapedit = new TvWidget_map_editor( *ref.mapedit ); else mapedit = NULL; if ( ref.blendmod != NULL ) blendmod = new TvWidget_blendmap_mod( *ref.blendmod ); else blendmod = NULL; if ( ref.blockpattern != NULL ) blockpattern = new TvWidget_blockpattern( *ref.blockpattern ); else blockpattern = NULL; if ( ref.normal1 != NULL ) normal1 = new PovTexNormal( *ref.normal1 ); else normal1 = NULL; if ( ref.normal2 != NULL ) normal2 = new PovTexNormal( *ref.normal2 ); else normal2 = NULL; if ( ref.normal3 != NULL ) normal3 = new PovTexNormal( *ref.normal3 ); else normal3 = NULL; } PovTexNormal::~PovTexNormal() { delete use; delete type; delete bump_depth; delete no_bump_scale; delete transform; delete noise; delete warp; delete slopemap; delete accuracy; delete bumpmap; if ( pattern != NULL ) delete pattern; if ( blockpattern != NULL ) delete blockpattern; if ( mapedit != NULL ) delete mapedit; if ( blendmod != NULL ) delete blendmod; if ( normal1 != NULL ) { delete normal1; delete normal2; delete normal3; } } //************************************** // Editeur //************************************** void PovTexNormal::edit_widget( GtkWidget *box ) { PREF_DEF bool tt = pref->tooltips->value(); MaterialItem::edit_widget( box, _("Normal") ); activated_box = gtk_vbox_new( FALSE, 0 ); use->set_target( activated_box ); if ( is_mother ) use->get_widget_no_toggle( edit_cont, tt ); gtk_box_pack_start( GTK_BOX(edit_cont), activated_box, TRUE, TRUE, 0 ); type->get_widget( activated_box, tt ); type->connect_signal( GTK_SIGNAL_FUNC(sign_normal_type_changed), this ); set_changing_box(); gtk_widget_show_all( widget ); if ( is_mother ) use->update_widget(); } //-------------------- // Add to tree //-------------------- void PovTexNormal::add_to_tree( GtkTreeView *view, GtkTreeStore *store, GtkTreeSelection *selection, GtkTreeIter *parent, GtkTreeIter *sibling ) { MaterialItem::add_to_tree( view, store, selection, parent, sibling ); if ( normal1 != NULL ) { normal1->add_to_tree( view, store, selection, &node_iter ); normal2->add_to_tree( view, store, selection, &node_iter ); if ( blockpattern->value() == 2 ) normal3->add_to_tree( view, store, selection, &node_iter ); } if ( mapedit != NULL ) mapedit->add_to_tree( view, store, selection, &node_iter ); set_node_state(); } void PovTexNormal::remove_from_tree() { if ( normal1 != NULL ) normal1->remove_from_tree(); if ( normal2 != NULL ) normal2->remove_from_tree(); if ( normal3 != NULL ) normal3->remove_from_tree(); if ( mapedit != NULL ) mapedit->remove_from_tree(); MaterialItem::remove_from_tree(); } void PovTexNormal::save_node_state() { if ( normal1 != NULL ) normal1->save_node_state(); if ( normal2 != NULL ) normal2->save_node_state(); if ( normal3 != NULL ) normal3->save_node_state(); if ( mapedit != NULL ) mapedit->save_node_state(); } //-------------------- // Type changed //-------------------- void PovTexNormal::type_changed() { type->flush(); if ( normal1 != NULL && type->value() != 1 ) { normal1->remove_from_tree(); normal2->remove_from_tree(); normal3->remove_from_tree(); delete normal1; normal1 = NULL; delete normal2; delete normal3; } if ( normal1 == NULL && type->value() == 1 ) { normal1 = new PovTexNormal( app_ref, NULL, false ); normal2 = new PovTexNormal( app_ref, NULL, false ); normal3 = new PovTexNormal( app_ref, NULL, false ); normal1->add_to_tree( tree_view, tree_store, tree_selection, &node_iter ); normal2->add_to_tree( tree_view, tree_store, tree_selection, &node_iter ); } if ( pattern != NULL ) { delete pattern; pattern = NULL; } if ( blockpattern != NULL ) { delete blockpattern; blockpattern = NULL; } if ( mapedit != NULL ) { mapedit->remove_from_tree(); delete mapedit; mapedit = NULL; delete blendmod; blendmod = NULL; } set_changing_box(); } //-------------------- // Set changing box //-------------------- void PovTexNormal::set_changing_box() { PREF_DEF bool tt = pref->tooltips->value(); // Changing box 1 if ( changing_box1 != NULL ) gtk_widget_destroy( changing_box1 ); bump_depth->clear_widget(); no_bump_scale->clear_widget(); changing_box1 = gtk_vbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(activated_box), changing_box1, FALSE, FALSE, 0 ); GtkWidget *table = new_table_no_frame( changing_box1, 3 ); bump_depth->get_widget( table, tt, 1 ); no_bump_scale->get_widget( table, tt, 2 ); accuracy->get_widget( table, tt, 3 ); switch ( type->value() ) { case 0: if ( pattern == NULL ) pattern = new TvWidget_blendmap( N_("Pattern"), "BMAP", NULL, app_ref, true ); pattern->get_widget( changing_box1, tt ); break; case 1: { if ( blockpattern == NULL ) blockpattern = new TvWidget_blockpattern( N_("Block Pattern"), "BLKPAT", NULL, app_ref ); blockpattern->get_widget( changing_box1, tt ); blockpattern->connect_signal( sign_normblocktype_changed, this ); set_normblock_items(); } break; case 2: { if ( pattern == NULL ) pattern = new TvWidget_blendmap( N_("Map definition"), "BMAP", NULL, app_ref ); pattern->get_widget( changing_box1, tt ); if ( mapedit == NULL ) { mapedit = new TvWidget_map_editor( N_("Map editor"), "MAPEDIT", NULL, app_ref, mapedit_feeder_normal, this ); MapItem_normal *norm = new MapItem_normal( 0.0, 0, app_ref ); mapedit->add( norm ); norm = new MapItem_normal( 1.0, 255, app_ref ); mapedit->add( norm ); mapedit->add_to_tree( tree_view, tree_store, tree_selection, &node_iter ); } mapedit->get_widget( changing_box1, tt ); } break; case 3: { // if ( bumpmap == NULL ) bumpmap = new TvWidget_bumpmap( N_("Bump map"), "BUMPMAP", NULL, app_ref ); bumpmap->get_widget( changing_box1, tt ); } break; } // Changing box 2 if ( changing_box2 != NULL ) gtk_widget_destroy( changing_box2 ); changing_box2 = gtk_vbox_new( FALSE, 0 ); gtk_box_pack_start( GTK_BOX(activated_box), changing_box2, FALSE, FALSE, 0 ); transform->get_widget_rb( changing_box2, tt ); noise->get_widget_rb( changing_box2, tt ); warp->get_widget_rb( changing_box2, tt ); if ( type->value() == 0 || type->value() == 2 ) slopemap->get_widget_rb( changing_box2, tt ); if ( type->value() == 2 ) { if ( blendmod == NULL ) blendmod = new TvWidget_blendmap_mod( N_("Modifiers"), "BMAPMOD", NULL, app_ref ); blendmod->get_widget( changing_box2, tt ); } gtk_widget_show_all( changing_box1 ); gtk_widget_show_all( changing_box2 ); } void PovTexNormal::destroy_widget() { MaterialItem::destroy_widget(); use->clear_widget(); type->clear_widget(); bump_depth->clear_widget(); no_bump_scale->clear_widget(); transform->clear_widget(); noise->clear_widget(); warp->clear_widget(); slopemap->clear_widget(); accuracy->clear_widget(); if ( pattern != NULL ) pattern->clear_widget(); if ( blockpattern != NULL ) blockpattern->clear_widget(); if ( mapedit != NULL ) mapedit->clear_widget(); bumpmap->clear_widget(); if ( blendmod != NULL ) blendmod->clear_widget(); changing_box1 = changing_box2 = NULL; } void PovTexNormal::flush() { use->flush(); type->flush(); bump_depth->flush(); no_bump_scale->flush(); transform->flush(); noise->flush(); warp->flush(); accuracy->flush(); slopemap->flush(); if ( pattern != NULL ) pattern->flush(); if ( blockpattern != NULL ) blockpattern->flush(); if ( mapedit != NULL ) mapedit->flush(); bumpmap->flush(); if ( blendmod != NULL ) blendmod->flush(); } void PovTexNormal::set_normblock_items() { if ( normal3 == NULL ) return; blockpattern->flush(); if ( blockpattern->value() == 2 ) normal3->add_to_tree( tree_view, tree_store, tree_selection, &node_iter ); else normal3->remove_from_tree(); } //************************************** // Output / Export //************************************** void PovTexNormal::output_to_povray( ofstream & file, bool in_map ) { if ( !use->value() ) return; if ( !in_map ) file << "\n\t\tnormal {\n\t\t\t"; switch( type->value() ) { case 0: { pattern->output_to_povray( file ); int pty = pattern->get_type(); if ( pty != 3 && pty != 6 && pty != 16 && pty != 20 && pty != 22 ) slopemap->output_to_povray( file ); } break; case 1: { blockpattern->output_to_povray( file ); file << "\n\t\t\t\t"; normal1->output_to_povray( file ); file << ",\n\t\t\t\t"; normal2->output_to_povray( file ); if ( blockpattern->value() == 2 ) { file << ",\n\t\t\t\t"; normal3->output_to_povray( file ); } blockpattern->output_to_povray_options( file ); } break; case 2: { pattern->output_to_povray( file ); file << "\n\t\t\tnormal_map {"; mapedit->output_to_povray( file ); file << "\n\t\t\t}\n\t\t\t"; if ( blendmod != NULL ) blendmod->output_to_povray( file ); } break; case 3: bumpmap->output_to_povray( file ); break; } file << "\n\t\t\tbump_size "; bump_depth->output_to_povray( file ); file << "\n\t\t\taccuracy "; accuracy->output_to_povray( file ); if ( no_bump_scale->value() ) file << "\n\t\tno_bump_scale"; file << "\n\t\t\t"; noise->output_to_povray( file ); file << "\n\t\t\t"; warp->output_to_povray( file ); file << "\n\t\t\t"; slopemap->output_to_povray( file ); file << "\n\t\t\t"; transform->output_to_povray( file ); if ( !in_map ) file << "\n\t\t}"; } //************************************** // SAve //************************************** void PovTexNormal::save( ofstream & file ) { if ( !use->value() ) return; file << "NORMAL{\n"; use->save( file ); type->save( file ); name->save( file ); expand->save( file ); switch( type->value() ) { case 0: pattern->save( file ); if ( slopemap != NULL ) slopemap->save( file ); break; case 1: { blockpattern->save( file ); normal1->save( file ); normal2->save( file ); if ( blockpattern->value() == 2 ) normal3->save( file ); } break; case 2: { pattern->save( file ); mapedit->save( file ); if ( blendmod != NULL ) blendmod->save( file ); if ( slopemap != NULL ) slopemap->save( file); } break; case 3: bumpmap->save( file ); break; } bump_depth->save( file ); no_bump_scale->save( file ); accuracy->save( file ); noise->save( file ); warp->save( file ); slopemap->save( file ); transform->save( file ); file << "}\n"; } bool PovTexNormal::load( ifstream & file, char * ltag ) { if ( strcmp( "NORMAL", ltag ) ) return false; char * tag = NULL; use->set( true ); do { tag = tvio_get_next_tag( file ); if ( tag == NULL ) break; if (type->load( file , tag ) ) continue; if (bump_depth->load( file , tag ) ) continue; if (no_bump_scale->load( file , tag ) ) continue; if (accuracy->load( file , tag ) ) continue; if (noise->load( file , tag ) ) continue; if (warp->load( file , tag ) ) continue; if (slopemap->load( file , tag ) ) continue; if (transform->load( file , tag ) ) continue; if (name->load( file , tag ) ) continue; if (expand->load( file , tag ) ) continue; if (bumpmap->load( file , tag ) ) continue; if (use->load( file , tag ) ) continue; if ( !strcmp( tag, "BMAP" ) ) { if ( pattern == NULL ) pattern = new TvWidget_blendmap( _("Pattern"), "BMAP", NULL, app_ref ); pattern->load( file, tag ); continue; } if ( !strcmp( tag, "BMAPMOD" ) ) { if ( blendmod == NULL ) blendmod = new TvWidget_blendmap_mod( _("Pattern"), "BMAPMOD", NULL, app_ref ); blendmod->load( file, tag ); continue; } if ( !strcmp( tag, "BLKPAT" ) ) { if ( blockpattern == NULL ) blockpattern = new TvWidget_blockpattern( _("Block Pattern"), "BLKPAT", NULL, app_ref ); blockpattern->load( file, tag ); continue; } if ( !strcmp( tag, "NORMAL" ) ) { if ( normal1 == NULL ) { normal1 = new PovTexNormal( app_ref, NULL, false ); normal1->load( file, tag ); continue; } if ( normal2 == NULL ) { normal2 = new PovTexNormal( app_ref, NULL, false ); normal2->load( file, tag ); continue; } if ( normal3 == NULL ) { normal3 = new PovTexNormal( app_ref, NULL, false ); normal3->load( file, tag ); continue; } tvio_skip_section( file ); } if ( !strcmp( tag, "MAPEDIT" ) ) { mapedit = new TvWidget_map_editor( _("Map editor"), "MAPEDIT", NULL, app_ref, mapedit_feeder_normal, this ); mapedit->load( file, tag ); continue; } tvio_skip_section( file ); } while( tag != NULL ); return true; } bool PovTexNormal::paste( MaterialItem *item ) { if ( item->get_type() != TV_MITEM_NORMAL ) return false; set_name( item->get_name() ); PovTexNormal *norm = (PovTexNormal*)item; if ( normal1 != NULL ) { delete normal1; normal1 = NULL; } if ( normal2 != NULL ) { delete normal2; normal2 = NULL; } if ( normal3 != NULL ) { delete normal3; normal3 = NULL; } if ( pattern != NULL ) { delete pattern; pattern = NULL; } if ( blendmod != NULL ) { delete blendmod; blendmod = NULL; } if ( blockpattern != NULL ) { delete blockpattern; blockpattern = NULL; } if ( mapedit != NULL ) { delete mapedit; mapedit = NULL; } if ( GTK_IS_WIDGET(widget) ) { gtk_widget_destroy( edit_cont ); use->clear_widget(); type->clear_widget(); transform->clear_widget(); noise->clear_widget(); warp->clear_widget(); slopemap->clear_widget(); bump_depth->clear_widget(); } use->copy( norm->use ); type->copy( norm->type ); transform->copy( norm->transform ); noise->copy( norm->noise ); warp->copy( norm->warp ); slopemap->copy( norm->slopemap ); bump_depth->copy( norm->bump_depth ); no_bump_scale->copy( norm->no_bump_scale ); accuracy->copy( norm->no_bump_scale ); if ( norm->normal1 != NULL ) normal1 = new PovTexNormal( *norm->normal1 ); else normal1 = NULL; if ( norm->normal2 != NULL ) normal2 = new PovTexNormal( *norm->normal2 ); else normal2 = NULL; if ( norm->normal3 != NULL ) normal3 = new PovTexNormal( *norm->normal3 ); else normal3 = NULL; if ( norm->pattern != NULL ) pattern = new TvWidget_blendmap( *norm->pattern ); if ( norm->blendmod != NULL ) blendmod = new TvWidget_blendmap_mod( *norm->blendmod ); if ( norm->blockpattern != NULL ) blockpattern = new TvWidget_blockpattern( *norm->blockpattern ); if ( norm->mapedit != NULL ) mapedit = new TvWidget_map_editor( *norm->mapedit ); //TEXLIST_DEF GtkTreeIter *old_node = gtk_tree_iter_copy( &(norm->node_iter) ); add_to_tree( tree_view, tree_store, tree_selection, tree_node_parent, old_node ); gtk_tree_selection_unselect_iter( tree_selection, &node_iter ); select_tree_row(); gtk_tree_iter_free( old_node ); return true; } //************************************** // Normal map //************************************** int MapItem_normal::obj_count = 1; MapItem *mapedit_feeder_normal( gpointer data ) { return (MapItem*)( new MapItem_normal( 0, 0, ((PovTexNormal*)data)->app_ref ) ); } MapItem_normal::MapItem_normal( float val, guint8 c, app_objs *appref ) : MapItem( _("Normal"), val ) { color[0]=color[1]=color[2]=c; color[3]=255; normal = new PovTexNormal( appref, NULL, false ); char text[25]; sprintf( text, "Map normal #%u", obj_count++ ); normal->set_name( text ); } MapItem_normal::MapItem_normal( MapItem_normal & ref ) : MapItem( ref ) { for ( int i = 0 ; i < 3 ; i ++ ) color[i] = ref.color[i]; color[3]=255; normal = new PovTexNormal( *ref.normal ); normal->set_name( ref.normal->get_name() ); } void MapItem_normal::save( ofstream & file ) { MapItem::save( file ); normal->save( file ); file << "} "; } bool MapItem_normal::load( ifstream & file, char *ltag ) { if ( strcmp( "MAPITEM", ltag ) ) return false; char * tag = NULL; do { tag = tvio_get_next_tag( file ); if ( tag == NULL ) break; if ( normal->load( file , tag ) ) continue; if ( MapItem::load( file , tag ) ) continue; tvio_skip_section( file ); } while( tag != NULL ); return true; }