//***************************************************************************************** // Truevision - a 3d modeler for gnome and povray // // bicubic.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/bicubic.h" #include "include/viewmanager.h" #include "include/objectlist.h" #include "include/tvio.h" #include "include/preferences.h" #include "include/utils3d.h" float default_points[16][3] = { {0, 0, -.2}, {.1, 0, 0}, {.2, 0, 0}, {.3, 0,.2}, {0, .1, 0}, {.1, .1, 0}, {.2, .1, 0}, {.3, .1, 0}, {0, .2, 0}, {.1, .2, 0}, {.2, .2, 0}, {.3, .2, 0}, {0, .3, -.2}, {.1, .3, 0}, {.2, .3, 0}, {.3, .3, .2} }; /* float default_points[16][3] = { {-0.3, -0.3, -.1}, {-.1, -.3, .1}, {.1, -.3, .2}, {.3, -.3,-.1}, {-.3, -.1, -.3}, {-.1, -.1, .2}, {.1 -.1, -.1}, {.3, -.1, .1}, {-.3, .1, -.1}, {-.1, .1, -.1}, {.1, .1, .1}, {.3, .1, -.1}, {-.3, .3, -.2}, {-.1, .3, .1}, {.1, .3, .3}, {.3, .3, .1} };*/ //************************************** // Bicubic - Constructeur //************************************** Bicubic::Bicubic( app_objs *appref ) : Object3D_with_material( appref ) { type = TV_OBJ3D_BICUBIC; category = TV_OBJ3D_OBJECTS; set_name( "Bicubic Patch" ); patch_edit_box = NULL; in_undo = false; in_update = false; // Initialize control points for ( int i = 0 ; i < 16 ; i++ ) { control_points[i][0] = default_points[i][0]; control_points[i][1] = default_points[i][1]; control_points[i][2] = default_points[i][2]; } // Base location = new ObjParam_point( N_("Location"), "LOC", NULL, app_ref, true ); location->set( 0, 0, 0 ); size = new ObjParam_scale( N_("Size"), "SIZE", NULL, app_ref, true ); size->set( 1, 1, 1 ); rotation = new ObjParam_rotation( N_("Rotation"), "ROT", NULL, app_ref, true ); rotation->set( 0, 0, 0 ); edit = new ObjParam_bool_activator( N_("Edit"), "EDIT", N_("Edit Bicubic"), app_ref, true, true ); flatness = new ObjParam_float( N_("Flatness"), "FLATN", NULL, app_ref, false, 0 ); flatness->set_range( 1, 0, 0.01, 5 ); preprocess = new ObjParam_bool( N_("Preprocess"), "PREP", NULL, app_ref, false, true ); ustep = new ObjParam_int( N_("U Step"), "USTEP", NULL, app_ref, false, 4 ); ustep->set_range( 10, 1, 1 ); vstep = new ObjParam_int( N_("V Step"), "VSTEP", NULL, app_ref, false, 4 ); vstep->set_range( 10, 1, 1 ); current_point_num = new ObjParam_int( N_("Point #"), "PNUM", NULL, app_ref, true, 1 ); current_point_num->set_range( 16, 1, 1 ); current_point_num->set_send_undo( false ); current_point = new ObjParam_point( N_("Position"), "POS", NULL, app_ref, true ); current_point->set_send_undo( false ); } Bicubic::Bicubic( Bicubic & ref ) : Object3D_with_material( ref ) { in_undo = false; patch_edit_box = NULL; in_update = false; location = new ObjParam_point( *ref.location ); size = new ObjParam_scale( *ref.size ); rotation = new ObjParam_rotation( *ref.rotation ); edit = new ObjParam_bool_activator( *ref.edit ); current_point_num = new ObjParam_int( *ref.current_point_num ); current_point = new ObjParam_point( *ref.current_point ); flatness = new ObjParam_float( *ref.flatness ); preprocess = new ObjParam_bool( *ref.preprocess ); ustep = new ObjParam_int( *ref.ustep ); vstep = new ObjParam_int( *ref.vstep ); // Copy control points for ( int i = 0 ; i < 16 ; i++ ) { control_points[i][0] = ref.control_points[i][0]; control_points[i][1] = ref.control_points[i][1]; control_points[i][2] = ref.control_points[i][2]; } } Bicubic::~Bicubic() { delete location; delete size; delete rotation; delete edit; delete flatness; delete preprocess; delete ustep; delete vstep; delete current_point_num; delete current_point; } //************************************** // Display // Dessin de la boite //************************************** /*tv_matrix Bmat = { { -0.166666666, 0.5, -0.5, 0.1666666666 }, { 0.5, -1, 0.5, 0 }, { -0.5, 0, 0.5, 0 }, { 0.16666666, 0.6666666, 0.166666, 0 } }; */ tv_matrix Bmat = { { -1, 3, -3, 1 }, { 3, -6, 3, 0 }, { -3, 3, 0, 0 }, { 1, 0, 0, 0 } }; void Bicubic::display( glview *view, bool set_col ) { if ( hidden->value() ) return; if ( location->changed() || size->changed() || rotation->changed() || edit->changed() || current_point_num->changed() \ || current_point->changed() ) list.invalidate(); OBJLIST_DEF PREF_DEF int quality = 6 + pref->preview_quality->value()*4; // creation de la liste si necessaire set_color(); list.begin(); glPushMatrix(); // Position et direction gfloat x1, y1, z1; gfloat x2, y2, z2; location->get( x1, y1, z1 ); glTranslatef( x1, y1, z1 ); rotation->gl_rotate(); size->get( x2, y2, z2 ); glScalef( x2, y2, z2 ); int mode; glGetIntegerv( GL_RENDER_MODE, &mode ); if ( edit->value() ) { // Draw control points pick_name = -1; int selected_point = current_point_num->value() - 1; glPointSize( 4 ); for ( int i = 0 ; i < 16 ; i++ ) { int pick = objlist->get_pick_name(); if ( pick_name == -1 ) pick_name = pick; glLoadName( pick ); if ( i != selected_point ) { glBegin( GL_POINTS ); glVertex3f( control_points[i][0], control_points[i][1], control_points[i][2] ); glEnd(); } else { glPointSize( 6 ); glBegin( GL_POINTS ); glColor3f( 1.0, 0, 0 ); glVertex3f( control_points[selected_point][0], control_points[selected_point][1], control_points[selected_point][2] ); set_color(); glEnd(); glPointSize( 4 ); } } if ( mode != GL_SELECT ) { // Draw the hull for ( int i = 0 ; i < 3 ; i++ ) { for ( int j = 0 ; j < 3 ; j++ ) { glBegin( GL_LINE_LOOP ); int ind = i*4+j; glVertex3f( control_points[ind][0], control_points[ind][1], control_points[ind][2] ); ind += 1; glVertex3f( control_points[ind][0], control_points[ind][1], control_points[ind][2] ); ind += 4; glVertex3f( control_points[ind][0], control_points[ind][1], control_points[ind][2] ); ind -= 1; glVertex3f( control_points[ind][0], control_points[ind][1], control_points[ind][2] ); glEnd(); } } } } if ( mode != GL_SELECT ) { // Bicubic patch float points[quality][quality][3]; float normals[quality][quality][3]; tv_matrix a, aa, b, bb, c, cc, trans, tn[3]; for ( int i = 0 ; i < 4 ; i++ ) for ( int j = 0 ; j < 4 ; j++ ) { int ind = i*4+j; a[i][j] = control_points[ind][0]; b[i][j] = control_points[ind][1]; c[i][j] = control_points[ind][2]; } transpose_matrix( Bmat, trans ); prod_matrix_matrix( Bmat, a, aa ); prod_matrix_matrix( Bmat, b, bb ); prod_matrix_matrix( Bmat, c, cc ); prod_matrix_matrix( aa, trans, tn[0] ); prod_matrix_matrix( bb, trans, tn[1] ); prod_matrix_matrix( cc, trans, tn[2] ); for ( int i = 0 ; i < quality ; i++ ) { for ( int j = 0 ; j < quality ; j++ ) { float s = (float)i / (float)(quality-1); float t = (float)j / (float)(quality-1); tv_vector S = { s*s*s, s*s, s, 1 }; tv_vector T = { t*t*t, t*t, t, 1 }; tv_vector dS = { 3*s*s, 2*s, 1, 0 }; tv_vector dT = { 3*t*t, 2*t, 1, 0 }; tv_point ds, dt; tv_vector d; for ( int k = 0 ; k < 3 ; k++ ) { prod_vector_matrix( S, tn[k], d ); points[i][j][k] = prod_vector_vector( d, T ); prod_vector_matrix( dS, tn[k], d ); ds[k] = prod_vector_vector( d, T ); prod_vector_matrix( S, tn[k], d ); dt[k] = prod_vector_vector( d, dT ); } prod_vector( dt, ds, normals[i][j] ); normalize( normals[i][j] ); } } for ( int i = 0 ; i < quality-1 ; i++ ) { glBegin( GL_TRIANGLE_STRIP ); for ( int j = 0 ; j < quality ; j++ ) { glNormal3f( normals[i][j][0], normals[i][j][1], normals[i][j][2] ); glVertex3f( points[i][j][0], points[i][j][1], points[i][j][2] ); glNormal3f( normals[i+1][j][0], normals[i+1][j][1], normals[i+1][j][2] ); glVertex3f( points[i+1][j][0], points[i+1][j][1], points[i+1][j][2] ); } glEnd(); } } glPopMatrix(); list.end(); } //*********************************************** // Edit //*********************************************** void Bicubic::edit_widget( GtkWidget *wid ) { PREF_DEF bool tt = pref->tooltips->value(); // Options communes Object3D::edit_widget( wid ); // Spline edition new_frame( edit_cont, N_("Patch edition") ); edit->get_widget( frame, tt ); patch_edit_box = dlg_simple_box_frame( N_("Points edition"), frame ); new_table_no_frame( patch_edit_box, 2 ); current_point_num->get_widget( table, tt, 1 ); current_point->get_widget( table, tt, 2, sign_bicubic_current_point_changed, this ); new_table_no_frame( frame, 4 ); flatness->get_widget( table, tt, 1 ); preprocess->get_widget( table, tt, 2 ); ustep->get_widget( table, tt, 3 ); vstep->get_widget( table, tt, 4 ); // Options de geometrie new_table( edit_cont, N_("General settings"), 3 ); location->get_widget( table, tt, 1 ); size->get_widget( table, tt, 2 ); rotation->get_widget( table, tt, 3 ); get_texture_widgets( edit_cont, tt ); gtk_widget_show_all( wid ); edit->set_target( patch_edit_box ); edit->toggle(); current_point_num->connect_signal( GTK_SIGNAL_FUNC(sign_bicubic_current_point_num_changed), this ); current_point_num_changed(); } //*********************************************** // Mouse drag //*********************************************** void Bicubic::mouse_drag( struct drag_info *drag ) { VMAN_DEF OBJLIST_DEF switch( vmanager->get_pointer_mode() ) { case TV_PMODE_SELECT: case TV_PMODE_TRANSLATE: if ( edit->value() ) current_point->mouse_drag( drag ); else location->mouse_drag( drag ); break; case TV_PMODE_SCALE: { size->mouse_drag( drag ); } break; case TV_PMODE_ROTATE: { rotation->mouse_drag( drag ); break; } case TV_PMODE_CUSTOM: ((ObjParam_point*)(objlist->get_current_param()))->mouse_drag( drag ); break; default: break; } } //*********************************************** // Pref_changed //*********************************************** void Bicubic::pref_changed() { Object3D::pref_changed(); location->pref_changed(); size->pref_changed(); rotation->pref_changed(); edit->pref_changed(); current_point_num->pref_changed(); current_point->pref_changed(); flatness->pref_changed(); preprocess->pref_changed(); ustep->pref_changed(); vstep->pref_changed(); } //*********************************************** // Destroy editor //*********************************************** void Bicubic::destroy_editor() { Object3D::destroy_editor(); location->clear_widget(); size->clear_widget(); texture->clear_widget(); rotation->clear_widget(); edit->clear_widget(); current_point_num->clear_widget(); current_point->clear_widget(); flatness->clear_widget(); preprocess->clear_widget(); ustep->clear_widget(); vstep->clear_widget(); if ( patch_edit_box != NULL ) patch_edit_box = NULL; } //*********************************************** // Output to povray //*********************************************** void Bicubic::output_to_povray_pass1( ofstream & file ) { file << "\n\n// Bicubic : " << name->value(); file << "\n#declare "; get_underscore_name( file ); file << " ="; file << "\nbicubic_patch {"; if ( preprocess->value() ) file << "\n\ttype 1"; else file << "\n\ttype 0"; file << "\n\tflatness " << flatness->value(); file << "\n\tu_steps " << ustep->value(); file << "\n\tv_steps " << vstep->value(); file << "\n\t"; for ( int i = 0 ; i < 4 ; i++ ) { for ( int j = 0 ; j < 4 ; j++ ) { int ind = i*4+j; file << "<" << control_points[ind][0] << "," << control_points[ind][1] << "," << -control_points[ind][2]; if ( ind != 15 ) file << ">,"; else file << ">"; } file << "\n\t"; } float a, b, c, x, y, z; Object3D_with_material::output_to_povray_pass1( file ); file << "\n\t"; size->get( a, b, c ); file << "scale <" << a << "," << b << "," << c << ">"; rotation->output_to_povray( file ); location->get( x, y, z ); file << "\n\ttranslate <" << x << "," << y << "," << -z << "> \n\t"; file << "\n}"; } //*********************************************** // Save & load //*********************************************** void Bicubic::save( ofstream & file ) { file << "\nBICUBIC{\n"; save_basics( file ); location->save( file ); size->save( file ); rotation->save( file ); texture->save( file ); edit->save( file ); flatness->save( file ); preprocess->save( file ); ustep->save( file ); vstep->save( file ); file << "\n\tCONTROLS{"; for ( int i = 0 ; i < 16 ; i++ ) file << ' ' << control_points[i][0] << ' ' << control_points[i][1] << ' ' << control_points[i][2]; file << " }\n}"; } bool Bicubic::load( ifstream & file, char *ltag ) { if ( strcmp( ltag, "BICUBIC" ) ) return false; set_load_progress( file ); char * tag = NULL; do { tag = tvio_get_next_tag( file ); if ( tag == NULL ) break; if ( load_basics( file, tag ) ) continue; if ( location->load( file, tag ) ) continue; if ( size->load( file, tag ) ) continue; if ( rotation->load( file, tag ) ) continue; if ( edit->load( file, tag ) ) continue; if ( flatness->load( file, tag ) ) continue; if ( preprocess->load( file, tag ) ) continue; if ( ustep->load( file, tag ) ) continue; if ( vstep->load( file, tag ) ) continue; if ( ! strcmp( "CONTROLS", tag ) ) { char ch = 0; while ( ch == 0 || ch == '{' ) ch = file.get(); char line[150]; for ( int i = 0 ; i < 16 ; i++ ) for ( int j = 0 ; j < 3 ; j++ ) { char ch = 0; int ind = 0; while ( ch != ' ') ch = line[ind++] = file.get(); line[ind]= '\0'; sscanf( line, "%f", &control_points[i][j] ); //cout << "\nscanning [" << i << "][" << j << "] ->" << line << " = " << control_points[i][j]; cout.flush(); } //tvio_skip_section(file ); } tvio_skip_section(file ); } while ( tag != NULL ); current_point_num->set_range( 16, 1, 1 ); return true; } //******************************************************* // Spline Edition //******************************************************* void Bicubic::current_point_num_changed() { if ( patch_edit_box == NULL ) return; if ( current_point_num->in_update ) return; if ( in_update ) return; in_update = true; int i = current_point_num->value() - 1; current_point->set( control_points[i][0], control_points[i][1], control_points[i][2] ); current_point->update_widget(); current_point->unchange(); current_point_num->update_widget(); in_update = false; } void Bicubic::current_point_changed() { if ( in_update ) return; if ( patch_edit_box == NULL ) return; if ( current_point->in_update ) return; int i = current_point_num->value() - 1; float x, y, z; if ( current_point->change_is_reversible() ) push_undo_item(); if ( !current_point->is_in_drag() ) push_undo_item(); current_point->flush(); current_point->get( x, y, z ); control_points[i][0] = x; control_points[i][1] = y; control_points[i][2] = z; list.invalidate(); VMAN_DEF vmanager->refresh(); } bool Bicubic::pick_test( int pname ) { int selected_point = current_point_num->value() - 1; if ( edit->value() ) { if ( ( pname >= pick_name ) && ( pname <= pick_name + 16 ) ) { int pointed = pname - pick_name; current_point_num->set( pointed + 1 ); if ( selected_point != current_point_num->value() -1 ) { current_point_num_changed(); } list.invalidate(); VMAN_DEF vmanager->refresh(); return true; } else return false; } else { if ( pname == pick_name ) return true; else return false; } return false; } void Bicubic::undo( Object3D *copy ) { in_undo = true; Bicubic *changed = (Bicubic*)copy; float temp[16][3]; for ( int i = 0 ; i < 16 ; i++ ) { temp[i][0] = control_points[i][0]; temp[i][1] = control_points[i][1]; temp[i][2] = control_points[i][2]; control_points[i][0] = changed->control_points[i][0]; control_points[i][1] = changed->control_points[i][1]; control_points[i][2] = changed->control_points[i][2]; changed->control_points[i][0] = temp[i][0]; changed->control_points[i][1] = temp[i][1]; changed->control_points[i][2] = temp[i][2]; } VMAN_DEF vmanager->refresh(); in_undo = false; }