//***************************************************************************************** // Truevision - a 3d modeler for gnome and povray // // obj3dcsg.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/obj3dcsg.h" #include "include/viewmanager.h" #include "include/objectlist.h" #include "include/tvio.h" //************************************** // Constructeur //************************************** ObjCSG::ObjCSG( app_objs *appref ) : Object3D_with_material( appref ) { category = TV_OBJ3D_OBJECTS; // Base translation = new ObjParam_point( N_("Location"), "LOC", NULL, app_ref, true ); translation->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 ); evaluate = new ObjParam_bool( N_("Evaluate"), "EVAL", NULL, app_ref, true, false ); node_expanded = new TvWidget_bool( NULL, "EXP", NULL, app_ref, true ); } ObjCSG::ObjCSG( ObjCSG & ref ) : Object3D_with_material( ref ) { type = ref.type; translation = new ObjParam_point( *ref.translation ); size = new ObjParam_scale( *ref.size ); rotation = new ObjParam_rotation( *ref.rotation ); evaluate = new ObjParam_bool( *ref.evaluate ); node_expanded = new TvWidget_bool( *ref.node_expanded ); OBJLIST_DEF for ( unsigned int i = 0 ; i < (ref).children.size() ; i++ ) { Object3D *no = ref.children[i]->duplicate_yourself(); children.push_back( no ); objlist->add_object( no ); no->set_parent( this ); } } ObjCSG::~ObjCSG() { delete translation; delete size; delete rotation; delete node_expanded; delete evaluate; for ( unsigned int i = 0 ; i < children.size() ; i++ ) delete children[i]; } void ObjCSG::set_layer( ObjectLayer *lay ) { Object3D::set_layer( lay ); for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->set_layer( lay ); } //************************************** // Display //************************************** void ObjCSG::display( glview *view, bool set_col ) { if ( hidden->value() ) return; glPushMatrix(); // Position et direction gfloat x, y, z; translation->get( x, y, z ); glTranslatef( x, y, z ); rotation->gl_rotate(); size->get( x, y, z ); glScalef( x, y, z ); for ( unsigned int i = 0 ; i < children.size() ; i++ ) { if ( set_col ) set_color(); if ( selected ) children[i]->select(); children[i]->display( view ); if ( selected ) children[i]->unselect(); } glPopMatrix(); } //*********************************************** // Edit //*********************************************** void ObjCSG::edit_widget( GtkWidget *wid ) { bool tt = true; // Options communes Object3D_with_material::edit_widget( wid ); evaluate->get_widget( edit_cont, tt ); // Options de geometrie new_frame( edit_cont, _("General settings") ); translation->get_widget( frame, tt ); size->get_widget( frame, tt ); rotation->get_widget( frame, tt ); get_texture_widgets( frame, tt ); gtk_widget_show_all( wid ); } //*********************************************** // Mouse drag //*********************************************** void ObjCSG::mouse_drag( struct drag_info *drag ) { VMAN_DEF OBJLIST_DEF switch( vmanager->get_pointer_mode() ) { case TV_PMODE_TRANSLATE: translation->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 ObjCSG::pref_changed() { Object3D_with_material::pref_changed(); translation->pref_changed(); size->pref_changed(); rotation->pref_changed(); evaluate->pref_changed(); } //*********************************************** // Destroy editor //*********************************************** void ObjCSG::destroy_editor() { Object3D_with_material::destroy_editor(); translation->clear_widget(); size->clear_widget(); rotation->clear_widget(); evaluate->clear_widget(); } //*********************************************** // Add to tree //*********************************************** void ObjCSG::add_to_tree( GtkWidget *view, GtkTreeStore *store, GtkTreeSelection *sel, GtkTreeIter *parent, GtkTreeIter *sibling, const gchar *pixmap ) { Object3D::add_to_tree( view, store, sel, parent, sibling, pixmap ); for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->add_to_tree( view, store, sel, &node_iter, NULL ); GtkTreePath *path = gtk_tree_model_get_path( GTK_TREE_MODEL(tree_store), &node_iter ); bool test = false; if ( node_expanded->value() == true ) test = gtk_tree_view_expand_row( GTK_TREE_VIEW(tree_view), path, FALSE ); else gtk_tree_view_collapse_row( GTK_TREE_VIEW(tree_view), path ); gtk_tree_path_free( path );} void ObjCSG::save_tree() { gboolean isexp; if ( !GTK_IS_TREE_VIEW(tree_view) ) return; GtkTreePath *path = gtk_tree_model_get_path( GTK_TREE_MODEL(tree_store), &node_iter ); isexp = gtk_tree_view_row_expanded( GTK_TREE_VIEW(tree_view), path ); g_free( path ); node_expanded->set( isexp ); for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->save_tree(); } //*********************************************** // Child manipulation //*********************************************** void ObjCSG::add_object( Object3D *obj ) { OBJLIST_DEF objlist->add_object( obj ); children.push_back( obj ); obj->set_parent( this ); } void ObjCSG::paste_object( Object3D *obj ) { add_object( obj ); obj->add_to_tree( tree_view, tree_store, tree_selection, &node_iter , NULL ); obj->tree_node_select(); } void ObjCSG::insert_child( Object3D *obj, int position ) { OBJLIST_DEF objlist->add_object( obj ); obj->set_parent( this ); vector::iterator it; it = children.begin() + position; children.insert( it, obj ); //obj->add_to_tree( GTK_WIDGET(ctree), ctree_node , ( (unsigned int)position == children.size() - 1 ) ? NULL : children[position+1]->get_node() ); obj->add_to_tree( tree_view, tree_store, tree_selection, &node_iter, ( (unsigned int)position == children.size() - 1 ) ? NULL : children[position+1]->get_node() ); obj->tree_node_select(); } bool ObjCSG::has_as_ancester( Object3D *obj ) { Object3D *mum = this; while ( mum != NULL ) { mum = mum->get_parent(); if ( mum == obj ) return true; } return false; } void ObjCSG::remove_object( Object3D *obj ) { vector::iterator object; unsigned int i = 0; for ( object = children.begin() ; object != children.end() ; object++ ) { i++; if ( *object != obj ) continue; if ( i < 0 ) i = 0; if ( i > children.size() - 1 ) i = children.size() - 2; obj->remove_from_tree(); if ( children.size() > 1 ) children[i]->tree_node_select(); else tree_node_select(); OBJLIST_DEF objlist->remove_object( obj ); children.erase( object ); break; } /*if ( obj->get_parent() != NULL && parent ) { obj->get_parent()->remove_object( obj ); return; }*/ } void ObjCSG::duplicate_object( Object3D *obj ) { vector::iterator object; for ( object = children.begin() ; object != children.end() ; object++ ) { if ( *object != obj ) continue; Object3D *target = *object; OBJLIST_DEF Object3D *newobj = target->duplicate_yourself(); objlist->add_object( newobj ); target = *(++object); newobj->add_to_tree( tree_view, tree_store, tree_selection , &node_iter, ( object != children.end() ) ? target->get_node() : NULL ); children.insert( object, newobj ); newobj->tree_node_select(); break; } } void ObjCSG::move_child_down( Object3D *obj ) { vector::iterator object; unsigned int i = 0; for ( object = children.begin() ; object != children.end() ; object++ ) { i++; if ( *object != obj ) continue; if ( i == children.size() ) return; Object3D *target = *object; vector::iterator object2 = object; object2 += 1; //gtk_ctree_move( ctree, (*object2)->get_node(), ctree_node, target->get_node() ); gtk_tree_store_move_after( tree_store, target->get_node(), (*object2)->get_node() ); children.erase( object ); children.insert( object2, target ); break; } } void ObjCSG::move_child_up( Object3D *obj ) { vector::iterator object; int i = 0; for ( object = children.begin() ; object != children.end() ; object++ ) { i++; if ( *object != obj ) continue; if ( i == 1 ) return; Object3D *target = *object; vector::iterator object2 = object; object2--; //gtk_ctree_move( ctree, obj->get_node(), ctree_node, (*object2)->get_node() ); gtk_tree_store_move_before( tree_store, target->get_node(), (*object2)->get_node() ); children.erase( object ); children.insert( object2, target ); break; } } //*********************************************** // save //*********************************************** void ObjCSG::save_children( ofstream & file ) { save_basics( file ); translation->save( file ); size->save( file ); rotation->save( file ); texture->save( file ); node_expanded->save( file ); evaluate->save( file ); for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->save( file ); } void ObjCSG::load_children( ifstream & file ) { OBJLIST_DEF char * tag = NULL; do { tag = tvio_get_next_tag( file ); if ( tag == NULL ) break; if ( load_basics( file, tag ) ) continue; if ( translation->load( file, tag ) ) continue; if ( rotation->load( file, tag ) ) continue; if ( size->load( file, tag ) ) continue; if ( node_expanded->load( file, tag ) ) continue; if ( evaluate->load( file, tag ) ) continue; Object3D *obj = objlist->create_object( tag ); if ( obj != NULL ) { if ( obj->load( file, tag ) ) { add_object( obj ); continue; } else delete obj; } tvio_skip_section(file ); } while ( tag != NULL ); } //*********************************************** // Cutaway for Intersection / Difference //*********************************************** void CsgCutAway::edit_widget( GtkWidget *wid ) { bool tt = true; // Options communes Object3D_with_material::edit_widget( wid ); evaluate->get_widget( edit_cont, tt ); // Options de geometrie new_frame( edit_cont, _("General settings") ); translation->get_widget( frame, tt ); size->get_widget( frame, tt ); rotation->get_widget( frame, tt ); cutaway_textures->get_widget( frame, tt ); get_texture_widgets( frame, tt ); gtk_widget_show_all( wid ); } void CsgCutAway::load_children( ifstream & file ) { OBJLIST_DEF char * tag = NULL; do { tag = tvio_get_next_tag( file ); if ( tag == NULL ) break; if ( load_basics( file, tag ) ) continue; if ( translation->load( file, tag ) ) continue; if ( rotation->load( file, tag ) ) continue; if ( size->load( file, tag ) ) continue; if ( node_expanded->load( file, tag ) ) continue; if ( evaluate->load( file, tag ) ) continue; if ( cutaway_textures->load( file, tag ) ) continue; Object3D *obj = objlist->create_object( tag ); if ( obj != NULL ) { if ( obj->load( file, tag ) ) { add_object( obj ); continue; } else delete obj; } tvio_skip_section(file ); } while ( tag != NULL ); } //*********************************************** // UNION //*********************************************** CsgUnion::CsgUnion( app_objs *appref ) : ObjCSG( appref ) { type = TV_OBJ3D_CSGUNION; set_name( "Union" ); split_union = new ObjParam_bool( N_("Split union"), "SPLIT", NULL, app_ref, false, true ); } void CsgUnion::edit_widget( GtkWidget *wid ) { bool tt = true; // Options communes Object3D_with_material::edit_widget( wid ); evaluate->get_widget( edit_cont, tt ); // Options de geometrie new_frame( edit_cont, _("General settings") ); translation->get_widget( frame, tt ); size->get_widget( frame, tt ); rotation->get_widget( frame, tt ); split_union->get_widget( frame, tt ); get_texture_widgets( frame, tt ); gtk_widget_show_all( wid ); } // Output to povray void CsgUnion::output_to_povray_pass1( ofstream & file ) { for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->output_to_povray_pass1( file ); if ( !render->value() ) return; file << "\n\n// Union : " << name->value(); file << "\n#declare "; get_underscore_name( file ); file << " ="; file << "\nunion {"; for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->output_to_povray_pass2( file ); Object3D_with_material::output_to_povray_pass1( file ); float x, y, z; size->get( x, y, z ); file << "\n\tscale <" << x << ',' << y << ',' << z << ">\n\t"; rotation->output_to_povray( file ); translation->get( x, y, z ); file << "\n\ttranslate <" << x << "," << y << "," << -z << ">"; if ( split_union->value() == false ) file << "\n\tsplit_union off"; file << "\n}"; } void CsgUnion::save( ofstream & file ) { file << "\nCSGUNION{\n"; split_union->save( file ); save_children( file ); file << "\n}"; } bool CsgUnion::load( ifstream & file, char *ltag ) { if ( strcmp( "CSGUNION", ltag ) ) return false; OBJLIST_DEF char * tag = NULL; do { tag = tvio_get_next_tag( file ); if ( tag == NULL ) break; if ( load_basics( file, tag ) ) continue; if ( translation->load( file, tag ) ) continue; if ( rotation->load( file, tag ) ) continue; if ( size->load( file, tag ) ) continue; if ( node_expanded->load( file, tag ) ) continue; if ( evaluate->load( file, tag ) ) continue; if ( split_union->load( file, tag ) ) continue; Object3D *obj = objlist->create_object( tag ); if ( obj != NULL ) { if ( obj->load( file, tag ) ) { add_object( obj ); continue; } else delete obj; } tvio_skip_section(file ); } while ( tag != NULL ); return true; } //*********************************************** // DIFFERENCE //*********************************************** CsgDifference::CsgDifference( app_objs *appref ) : CsgCutAway( appref ) { type = TV_OBJ3D_CSGDIFFERENCE; set_name( "Difference" ); } // Output to povray void CsgDifference::output_to_povray_pass1( ofstream & file ) { for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->output_to_povray_pass1( file ); if ( !render->value() ) return; file << "\n\n// Difference : " << name->value(); file << "\n#declare "; get_underscore_name( file ); file << " ="; file << "\ndifference {"; for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->output_to_povray_pass2( file ); if ( cutaway_textures->value() ) file << "\n\tcutaway_textures"; Object3D_with_material::output_to_povray_pass1( file ); float x, y, z; size->get( x, y, z ); file << "\n\tscale <" << x << ',' << y << ',' << z << ">\n\t"; rotation->output_to_povray( file ); translation->get( x, y, z ); file << "\n\ttranslate <" << x << "," << y << "," << -z << ">"; file << "\n}"; } void CsgDifference::save( ofstream & file ) { file << "\nCSGDIFF{\n"; save_children(file); file << "\n}"; } bool CsgDifference::load( ifstream & file, char *ltag ) { if ( strcmp( "CSGDIFF", ltag ) ) return false; load_children(file ); return true; } void CsgDifference::draw_b( glview *view ) { if ( selected ) children[0]->select(); children[0]->display( view ); if ( selected ) children[0]->unselect(); } void CsgDifference::draw_a( glview *view ) { for ( unsigned int i = 1 ; i < children.size() ; i++ ) { if ( selected ) children[i]->select(); children[i]->display( view ); if ( selected ) children[i]->unselect(); } } void CsgDifference::display( glview *view, bool set_col ) { if ( hidden->value() ) return; if ( children.size() == 0 ) return; glPushMatrix(); // Position et direction gfloat x, y, z; translation->get( x, y, z ); glTranslatef( x, y, z ); rotation->gl_rotate(); size->get( x, y, z ); glScalef( x, y, z ); if ( ! evaluate->value() ) { for ( unsigned int i = 0 ; i < children.size() ; i++ ) { if ( set_col ) set_color(); if ( selected ) children[i]->select(); children[i]->display( view ); if ( selected ) children[i]->unselect(); } } else { glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glCullFace( GL_FRONT ); glClear( GL_STENCIL_BUFFER_BIT ); glDepthMask(GL_TRUE); draw_a( view ); glDepthMask(GL_FALSE); glEnable(GL_STENCIL_TEST); glStencilMask( GL_TRUE ); glStencilFunc(GL_ALWAYS, 0, 0); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); glCullFace(GL_BACK); draw_b( view ); glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); glCullFace(GL_FRONT); draw_b( view ); glDepthMask(GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_NOTEQUAL, 0, 1); glDisable(GL_DEPTH_TEST); glCullFace(GL_FRONT); draw_a( view ); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glEnable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); glDepthFunc(GL_ALWAYS); draw_b( view ); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glCullFace( GL_BACK ); glClear( GL_STENCIL_BUFFER_BIT ); draw_b( view ); glDepthMask(GL_FALSE); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 0, 0); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); glCullFace(GL_BACK); draw_a( view ); glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); glCullFace(GL_FRONT); draw_a( view ); glDepthMask(GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_EQUAL, 0, 1); glDisable(GL_DEPTH_TEST); glCullFace(GL_BACK); draw_b( view ); glDisable(GL_STENCIL_TEST); glEnable(GL_DEPTH_TEST); glClear( GL_STENCIL_BUFFER_BIT ); } glPopMatrix(); } //*********************************************** // MERGE //*********************************************** CsgMerge::CsgMerge( app_objs *appref ) : ObjCSG( appref ) { type = TV_OBJ3D_CSGMERGE; set_name( "Merge" ); } // Output to povray void CsgMerge::output_to_povray_pass1( ofstream & file ) { for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->output_to_povray_pass1( file ); if ( !render->value() ) return; file << "\n\n// Merge : " << name->value(); file << "\n#declare "; get_underscore_name( file ); file << " ="; file << "\nmerge {"; for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->output_to_povray_pass2( file ); Object3D_with_material::output_to_povray_pass1( file ); float x, y, z; size->get( x, y, z ); file << "\n\tscale <" << x << ',' << y << ',' << z << ">\n\t"; rotation->output_to_povray( file ); translation->get( x, y, z ); file << "\n\ttranslate <" << x << "," << y << "," << -z << ">"; file << "\n}"; } void CsgMerge::save( ofstream & file ) { file << "\nCSGMERGE{\n"; save_children( file ); file << "\n}"; } bool CsgMerge::load( ifstream & file, char *ltag ) { if ( strcmp( "CSGMERGE", ltag ) ) return false; load_children( file ); return true; } //*********************************************** // INTERSECTION //*********************************************** CsgIntersection::CsgIntersection( app_objs *appref ) : CsgCutAway( appref ) { type = TV_OBJ3D_CSGINTERSECTION; set_name( "Intersection" ); } // Output to povray void CsgIntersection::output_to_povray_pass1( ofstream & file ) { for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->output_to_povray_pass1( file ); if ( !render->value() ) return; file << "\n\n// Intersection : " << name->value(); file << "\n#declare "; get_underscore_name( file ); file << " ="; file << "\nintersection {"; for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->output_to_povray_pass2( file ); if ( cutaway_textures->value() ) file << "\n\tcutaway_textures"; Object3D_with_material::output_to_povray_pass1( file ); float x, y, z; size->get( x, y, z ); file << "\n\tscale <" << x << ',' << y << ',' << z << ">\n\t"; rotation->output_to_povray( file ); translation->get( x, y, z ); file << "\n\ttranslate <" << x << "," << y << "," << -z << ">"; file << "\n}"; } void CsgIntersection::save( ofstream & file ) { file << "\nCSGINTER{\n"; save_children( file ); file << "\n}"; } bool CsgIntersection::load( ifstream & file, char *ltag ) { if ( strcmp( "CSGINTER", ltag ) ) return false; load_children( file ); return true; } void CsgIntersection::draw_b( glview *view ) { if ( selected ) children[0]->select(); children[0]->display( view ); if ( selected ) children[0]->unselect(); } void CsgIntersection::draw_a( glview *view ) { for ( unsigned int i = 1 ; i < children.size() ; i++ ) { if ( selected ) children[i]->select(); children[i]->display( view ); if ( selected ) children[i]->unselect(); } } void CsgIntersection::display( glview *view, bool set_col ) { if ( hidden->value() ) return; if ( children.size() == 0 ) return; glPushMatrix(); // Position et direction gfloat x, y, z; translation->get( x, y, z ); glTranslatef( x, y, z ); rotation->gl_rotate(); size->get( x, y, z ); glScalef( x, y, z ); if ( ! evaluate->value() ) { for ( unsigned int i = 0 ; i < children.size() ; i++ ) { if ( set_col ) set_color(); if ( selected ) children[i]->select(); children[i]->display( view ); if ( selected ) children[i]->unselect(); } } else { glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glCullFace( GL_BACK ); glClear( GL_STENCIL_BUFFER_BIT ); glDepthMask(GL_TRUE); draw_a( view ); glDepthMask(GL_FALSE); glEnable(GL_STENCIL_TEST); glStencilMask( GL_TRUE ); glStencilFunc(GL_ALWAYS, 0, 0); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); glCullFace(GL_BACK); draw_b( view ); glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); glCullFace(GL_FRONT); draw_b( view ); glDepthMask(GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_NOTEQUAL, 0, 1); glDisable(GL_DEPTH_TEST); glCullFace(GL_BACK); draw_a( view ); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glEnable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); glDepthFunc(GL_ALWAYS); draw_b( view ); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glCullFace( GL_BACK ); glClear( GL_STENCIL_BUFFER_BIT ); draw_b( view ); glDepthMask(GL_FALSE); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 0, 0); glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); glCullFace(GL_BACK); draw_a( view ); glStencilOp(GL_KEEP, GL_KEEP, GL_DECR); glCullFace(GL_FRONT); draw_a( view ); glDepthMask(GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glStencilFunc(GL_NOTEQUAL, 0, 1); glDisable(GL_DEPTH_TEST); glCullFace(GL_BACK); draw_b( view ); glDisable(GL_STENCIL_TEST); glEnable(GL_DEPTH_TEST); glClear( GL_STENCIL_BUFFER_BIT ); } glPopMatrix(); } //*********************************************** // Light Group //*********************************************** LightGroup::LightGroup( app_objs *appref ) : ObjCSG( appref ) { type = TV_OBJ3D_LIGHTGROUP; set_name( "Light Group" ); global_lights = new ObjParam_bool( N_("Global lights"), "GLOBLIGHTS", NULL, app_ref, true, false ); } void LightGroup::edit_widget( GtkWidget *wid ) { bool tt = true; // Options communes Object3D::edit_widget( wid, false ); // Options de geometrie new_frame( edit_cont, _("General settings") ); global_lights->get_widget( frame, tt ); translation->get_widget( frame, tt ); size->get_widget( frame, tt ); rotation->get_widget( frame, tt ); gtk_widget_show_all( wid ); } void LightGroup::destroy_editor() { Object3D::destroy_editor(); translation->clear_widget(); size->clear_widget(); rotation->clear_widget(); global_lights->clear_widget(); } void LightGroup::pref_changed() { Object3D::pref_changed(); translation->pref_changed(); size->pref_changed(); rotation->pref_changed(); global_lights->pref_changed(); } // Output to povray void LightGroup::output_to_povray_pass1( ofstream & file ) { for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->output_to_povray_pass1( file ); if ( !render->value() ) return; file << "\n\n// Light group : " << name->value(); file << "\n#declare "; get_underscore_name( file ); file << " ="; file << "\nlight_group {"; for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->output_to_povray_pass2( file ); file << "\n\tglobal_lights " << ( global_lights->value() ? "on" : "off" ); float x, y, z; size->get( x, y, z ); file << "\n\tscale <" << x << ',' << y << ',' << z << ">\n\t"; rotation->output_to_povray( file ); translation->get( x, y, z ); file << "\n\ttranslate <" << x << "," << y << "," << -z << ">"; file << "\n}"; } void LightGroup::save( ofstream & file ) { file << "\nLIGHTGROUP{\n"; save_basics( file ); translation->save( file ); size->save( file ); rotation->save( file ); texture->save( file ); node_expanded->save( file ); global_lights->save( file ); for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->save( file ); file << "\n}"; } bool LightGroup::load( ifstream & file, char *ltag ) { if ( strcmp( "LIGHTGROUP", ltag ) ) return false; OBJLIST_DEF char * tag = NULL; do { tag = tvio_get_next_tag( file ); if ( tag == NULL ) break; if ( load_basics( file, tag ) ) continue; if ( translation->load( file, tag ) ) continue; if ( rotation->load( file, tag ) ) continue; if ( size->load( file, tag ) ) continue; if ( node_expanded->load( file, tag ) ) continue; if ( global_lights->load( file, tag ) ) continue; Object3D *obj = objlist->create_object( tag ); if ( obj != NULL ) { if ( obj->load( file, tag ) ) { add_object( obj ); continue; } else delete obj; } tvio_skip_section(file ); } while ( tag != NULL ); return true; } //*********************************************** // Group //*********************************************** CsgGroup::CsgGroup( app_objs *appref ) : ObjCSG( appref ) { type = TV_OBJ3D_GROUP; set_name( "Group" ); } void CsgGroup::edit_widget( GtkWidget *wid ) { // Options communes Object3D_with_material::edit_widget_base( wid ); gtk_widget_show_all( wid ); } // Output to povray void CsgGroup::output_to_povray_pass1( ofstream & file ) { for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->output_to_povray_pass1( file ); } void CsgGroup::output_to_povray_pass2( ofstream & file ) { for ( unsigned int i = 0 ; i < children.size() ; i++ ) children[i]->output_to_povray_pass2( file ); } void CsgGroup::save( ofstream & file ) { file << "\nGROUP{\n"; save_children( file ); file << "\n}"; } bool CsgGroup::load( ifstream & file, char *ltag ) { if ( strcmp( "GROUP", ltag ) ) return false; OBJLIST_DEF char * tag = NULL; do { tag = tvio_get_next_tag( file ); if ( tag == NULL ) break; if ( load_basics( file, tag ) ) continue; if ( node_expanded->load( file, tag ) ) continue; Object3D *obj = objlist->create_object( tag ); if ( obj != NULL ) { if ( obj->load( file, tag ) ) { add_object( obj ); continue; } else delete obj; } tvio_skip_section(file ); } while ( tag != NULL ); return true; }