//***************************************************************************************** // Truevision - a 3d modeler for gnome and povray // // glview2d.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/glview2d.h" #include "include/preferences.h" #include "include/viewmanager.h" #include "include/objectlist.h" #include "include/objparam.h" #include "include/tvio.h" #include /* Some files do not define M_PI... */ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif // Définition const char *titres[] = { N_("Top"), N_("Front"), N_("Right") }; const float labels_width = 2; GlDisplayList glview2d::labels2D_lists[3]; TvWidget_float *glview2d::common_zoom = NULL; const float sensitivity = 180; const float zoom2d_max = 8; const float zoom2d_min = 0.1; //******************************************** // Constructeur //******************************************** glview2d::glview2d( app_objs *appr, ViewType mod, GtkWidget *box, GtkWidget *f1, GtkWidget *f2 ) : glview( appr, box, f1, f2 ) { type = mod; PREF_DEF set_title( titres[(int)type] ); background = (TvWidget_color*)(pref->v2dbkg_color); axis->set( pref->axis2D->value() ); grid = new TvWidget_bool( N_("Grid"), "GRID", NULL, app_ref, pref->grid2D->value() ); tv_widgets.push_back( grid ); label->set( pref->labels2D->value() ); local_zoom = new TvWidget_float( N_("Zoom"), "LZOOM", NULL, app_ref, 1.1 ); local_zoom->set_range( zoom2d_max, zoom2d_min, 0.1 ); tv_widgets.push_back( local_zoom ); if ( common_zoom == NULL ) { common_zoom = new TvWidget_float( N_("Common Zoom"), "CZOOM", NULL, app_ref, 1.1 ); common_zoom->set_range( zoom2d_max, zoom2d_min, 0.1 ); } tv_widgets.push_back( common_zoom ); zoom = ( pref->zoom2d->value() ) ? common_zoom : local_zoom; set_rotate(); attach_popup(); } glview2d::~glview2d() { delete local_zoom; common_zoom->set( 1.1 ); delete grid; } //***************************************************** // Set normal //***************************************************** void glview2d::set_rotate() { rotate.reset(); switch ( type ) { case TV_VIEW_TOP: rotate.add( 1, 0, 0, -M_PI/2 ); break; case TV_VIEW_RIGHT: rotate.add( 0, 1, 0, M_PI/2 ); break; default: break; } } //***************************************************** // Add menus //***************************************************** void glview2d::add_menu() { // Grid menu_grid = gtk_check_menu_item_new_with_label( N_("Show grid") ); gtk_signal_connect( GTK_OBJECT(menu_grid), "activate", GTK_SIGNAL_FUNC(sign_toggle_grid), this ); gtk_check_menu_item_set_show_toggle( GTK_CHECK_MENU_ITEM(menu_grid), TRUE ); GTK_CHECK_MENU_ITEM(menu_grid)->active = grid->value(); gtk_menu_append( GTK_MENU(popup), menu_grid ); // labels menu_labels = gtk_check_menu_item_new_with_label( N_("Show labels") ); gtk_signal_connect( GTK_OBJECT(menu_labels), "activate", GTK_SIGNAL_FUNC(sign_toggle_labels), this ); gtk_check_menu_item_set_show_toggle( GTK_CHECK_MENU_ITEM(menu_labels), TRUE ); GTK_CHECK_MENU_ITEM(menu_labels)->active = label->value(); gtk_menu_append( GTK_MENU(popup), menu_labels ); } //***************************************************** // Pref Changed ! //***************************************************** void glview2d::pref_changed() { glview::pref_changed(); for ( int i = 0 ; i < 3 ; i++ ) labels2D_lists[i].invalidate(); refresh(); } //******************************************** // Refresh //******************************************** void glview2d::refresh() { //cout << "\nEnter 2D refresh !"; cout.flush(); if ( !visible ) return; glview::refresh(); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); float aratio = (float)area->allocation.width / (float)area->allocation.height; float zoomv = zoom->value(); glOrtho( -zoomv * aratio, zoomv * aratio, -zoomv, zoomv, -50, 50 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); rotate.gl_rotate(); glTranslatef( -lookat->get(0), -lookat->get(1), -lookat->get(2) ); OBJLIST_DEF objlist->display( this ); objlist->display_current_param( this ); if ( axis->value() ) draw_axis(); if ( grid->value() ) draw_grid( (int)type, zoomv ); if ( label->value() ) draw_labels(); glFlush(); gdk_gl_drawable_swap_buffers( get_drawable() ); //cout << "\nExit 2d refresh !"; cout.flush(); gdk_window_process_all_updates (); } //******************************************** // Mouse moved //******************************************** void glview2d::mouse_moved( GdkEventMotion *ev ) { GdkRectangle rect; GdkModifierType state; VMAN_DEF PREF_DEF OBJLIST_DEF if ( drag.view != this ) return; if ( ev->is_hint ) gdk_window_get_pointer( ev->window, &drag.current_x, &drag.current_y, &state ); else { drag.current_x = (int)ev->x; drag.current_y = (int)ev->y; state = (GdkModifierType)ev->state; } rect.x = 0; rect.y = 0; rect.width = area->allocation.width; rect.height = area->allocation.height; switch ( vmanager->get_pointer_mode() ) { case TV_PMODE_TRACKBALL: if ( state & GDK_BUTTON1_MASK ) { if ( type == TV_VIEW_RIGHT ) lookat->setz( lookat->get(2) + (drag.current_x - drag.previous_x) / sensitivity ); else lookat->setx( lookat->get(0) - (drag.current_x - drag.previous_x) / sensitivity ); if ( type == TV_VIEW_TOP ) lookat->setz( lookat->get(2) - (drag.current_y - drag.previous_y) / sensitivity ); else lookat->sety( lookat->get(1) + (drag.current_y - drag.previous_y) / sensitivity ); if ( pref->nav2D->value() ) vmanager->refresh(); else gtk_widget_draw( area, &rect ); } if ( state & GDK_BUTTON2_MASK ) { zoom->set( zoom->value() + ( (float)(drag.current_y - drag.previous_y) / rect.height ) ); // if ( zoom < zoom2d_min ) zoom = zoom2d_min; // if ( zoom > zoom2d_max ) zoom = zoom2d_max; if ( zoom == common_zoom ) vmanager->refresh(); else gtk_widget_draw( area, &rect ); } drag.previous_x = drag.current_x; drag.previous_y = drag.current_y; break; default: drag.gdkview = ▭ drag.shift = ( state & GDK_SHIFT_MASK ) ? true : false; drag.control = ( state & GDK_CONTROL_MASK ) ? true : false; if ( state & GDK_BUTTON1_MASK ) objlist->mouse_interact_drag( &drag ); drag.previous_x = drag.current_x; drag.previous_y = drag.current_y; break; } } void glview2d::mouse_scrolled( GdkEventScroll *ev ) { VMAN_DEF float shift = 0; if ( ev->direction == GDK_SCROLL_UP ) shift = 0.1; else shift = -0.1; if ( ev->state & GDK_SHIFT_MASK ) { // up and down if ( type == TV_VIEW_RIGHT || type == TV_VIEW_FRONT ) lookat->sety( lookat->get(1) + (shift * zoom->value() ) ); else lookat->setz( lookat->get(2) + (shift * zoom->value() ) ); } else if ( ev->state & GDK_CONTROL_MASK ) { // left and right if ( type == TV_VIEW_TOP || type == TV_VIEW_FRONT ) lookat->setx( lookat->get(0) + (shift * zoom->value() ) ); else lookat->setz( lookat->get(2) + (shift * zoom->value() ) ); } else zoom->set( zoom->value() + shift ); //force_refresh(); vmanager->refresh(); } void glview2d::set_viewport() { //cout << "\nSetting viewport;.."; cout.flush(); float aratio = (float)area->allocation.width / (float)area->allocation.height; float zoomv = zoom->value(); glOrtho( -zoomv * aratio, zoomv * aratio, -zoomv, zoomv, -50, 50 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); rotate.gl_rotate(); glTranslatef( -lookat->get(0), -lookat->get(1), -lookat->get(2) ); //cout << " Done."; cout.flush(); } //********************************************************* // Reset view //********************************************************* void glview2d::reset_view( int ntype ) { type = (ViewType)ntype; set_title( titres[(int)type] ); set_rotate(); refresh(); } //********************************************************* // Draw labels //********************************************************* void glview2d::draw_labels() { PREF_DEF if ( ! labels2D_lists[(int)type].exec() ) { const float pos = 1.02; const float offset = 0.03; labels2D_lists[type].begin(); glLineWidth( labels_width ); pref->labels_color->gl_set_rgb(); glBegin( GL_LINES ); switch( type ) { default: case TV_VIEW_RIGHT: glVertex3f( 0, pos, offset*1/3 ); // Y glVertex3f( 0, pos+offset, -offset*2/3 ); glVertex3f( 0, pos+offset/2, 0 ); glVertex3f( 0, pos+offset, offset*2/3 ); glVertex3f( 0, offset, pos+offset ); // Z glVertex3f( 0, offset, pos ); glVertex3f( 0, offset, pos ); glVertex3f( 0, -offset, pos+offset ); glVertex3f( 0, -offset, pos+offset ); glVertex3f( 0, -offset, pos ); break; case TV_VIEW_TOP: glVertex3f( pos, 0, offset ); // X glVertex3f( pos+offset, 0, -offset ); glVertex3f( pos, 0, -offset ); glVertex3f( pos+offset, 0, offset ); glVertex3f( -offset, 0, pos ); // Z glVertex3f( offset, 0, pos ); glVertex3f( offset, 0, pos ); glVertex3f( -offset, 0, pos+offset ); glVertex3f( -offset, 0, pos+offset ); glVertex3f( offset, 0, pos+offset ); break; case TV_VIEW_FRONT: glVertex3f( pos, offset, 0 ); // X glVertex3f( pos+offset, -offset, 0 ); glVertex3f( pos, -offset, 0 ); glVertex3f( pos+offset, offset, 0 ); glVertex3f( -offset*1/3, pos, 0 ); // Y glVertex3f( offset*2/3, pos+offset, 0 ); glVertex3f( 0, pos+offset/2, 0 ); glVertex3f( -offset*2/3, pos+offset, 0 ); break; } glEnd(); glLineWidth( LINE_WIDTH ); labels2D_lists[type].end(); } } void glview2d::save( ofstream & file ) { file << "\nGLVIEW2D{\n"; save_basics( file ); grid->save( file ); local_zoom->save( file ); common_zoom->save( file ); file << "\n}"; } bool glview2d::load( ifstream & file, char *ltag ) { if ( strcmp( ltag, "GLVIEW2D" ) ) return false; TvWidget_int wtype( N_("Type"), "TYPE", NULL, app_ref, type ); TvWidget_bool new_maximized( N_("Maximized"), "MAXI", NULL, app_ref, false ); TvWidget_bool new_rolled_up( N_("Rolled"), "ROLLU", NULL, app_ref, false ); char * tag = NULL; do { tag = tvio_get_next_tag( file ); if ( tag == NULL ) break; if ( load_basics( file, tag ) ) continue; if ( new_maximized.load( file, tag ) ) continue; if ( new_rolled_up.load( file, tag ) ) continue; if ( wtype.load( file, tag ) ) continue; if ( grid->load( file, tag ) ) continue; if ( local_zoom->load( file, tag ) ) continue; if ( common_zoom->load( file, tag ) ) continue; tvio_skip_section(file ); } while ( tag != NULL ); if ( type != wtype.value() ) { change_type( (ViewType)(wtype.value()) ); return true; } if ( maximized->value() != new_maximized.value() ) MaximizeRestore(); if ( rolled_up->value() != new_rolled_up.value() ) RollUp(); GTK_CHECK_MENU_ITEM(menu_gl_solid)->active = gl_solid->value(); GTK_CHECK_MENU_ITEM(menu_gl_lighting)->active = gl_lighting->value(); GTK_CHECK_MENU_ITEM(menu_gl_smooth)->active = gl_smooth->value(); GTK_CHECK_MENU_ITEM(menu_axis)->active = axis->value(); GTK_CHECK_MENU_ITEM(menu_labels)->active = label->value(); GTK_CHECK_MENU_ITEM(menu_grid)->active = grid->value(); if ( !gdk_gl_drawable_gl_begin( get_drawable(), get_context() ) ) return true; OBJLIST_DEF objlist->light_disable_all(); gdk_gl_drawable_gl_end( get_drawable() ); return true; } void glview2d::clear( ViewType cl_type ) { if ( cl_type != type ) { change_type( cl_type ); return; } glview::clear( cl_type ); local_zoom->set( 1.1 ); common_zoom->set( 1.1 ); grid->set( true ); } void glview2d::reset_home() { local_zoom->set( 1.1 ); common_zoom->set( 1.1 ); local_lookat->set( 0, 0, 0 ); common_lookat->set( 0, 0, 0 ); VMAN_DEF vmanager->refresh(); } void glview2d::key_press( GdkEventKey *ev ) { if ( ev->length == 0 ) return; if ( handle_base_key_press( ev ) ) return; switch ( ev->keyval ) { case GDK_B: case GDK_b: label->toggle(); GTK_CHECK_MENU_ITEM(menu_labels)->active = label->value(); refresh(); break; case GDK_G: case GDK_g: grid->toggle(); GTK_CHECK_MENU_ITEM(menu_grid)->active = grid->value(); refresh(); break; default: break; } }