//***************************************************************************************** // Truevision - a 3d modeler for gnome and povray // // heightfield.cc // // Kent Gustavsson // 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/heightfield.h" #include "include/viewmanager.h" #include "include/preferences.h" #include "include/objectlist.h" #include "include/tvio.h" #include "include/utils3d.h" #include //************************************** // Constructeur //************************************** const int hfiletype_num = 8; const char *hfiletype_ext[hfiletype_num] = { "gif","tga","pot","png","pgm","ppm", "jpg", "tif" }; const char *hfiletype_def[hfiletype_num] = { "gif","tga","pot","png","pgm","ppm", "jpeg", "tiff" }; Heightfield::Heightfield( app_objs *appref ) : Object3D_with_material( appref ) { type = TV_OBJ3D_HEIGHTFIELD; category = TV_OBJ3D_OBJECTS; set_name( "HeightField" ); // Base location = new ObjParam_point( _("Location"), "LOC", NULL, app_ref, true ); location->set( 0, 0, 0 ); size = new ObjParam_scale( _("Size"), "SIZE", NULL, app_ref, true ); size->set( 1, 1, 1 ); rotation = new ObjParam_rotation( _("Rotation"), "ROT", NULL, app_ref, true ); rotation->set( 0, 0, 0 ); water_level = new ObjParam_float (_("Water level"), "W_LEVEL", NULL, app_ref, true, 0 ); water_level->set_range( 1, 0, 0.01, 5 ); smooth = new ObjParam_bool (_("Smooth"), "SMOOTH", NULL, app_ref, true, false ); hierarchy = new ObjParam_bool (_("Hierarchy"), "HIERARCHY", NULL, app_ref, true, true); bitmap = new ObjParam_file( _("Image"), "BITMAP", NULL, app_ref, true ); bitmap->set_list( hfiletype_ext, hfiletype_def, hfiletype_num ); preview = new ObjParam_bool ( _("Preview"), "PREV", NULL, app_ref, true, false ); } Heightfield::Heightfield( Heightfield & ref ) : Object3D_with_material( ref ) { location = new ObjParam_point( *ref.location ); size = new ObjParam_scale( *ref.size ); rotation = new ObjParam_rotation( *ref.rotation ); smooth = new ObjParam_bool( *ref.smooth ); water_level = new ObjParam_float( *ref.water_level ); hierarchy = new ObjParam_bool( *ref.hierarchy ); bitmap = new ObjParam_file( *ref.bitmap ); preview = new ObjParam_bool( *ref.preview ); } Heightfield::~Heightfield() { delete location; delete size; delete rotation; delete smooth; delete water_level; delete hierarchy; delete bitmap; delete preview; } //************************************** // Display // Dessin de la boite //************************************** void Heightfield::display( glview *view, bool setcol ) { if ( hidden->value() ) return; if ( location->changed() || size->changed() || rotation->changed() || water_level->changed() || preview->changed() || bitmap->changed() ) list.invalidate(); Object3D::display( view ); if ( setcol ) set_color(); if ( ! list.exec() ) { PREF_DEF // mise à zero des parametres location->unchange(); size->unchange(); rotation->unchange(); water_level->unchange(); preview->unchange(); bitmap->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 ); rotation->gl_rotate(); glScalef( a, b, c ); bool do_preview = preview->value(); if ( bitmap->value() == NULL ) do_preview = false; GdkPixbuf *image = NULL; if ( do_preview ) image = gdk_pixbuf_new_from_file( bitmap->value(), NULL ); if ( image == NULL ) do_preview = false; if ( do_preview ) { // Mesh preview float hf_prev_quality = pref->hf_preview_quality->value() / 100.0; int yadv = gdk_pixbuf_get_height( image ); int ysteps = (int)(float(yadv)*hf_prev_quality); float ystep_width = ((float)yadv)/((float)(ysteps-1)); int xadv = gdk_pixbuf_get_width( image ); int xsteps = (int)(float(xadv)*hf_prev_quality); float xstep_width = ((float)xadv)/((float)(xsteps-1)); int rowstride = gdk_pixbuf_get_rowstride( image ); float waterlevel = water_level->value(); guchar *pixels = gdk_pixbuf_get_pixels( image ); float xpoints[xsteps], ypoints[ysteps]; float adv = 0; int channels = gdk_pixbuf_get_n_channels( image ); float offset = 1.0 / (float)(xsteps); for ( int i = 0 ; i < xsteps ; i++ ) { xpoints[i] = adv; adv += offset; } adv = -1; offset = 1.0 / (float)(ysteps); for ( int j = 0 ; j < ysteps ; j++ ) { ypoints[j] = adv; adv += offset; } float zpoints[xsteps][ysteps]; for ( int j = 0 ; j < ysteps; j++) { for ( int i = 0 ; i < xsteps ; i++) { guchar *ptr = pixels + ((int)(j*ystep_width))*rowstride + ((int)(i*xstep_width))*channels; zpoints[j][i] = (float)( ptr[0]*256 + ptr[1] ) / 65536.0 ; } } for ( int j = 0 ; j < ysteps-1; j ++ ) { glBegin( GL_TRIANGLES ); for ( int i = 0 ; i < xsteps-1 ; i += 1 ) { if ( zpoints[j][i] >= waterlevel || zpoints[j+1][i] >= waterlevel || zpoints[j][i+1] >= waterlevel ) { get_normal( xpoints[i], zpoints[j][i], ypoints[j], xpoints[i], zpoints[j+1][i], ypoints[j+1], xpoints[i+1], zpoints[j][i+1], ypoints[j] ); // need optimization : normal y is always the same, don't need to calculate :) glVertex3f( xpoints[i], zpoints[j][i], ypoints[j] ); glVertex3f( xpoints[i], zpoints[j+1][i], ypoints[j+1] ); glVertex3f( xpoints[i+1], zpoints[j][i+1], ypoints[j] ); } if ( zpoints[j+1][i] >= waterlevel || zpoints[j][i+1] >= waterlevel || zpoints[j+1][i+1] >= waterlevel ) { get_normal( xpoints[i], zpoints[j+1][i], ypoints[j+1], xpoints[i+1], zpoints[j][i+1], ypoints[j], xpoints[i+1], zpoints[j+1][i+1], ypoints[j+1], true ); glVertex3f( xpoints[i], zpoints[j+1][i], ypoints[j+1] ); glVertex3f( xpoints[i+1], zpoints[j][i+1], ypoints[j] ); glVertex3f( xpoints[i+1], zpoints[j+1][i+1], ypoints[j+1] ); } } glEnd(); } } else { // Bounding box glBegin( GL_LINE_LOOP ); glVertex3f( 0, 0, 0 ); glVertex3f( 1, 0, 0 ); glVertex3f( 1, 0, -1 ); glVertex3f( 0, 0, -1 ); glEnd(); glBegin( GL_LINE_LOOP ); glVertex3f( 0, 1, 0 ); glVertex3f( 1, 1, 0 ); glVertex3f( 1, 1, -1 ); glVertex3f( 0, 1, -1 ); glEnd(); glBegin( GL_LINES ); glVertex3f( 0, 0, 0 ); glVertex3f( 0, 1, 0 ); glVertex3f( 0, 0, -1 ); glVertex3f( 0, 1, -1 ); glVertex3f( 1, 0, -1 ); glVertex3f( 1, 1, -1 ); glVertex3f( 1, 0, 0 ); glVertex3f( 1, 1, 0 ); glEnd(); } glPopMatrix(); list.end(); } } //*********************************************** // Edit //*********************************************** void Heightfield::edit_widget( GtkWidget *wid ) { PREF_DEF bool tt = pref->tooltips->value(); // Options communes Object3D::edit_widget( wid ); // Options de geometrie new_table( edit_cont, _("General settings"), 9 ); bitmap->get_widget( table, tt, 1 ); smooth->get_widget( table, tt, 3 ); water_level->get_widget( table, tt, 4 ); hierarchy->get_widget( table, tt, 5 ); preview->get_widget( table, tt, 6 ); location->get_widget( table, tt, 7 ); size->get_widget( table, tt, 8 ); rotation->get_widget( table, tt, 9 ); get_texture_widgets( edit_cont, tt ); gtk_widget_show_all( wid ); } //*********************************************** // Mouse drag //*********************************************** void Heightfield::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 Heightfield::pref_changed() { Object3D::pref_changed(); location->pref_changed(); size->pref_changed(); rotation->pref_changed(); smooth->pref_changed(); water_level->pref_changed(); hierarchy->pref_changed(); bitmap->pref_changed(); preview->pref_changed(); } //*********************************************** // Destroy editor //*********************************************** void Heightfield::destroy_editor() { Object3D::destroy_editor(); location->clear_widget(); size->clear_widget(); texture->clear_widget(); rotation->clear_widget(); smooth->clear_widget(); water_level->clear_widget(); hierarchy->clear_widget(); bitmap->clear_widget(); preview->clear_widget(); } //*********************************************** // Output to povray //*********************************************** void Heightfield::output_to_povray_pass1( ofstream & file ) { file << "\n\n// Heigthfield : " << name->value(); file << "\n#declare "; get_underscore_name( file ); file << " ="; file << "\nheight_field {\n\t"; bitmap->output_to_povray( file ); file << "\n\t"; if ( smooth->value() ) file << "smooth\n\t"; if ( hierarchy->value() == 0 ) file << "hierarchy off\n\t"; // Doesn't work if ( water_level->value() != 0 ) file << "water_level " << water_level->value() << "\n\t"; Object3D_with_material::output_to_povray_pass1( file ); float a, b, c, x, y, z; location->get( x, y, z ); size->get( a, b, c ); file << "scale <" << a << ',' << b << ',' << c << ">\n\t"; rotation->output_to_povray( file ); file << "\n\ttranslate <" << x << "," << y << "," << -z << "> \n\t"; file << "\n}"; } void Heightfield::save( ofstream & file ) { file << "\nHEIGHTFIELD{\n"; save_basics( file ); location->save( file ); size->save( file ); rotation->save( file ); texture->save( file ); smooth->save( file ); water_level->save( file ); hierarchy->save( file ); bitmap->save( file ); preview->save( file ); file << "\n}"; } bool Heightfield::load( ifstream & file, char *ltag ) { if ( strcmp( ltag, "HEIGHTFIELD" ) ) return false; 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 ( smooth->load( file, tag ) ) continue; if ( water_level->load( file, tag ) ) continue; if ( hierarchy->load( file, tag ) ) continue; if ( bitmap->load( file, tag ) ) continue; if ( preview->load( file, tag ) ) continue; tvio_skip_section(file ); } while ( tag != NULL ); return true; }