//***************************************************************************************** // Truevision - a 3d modeler for gnome and povray // // parametric.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/parametric.h" #include "include/viewmanager.h" #include "include/objectlist.h" #include "include/tvio.h" #include "include/preferences.h" #include "include/utils3d.h" //************************************** // Constructeur //************************************** Parametric::Parametric( app_objs *appref ) : Object3D_with_material( appref ) { type = TV_OBJ3D_PARAMETRIC; category = TV_OBJ3D_OBJECTS; set_name( "Parametric" ); // Transformation location = new ObjParam_point( N_("Translation"), "LOC", NULL, app_ref, true ); location->set( 0, 0, 0 ); size = new ObjParam_scale( N_("Scale"), "SIZE", NULL, app_ref, true ); size->set( 0.2, 0.2, 0.2 ); rotation = new ObjParam_rotation( N_("Rotation"), "ROT", NULL, app_ref, true ); rotation->set( 0, 0, 0 ); // Bounding box corner1 = new ObjParam_point( N_("Corner 1"), "CORN1", NULL, app_ref, true ); corner1->set( 1, 1, 1 ); corner2 = new ObjParam_point( N_("Corner 2"), "CORN2", NULL, app_ref, true ); corner2->set( -1, -1, -1 ); show_bb = new ObjParam_bool( N_("Show"), "BBSHOW", NULL, appref, true, true ); // Functions functionx = new ObjParam_function( N_("X Function"), "FUNCX", NULL, appref, true ); functiony = new ObjParam_function( N_("Y Function"), "FUNCY", NULL, appref, true ); functionz = new ObjParam_function( N_("Z Function"), "FUNCZ", NULL, appref, true ); umin = new ObjParam_float( N_("U min"), "UMIN", NULL, app_ref, true ); umin->set_range( 100, -100, 0.1, 5 ); umax = new ObjParam_float( N_("U max"), "UMAX", NULL, app_ref, true ); umax->set_range( 100, -100, 0.1, 5 ); vmin = new ObjParam_float( N_("V min"), "VMIN", NULL, app_ref, true ); vmin->set_range( 100, -100, 0.1, 5 ); vmax = new ObjParam_float( N_("V max"), "VMAX", NULL, app_ref, true ); vmax->set_range( 100, -100, 0.1, 5 ); preview = new ObjParam_bool( N_("Preview"), "PREV", NULL, appref, true, true ); accuracy = new ObjParam_float( N_("Accuracy"), "ACC", NULL, appref, false, 0.001); accuracy->set_range( 100, 0, 0.0001, 6 ); max_gradient = new ObjParam_float( N_("Max gradient"), "MAXG", NULL, appref, false, 1.1 ); max_gradient->set_range( 10000, 0, 0.01, 5 ); // Precompute precompute_depth = new ObjParam_int( N_("Depth"), "PREDE", NULL, appref, false, 10 ); precompute_depth->set_range( 20, 0, 1 ); precompute_x = new ObjParam_bool( N_("Precompute x"), "PRECX", NULL, appref, false, false ); precompute_y = new ObjParam_bool( N_("Precompute y"), "PRECY", NULL, appref, false, false ); precompute_z = new ObjParam_bool( N_("Precompute z"), "PRECZ", NULL, appref, false, false ); } Parametric::Parametric( Parametric & ref ) : Object3D_with_material( ref ) { location = new ObjParam_point( *ref.location ); size = new ObjParam_scale( *ref.size ); rotation = new ObjParam_rotation( *ref.rotation ); corner1 = new ObjParam_point( *ref.corner1 ); corner2 = new ObjParam_point( *ref.corner2 ); show_bb = new ObjParam_bool( *ref.show_bb ); functionx = new ObjParam_function( *ref.functionx ); functiony = new ObjParam_function( *ref.functiony ); functionz = new ObjParam_function( *ref.functionz ); preview = new ObjParam_bool( *ref.preview ); accuracy = new ObjParam_float( *ref.accuracy ); max_gradient = new ObjParam_float( *ref.max_gradient ); umin = new ObjParam_float( *ref.umin ); umax = new ObjParam_float( *ref.umax ); vmin = new ObjParam_float( *ref.vmin ); vmax = new ObjParam_float( *ref.vmax ); precompute_depth = new ObjParam_int( *ref.precompute_depth ); precompute_x = new ObjParam_bool( *ref.precompute_x ); precompute_y = new ObjParam_bool( *ref.precompute_y ); precompute_z = new ObjParam_bool( *ref.precompute_z ); } Parametric::~Parametric() { delete location; delete size; delete rotation; delete corner1; delete corner2; delete show_bb; delete functionx; delete functiony; delete functionz; delete preview; delete accuracy; delete max_gradient; delete umin; delete umax; delete vmin; delete vmax; delete precompute_depth; delete precompute_x; delete precompute_y; delete precompute_z; } //************************************** // Display // Dessin de la boite //************************************** void Parametric::display( glview *view, bool set_col ) { if ( hidden->value() ) return; if ( location->changed() || size->changed() || rotation->changed() || corner1->changed() || corner2->changed() || show_bb->changed() \ || functionx->changed() || functiony->changed() || functionz->changed() || preview->changed() || umin->changed() || umax->changed() \ || vmin->changed() || vmax->changed() ) list.invalidate(); Object3D::display( view ); if ( set_col ) set_color(); if ( ! list.exec() ) { // mise à zero des parametres location->unchange(); size->unchange(); rotation->unchange(); corner1->unchange(); corner2->unchange(); show_bb->unchange(); functionx->unchange(); functiony->unchange(); functionz->unchange(); preview->unchange(); umin->unchange(); umax->unchange(); vmin->unchange(); vmax->unchange(); // creation de la liste si necessaire list.begin(); glPushMatrix(); // Position et direction gfloat x, y, z; gfloat a, b, c; location->get( x, y, z ); glTranslatef( x, y, z ); size->get( a, b, c ); glScalef( a, b, c ); rotation->gl_rotate(); corner1->get( a, b, c ); corner2->get( x, y, z ); // Bounding box display if requested if ( show_bb->value() ) { const float div = 4.0; float xrule = (x-a) / div ; float yrule = (y-b) / div ; float zrule = (z-c) / div ; glBegin( GL_LINES ); glVertex3f( x, y, z ); glVertex3f( x-xrule, y, z ); glVertex3f( x, y, z ); glVertex3f( x, y-yrule, z ); glVertex3f( x, y, z ); glVertex3f( x, y, z-zrule ); glVertex3f( x, y, c ); glVertex3f( x-xrule, y, c ); glVertex3f( x, y, c ); glVertex3f( x, y-yrule, c ); glVertex3f( x, y, c ); glVertex3f( x, y, c+zrule ); glVertex3f( a, y, z ); glVertex3f( a+xrule, y, z ); glVertex3f( a, y, z ); glVertex3f( a, y-yrule, z ); glVertex3f( a, y, z ); glVertex3f( a, y, z-zrule ); glVertex3f( a, y, c ); glVertex3f( a+xrule, y, c ); glVertex3f( a, y, c ); glVertex3f( a, y-yrule, c ); glVertex3f( a, y, c ); glVertex3f( a, y, c+zrule ); glVertex3f( a, b, c ); glVertex3f( a+xrule, b, c ); glVertex3f( a, b, c ); glVertex3f( a, b+yrule, c ); glVertex3f( a, b, c ); glVertex3f( a, b, c+zrule ); glVertex3f( x, b, c ); glVertex3f( x-xrule, b, c ); glVertex3f( x, b, c ); glVertex3f( x, b+yrule, c ); glVertex3f( x, b, c ); glVertex3f( x, b, c+zrule ); glVertex3f( a, b, z ); glVertex3f( a+xrule, b, z ); glVertex3f( a, b, z ); glVertex3f( a, b+yrule, z ); glVertex3f( a, b, z ); glVertex3f( a, b, z-zrule ); glVertex3f( x, b, z ); glVertex3f( x-xrule, b, z ); glVertex3f( x, b, z ); glVertex3f( x, b+yrule, z ); glVertex3f( x, b, z ); glVertex3f( x, b, z-zrule ); glEnd(); } // Add preview here if ( functionx->get_status() && functiony->get_status() && functionz->get_status() && preview->value() ) { PREF_DEF float pref_factor = 1 + pref->preview_quality->value()*4; float udist = ( umax->value() - umin->value() ); int usub = (int)( pref_factor * udist ); float udiv = udist / (float)usub; float vdist = ( vmax->value() - vmin->value() ); int vsub = (int)( pref_factor * vdist ); float vdiv = vdist / (float)vsub; float u = umin->value(); float v = vmin->value(); float xcoords[ usub+1 ][ vsub+1 ], ycoords[ usub+1 ][ vsub+1 ], zcoords[ usub+1 ][ vsub+1 ]; for ( int i = 0 ; i < usub+1 ; i++ ) { v = vmin->value(); for ( int y = 0 ; y < vsub+1 ; y++ ) { xcoords[i][y] = functionx->evaluate( u, v, 0 ); ycoords[i][y] = functiony->evaluate( u, v, 0 ); zcoords[i][y] = - functionz->evaluate( u, v, 0 ); v += vdiv; } u += udiv; } float min[3] = { a < x ? a : x, b < y ? b : y, c < z ? c : z }; float max[3] = { a > x ? a : x, b > y ? b : y, c > z ? c : z }; for ( int i = 0 ; i < vsub ; i++ ) { glBegin( GL_TRIANGLE_STRIP ); for ( int y = 0 ; y < usub+1 ; y++ ) { if ( xcoords[y][i] > max[0] || xcoords[y][i] < min[0] ) continue; if ( ycoords[y][i] > max[1] || zcoords[y][i] < min[1] ) continue; if ( zcoords[y][i] > max[2] || zcoords[y][i] < min[2] ) continue; get_normal( xcoords[y][i], ycoords[y][i], zcoords[y][i], xcoords[y][i+1], ycoords[y][i+1], zcoords[y][i+1], xcoords[y+1][i], ycoords[y+1][i], zcoords[y+1][i] ); glVertex3f( xcoords[y][i], ycoords[y][i], zcoords[y][i] ); glVertex3f( xcoords[y][i+1], ycoords[y][i+1], zcoords[y][i+1] ); } glEnd(); } } glPopMatrix(); list.end(); } } //*********************************************** // Edit //*********************************************** void Parametric::edit_widget( GtkWidget *wid ) { PREF_DEF bool tt = pref->tooltips->value(); // Options communes Object3D::edit_widget( wid ); // Options de geometrie new_table( edit_cont, _("Bounding Box"), 3 ); corner1->get_widget( table, tt, 1 ); corner2->get_widget( table, tt, 2 ); show_bb->get_widget( table, tt, 3 ); new_table( edit_cont, _("General settings"), 5 ); preview->get_widget( table, tt, 1 ); umin->get_widget( table, tt, 2 ); umax->get_widget( table, tt, 3 ); vmin->get_widget( table, tt, 4 ); vmax->get_widget( table, tt, 5 ); functionx->get_widget( table, tt, 6 ); functiony->get_widget( table, tt, 7 ); functionz->get_widget( table, tt, 8 ); accuracy->get_widget( table, tt, 9 ); max_gradient->get_widget( table, tt, 10 ); new_table( edit_cont, _("Precompute"), 4 ); precompute_depth->get_widget( table, tt, 1 ); precompute_x->get_widget( table, tt, 2 ); precompute_y->get_widget( table, tt, 3 ); precompute_z->get_widget( table, tt, 4 ); new_table( edit_cont, _("Transformation"), 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 ); } //*********************************************** // Mouse drag //*********************************************** void Parametric::mouse_drag( struct drag_info *drag ) { VMAN_DEF OBJLIST_DEF switch( vmanager->get_pointer_mode() ) { case TV_PMODE_SELECT: case TV_PMODE_TRANSLATE: 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 Parametric::pref_changed() { Object3D::pref_changed(); location->pref_changed(); size->pref_changed(); rotation->pref_changed(); corner1->pref_changed(); corner2->pref_changed(); show_bb->pref_changed(); functionx->pref_changed(); functiony->pref_changed(); functionz->pref_changed(); preview->pref_changed(); accuracy->pref_changed(); max_gradient->pref_changed(); umin->pref_changed(); umax->pref_changed(); vmin->pref_changed(); vmax->pref_changed(); precompute_depth->pref_changed(); precompute_x->pref_changed(); precompute_y->pref_changed(); precompute_z->pref_changed(); } //*********************************************** // Destroy editor //*********************************************** void Parametric::destroy_editor() { Object3D::destroy_editor(); location->clear_widget(); size->clear_widget(); texture->clear_widget(); rotation->clear_widget(); corner1->clear_widget(); corner2->clear_widget(); show_bb->clear_widget(); functionx->clear_widget(); functiony->clear_widget(); functionz->clear_widget(); preview->clear_widget(); accuracy->clear_widget(); max_gradient->clear_widget(); umin->clear_widget(); umax->clear_widget(); vmin->clear_widget(); vmax->clear_widget(); precompute_depth->clear_widget(); precompute_x->clear_widget(); precompute_y->clear_widget(); precompute_z->clear_widget(); } //*********************************************** // Output to povray //*********************************************** void Parametric::output_to_povray_pass1( ofstream & file ) { //if ( function->value() == NULL ) return; file << "\n\n// Parametric : " << name->value(); functionx->define_internals( file ); functiony->define_internals( file ); functionz->define_internals( file ); file << "\n#declare "; get_underscore_name( file ); file << " ="; file << "\nparametric {"; file << "\n\tfunction{ "; file << functionx->value() << " }"; file << "\n\tfunction{ "; file << functiony->value() << " }"; file << "\n\tfunction{ "; file << functionz->value() << " }"; file << "\n\t< " << umin->value() << ", " << vmin->value() << " >, < " << umax->value() << ", " << vmax->value() << " >"; file << "\n\tcontained_by{ box{ "; float a, b, c, x, y, z; corner1->get( a, b, c ); corner2->get( x, y, z ); file << '<' << a << ',' << b << ',' << -c << ">,\n\t<" << x << ',' << y << ',' << -z << "> } }\n\t"; file << "\n\taccuracy " << accuracy->value(); file << "\n\tmax_gradient " << max_gradient->value(); if ( precompute_x->value() || precompute_y->value() || precompute_z->value() ) { file << "\n\tprecompute " << precompute_depth->value(); if ( precompute_x->value() ) file << " x"; if ( precompute_y->value() ) file << " y"; if ( precompute_z->value() ) file << " z"; } Object3D_with_material::output_to_povray_pass1( file ); file << "\t"; rotation->output_to_povray( file ); size->get( x, y, z ); file << "\n\tscale <" << x << ',' << y << ',' << z << ">"; location->get( x, y, z ); file << "\n\ttranslate <" << x << "," << y << "," << -z << ">"; file << "\n} "; } //*********************************************** // Save & load //*********************************************** void Parametric::save( ofstream & file ) { file << "\nPARAMETRIC{\n"; save_basics( file ); corner1->save( file ); corner2->save( file ); show_bb->save( file ); functionx->save( file ); functiony->save( file ); functionz->save( file ); preview->save( file ); accuracy->save( file ); max_gradient->save( file ); umin->save( file ); umax->save( file ); vmin->save( file ); vmax->save( file ); precompute_depth->save( file ); precompute_x->save( file ); precompute_y->save( file ); precompute_z->save( file ); location->save( file ); size->save( file ); rotation->save( file ); texture->save( file ); file << "\n}"; } bool Parametric::load( ifstream & file, char *ltag ) { if ( strcmp( ltag, "PARAMETRIC" ) ) 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 ( corner1->load( file, tag ) ) continue; if ( corner2->load( file, tag ) ) continue; if ( show_bb->load( file, tag ) ) continue; if ( functionx->load( file, tag ) ) continue; if ( functiony->load( file, tag ) ) continue; if ( functionz->load( file, tag ) ) continue; if ( preview->load( file, tag ) ) continue; if ( accuracy->load( file, tag ) ) continue; if ( max_gradient->load( file, tag ) ) continue; if ( umin->load( file, tag ) ) continue; if ( umax->load( file, tag ) ) continue; if ( vmin->load( file, tag ) ) continue; if ( vmax->load( file, tag ) ) continue; if ( precompute_depth->load( file, tag ) ) continue; if ( precompute_x->load( file, tag ) ) continue; if ( precompute_y->load( file, tag ) ) continue; if ( precompute_z->load( file, tag ) ) continue; tvio_skip_section(file ); } while ( tag != NULL ); return true; }