//***************************************************************************************** // Truevision - a 3d modeler for gnome and povray // // glview3d.cc // // Vincent LE PRINCE // Copyright (C) 2000-2001 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/glview3d.h" #include "include/preferences.h" #include "include/viewmanager.h" #include "include/objectlist.h" #include "include/camera.h" #include "include/tvio.h" #include // Définitions const float labels_width = 2; /* Some files do not define M_PI... */ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif //***************************************************** // Constructeur //***************************************************** glview3d::glview3d( app_objs *appr, GtkWidget *box, GtkWidget *f1, GtkWidget *f2 ) : glview( appr, box, f1, f2 ) { type = TV_VIEW_3D; set_title( N_("Perspective") ); init_3dview(); } void glview3d::init_3dview() { PREF_DEF rotate.set( -0.1796346, 0.2291131, 0.0429528, 0.958205 ); zoom = new TvWidget_float( _("Zoom"), "ZOOM", NULL, app_ref, 20 ); zoom->set_range( 100, 1, 1 ); tv_widgets.push_back( zoom ); background = (TvWidget_color*)(pref->v3dbkg_color); gl_solid->set( true ); gl_lighting->set( true ); // Grid grids[0] = new TvWidget_bool( N_("GridXZ"), "GXZ", NULL, app_ref, pref->gridxz->value() ); grids[1] = new TvWidget_bool( N_("GridXY"), "GXY", NULL, app_ref, pref->gridxy->value() ); grids[2] = new TvWidget_bool( N_("GridYZ"), "GYZ", NULL, app_ref, pref->gridyz->value() ); // Label axis->set( pref->axis3D->value() ); label->set( pref->labels3D->value() ); attach_popup(); } glview3d::~glview3d() { delete zoom; for ( int i = 0 ; i < 0 ; i ++ ) delete grids[i]; } //***************************************************** // Pref Changed ! //***************************************************** void glview3d::pref_changed() { glview::pref_changed(); label_list.invalidate(); refresh(); } //***************************************************** // Menus //***************************************************** const gchar *gridlabs[3] = { N_("Top (XZ)"), N_("Front (XY)"), N_("Right (YZ)") }; void glview3d::add_menu() { // 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_3Dlabels), 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 ); // Grids GtkWidget *subm = gtk_menu_new(); for ( int i = 0 ; i < 3 ; i++ ) { menu_grids[i] = gtk_check_menu_item_new_with_label( gridlabs[i] ); gtk_menu_append( GTK_MENU(subm), menu_grids[i] ); gtk_check_menu_item_set_show_toggle( GTK_CHECK_MENU_ITEM(menu_grids[i]), TRUE ); GTK_CHECK_MENU_ITEM(menu_grids[i])->active = grids[i]->value(); gtk_signal_connect( GTK_OBJECT(menu_grids[i]), "activate", GTK_SIGNAL_FUNC(sign_toggle_grids), this ); } GtkWidget *item = gtk_menu_item_new_with_label( N_("Show grids") ); gtk_menu_item_set_submenu( GTK_MENU_ITEM(item), subm ); gtk_menu_append( GTK_MENU(popup), item ); } //******************************************************* // Refresh //******************************************************* void glview3d::refresh() { if ( !visible ) return; glview::refresh(); // Zoom glMatrixMode( GL_PROJECTION ); glLoadIdentity(); gluPerspective( zoom->value(), (float)area->allocation.width / (float)area->allocation.height, 1, +100 ); glMatrixMode( GL_MODELVIEW ); // Transformations glLoadIdentity(); glTranslatef( 0, 0, -5 ); rotate.gl_rotate(); // Center of Interest glTranslatef( -lookat->get(0), -lookat->get(1), -lookat->get(2) ); display_objects(); gdk_window_process_all_updates (); } void glview3d::display_objects() { //glEnable( GL_LIGHTING ); //glEnable( GL_LIGHT0 ); OBJLIST_DEF objlist->display( this ); objlist->display_current_param( this ); // Options if ( axis->value() ) draw_axis(); if ( label->value() ) draw_label(); for ( int i = 0 ; i < 3 ; i++ ) if ( grids[i]->value() ) draw_grid(i); glFlush(); gdk_gl_drawable_swap_buffers( get_drawable() ); } //******************************************************* // Mouse moved //******************************************************* void glview3d::mouse_moved( GdkEventMotion *ev ) { GdkRectangle rect; GdkModifierType state; if ( drag.view != this ) return; rect.x = 0; rect.y = 0; rect.width = area->allocation.width; rect.height = area->allocation.height; VMAN_DEF OBJLIST_DEF 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; } switch( vmanager->get_pointer_mode() ) { // TRACKBALL MODE case TV_PMODE_TRACKBALL: { // SPINNING MODE if ( (state & GDK_BUTTON1_MASK) ) { double w = rect.width; double h = rect.height; //cout << "\n coords < " << drag.previous_x << ", " << drag.previous_y << ", " << drag.current_x << ", " << drag.current_y << ">" ; cout.flush(); rotate.trackball( (2.0*(double)drag.previous_x - w ) / w , (-2.0*(double)drag.previous_y + h ) / h, (2.0*(double)drag.current_x - w ) / w, (-2.0*(double)drag.current_y + h ) / h ); gtk_widget_draw( area, &rect ); } // Zoom mode if ( state & GDK_BUTTON2_MASK ) { zoom->set( zoom->value() + ( (float)(drag.current_y - drag.previous_y) / rect.height ) * 40 ); gtk_widget_draw( area, &rect ); } drag.previous_x = drag.current_x; drag.previous_y = drag.current_y; } break; // Default mode : sending datas to current object 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 glview3d::mouse_scrolled( GdkEventScroll *ev ) { VMAN_DEF float shift = 0; if ( ev->direction == GDK_SCROLL_UP ) shift = 1; else shift = -1; zoom->set( zoom->value() + shift ); //force_refresh(); vmanager->refresh(); } //******************************************************** // Picking //******************************************************** void glview3d::set_viewport() { gluPerspective( zoom->value(), (float)area->allocation.width / (float)area->allocation.height, 1, +100 ); glMatrixMode( GL_MODELVIEW ); // Transformations glLoadIdentity(); glTranslatef( 0, 0, -5 ); rotate.gl_rotate(); // Center of Interest glTranslatef( -lookat->get(0), -lookat->get(1), -lookat->get(2) ); } //********************************************************* // Draw labels //********************************************************* void glview3d::draw_label() { PREF_DEF if ( !label_list.exec() ) { label_list.begin(); glLineWidth( labels_width ); pref->labels_color->gl_set_rgb(); glBegin( GL_LINES ); // Lettres const float pos = 1.05; const float pos2 = 1.1; float offset = 0.05; glVertex3f( pos, offset, 0 ); // X glVertex3f( pos2, -offset, 0 ); glVertex3f( pos, -offset, 0 ); glVertex3f( pos2, offset, 0 ); offset = 0.03; glVertex3f( offset, pos2, 0 ); // Y glVertex3f( -offset, pos, 0 ); glVertex3f( -offset, pos2, 0 ); glVertex3f( 0, pos+(pos2-pos)/2, 0 ); glEnd(); glBegin( GL_LINE_STRIP ); glVertex3f( 0, offset, pos2 ); // Z glVertex3f( 0, offset, pos ); glVertex3f( 0, -offset, pos2 ); glVertex3f( 0, -offset, pos ); glEnd(); glLineWidth( LINE_WIDTH ); label_list.end(); } } //********************************************************* // Toggle grids //********************************************************* void glview3d::toggle_grids() { for ( int i = 0 ; i < 3 ; i++ ) grids[i]->set( GTK_CHECK_MENU_ITEM(menu_grids[i])->active ); refresh(); } void glview3d::save( ofstream & file ) { file << "\nGLVIEW3D{\n"; save_basics( file ); zoom->save( file ); for ( int i = 0 ; i < 3 ; i ++ ) grids[i]->save( file ); file << "\n}"; } bool glview3d::load( ifstream & file, char *ltag ) { if ( strcmp( ltag, "GLVIEW3D" ) ) 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 ( grids[0]->load( file, tag ) ) continue; if ( grids[1]->load( file, tag ) ) continue; if ( grids[2]->load( file, tag ) ) continue; if ( 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(); for ( int i = 0 ; i < 3 ; i ++ ) GTK_CHECK_MENU_ITEM(menu_grids[i])->active = grids[i]->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 glview3d::clear( ViewType cl_type ) { if ( cl_type != type ) { change_type( cl_type ); return; } glview::clear( cl_type ); PREF_DEF rotate.set( -0.1796346, 0.2291131, 0.0429528, 0.958205 ); zoom->set( 20 ); background = (TvWidget_color*)(pref->v3dbkg_color); // Grid grids[0]->set( pref->gridxz->value() ); grids[1]->set( pref->gridxy->value() ); grids[2]->set( pref->gridyz->value() ); // Label axis->set( pref->axis3D->value() ); label->set( pref->labels3D->value() ); } void glview3d::reset_home() { rotate.set( -0.1796346, 0.2291131, 0.0429528, 0.958205 ); zoom->set( 20 ); local_lookat->set( 0, 0, 0 ); common_lookat->set( 0, 0, 0 ); VMAN_DEF vmanager->force_refresh(); } void glview3d::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; default: //cout << "\nUnhandled key -> " << ev->keyval; cout.flush(); break; } } //***************************************************** // Constructeur //***************************************************** glcamview::glcamview( app_objs *appr, GtkWidget *box, GtkWidget *f1, GtkWidget *f2 ) : glview3d( appr, box, f1, f2 ) { type = TV_VIEW_CAMERA; set_title( N_("Camera") ); init_3dview(); } //******************************************************* // Refresh //******************************************************* void glcamview::refresh() { if ( !visible ) return; glview::refresh(); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glcamview::set_viewport(); display_objects(); } void glcamview::set_viewport() { OBJLIST_DEF Camera *camera = (Camera*)(objlist->get_camera()); if ( camera == NULL ) { glview3d::set_viewport(); return; } gluPerspective( camera->get_angle(), /*camera->get_aspect() */(float)area->allocation.width / (float)area->allocation.height, 0.01, +100 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); // Position et direction TvWidget_point *location = camera->get_camera_location(); TvWidget_point *look_at = camera->get_lookat(); gfloat x, y, z, a, b, c; location->get( x, y, z ); look_at->get( a, b, c ); gfloat xoffset = x-a, yoffset = y-b, zoffset = z-c; gfloat xoffset2= xoffset*xoffset; gfloat zoffset2=zoffset*zoffset; float gamma = atan2( xoffset, zoffset ); float beta = - atan2( yoffset, sqrt( zoffset2 + xoffset2 ) ); float roll = camera->get_roll() /180.0 * M_PI; float upx = sin(beta)*sin(gamma)*cos(roll) - cos(gamma)*sin(roll); float upy = cos(beta)*cos(roll); float upz = cos(roll)*sin(beta)*cos(gamma) + sin(roll)*sin(gamma); gluLookAt( x, y, z, a ,b, c, upx, upy, upz ); } void glcamview::save( ofstream & file ) { file << "\nGLCAMVIEW{\n"; save_basics( file ); //zoom->save( file ); for ( int i = 0 ; i < 3 ; i ++ ) grids[i]->save( file ); file << "\n}"; } bool glcamview::load( ifstream & file, char *ltag ) { if ( strcmp( ltag, "GLCAMVIEW" ) ) return false; TvWidget_int wtype( _("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 ( grids[0]->load( file, tag ) ) continue; if ( grids[1]->load( file, tag ) ) continue; if ( grids[2]->load( file, tag ) ) continue; // if ( 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(); for ( int i = 0 ; i < 3 ; i ++ ) GTK_CHECK_MENU_ITEM(menu_grids[i])->active = grids[i]->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; }