//*****************************************************************************************
// Truevision - a 3d modeler for gnome and povray
//
// object3d.cc
//
// Vincent LE PRINCE <vincentleprince@users.sourceforge.net>
// 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/object3d.h"
#include "include/objectlist.h"
#include "include/interface.h"
#include "include/preferences.h"
#include "include/viewmanager.h"
#include "include/scene.h"

//**************************************
// Définition
//**************************************
GdkPixmap *Object3D::visibility_pix = NULL;
GdkPixmap *Object3D::visibility_mask = NULL;
GdkPixmap *Object3D::render_pix = NULL;
GdkPixmap *Object3D::render_mask = NULL;

app_objs *Object3D::app_ref = NULL;

//**************************************
// Noms des objets
//**************************************
const char *obj_names[] = {
	N_("Camera"),
	N_("Point light"),
	N_("Spot light"),
	N_("Cylindrical Light"),
	N_("Area Light"),
	N_("Box"),
	N_("Sphere"),
	N_("Cylinder"),
	N_("Cone"),
	N_("Background"),
	N_("Union"),
	N_("Merge"),
	N_("Intersection"),
	N_("Difference"),
	N_("Plane"),
	N_("Sky Sphere"),
	N_("Torus"),
	N_("Atmospheric Media"),
	N_("Disc"),
	N_("Heightfield"),
	N_("Superellipsoid"),
	N_("Fog"),
};


//**************************************
// Constructeur
//**************************************
Object3D::Object3D( app_objs *appref )
{
app_ref = appref;
parent = NULL;
layer = NULL;
hidden = new ObjParam_bool( N_("hide"), "HIDDE", NULL, app_ref, true, false );
render = new ObjParam_bool( N_("render"), "RENDER", NULL, app_ref, false, true );
hollow = new ObjParam_bool( N_("hollow"), "HOLLOW", NULL, app_ref, false, false );
no_shadow = new ObjParam_bool(N_("no shadow"), "NOSHAD", NULL, app_ref, false, false );
inverse  = new ObjParam_bool( N_("inverse"), "INV", NULL, app_ref, false, false );

name = new TvWidget_entry( N_("Name"), "NAME", NULL, app_ref );
selected = false;
ctree = NULL;
nm_entry = NULL;
object_pix = object_mask = NULL;
}

Object3D::Object3D( Object3D & ref )
{
type = ref.type;
parent = ref.parent;
layer = ref.layer;
category = ref.category;
hidden = new ObjParam_bool( *ref.hidden );
render = new ObjParam_bool( *ref.render );
hollow =  new ObjParam_bool( *ref.hollow );
no_shadow =  new ObjParam_bool( *ref.no_shadow );
inverse =  new ObjParam_bool( *ref.inverse );
selected = false;
ctree = NULL;
ctree_node = NULL;
nm_entry = NULL;

name = new TvWidget_entry( N_("Name"), "NAME", NULL, app_ref );
set_name( ref.name->value() );
object_pix = object_mask = NULL;
}

//**************************************
// Destructeur
//**************************************
Object3D::~Object3D()
{
delete hidden;
delete render;
delete hollow;
delete no_shadow;
delete name;
delete inverse;
if ( object_pix != NULL )
	{
	gdk_pixmap_unref( object_pix );
	gdk_pixmap_unref( object_mask );
	}
}


void Object3D::unselect()
{ 
selected = false; 
if ( ctree != NULL ) gtk_ctree_unselect( ctree, ctree_node );
list.invalidate(); 
}


//**************************************
// Set Name
//**************************************
void Object3D::name_changed()
{
if ( !name->has_changed() ) return;
set_name( name->get_current_value() );
}

void Object3D::set_name( char *nm )
{
OBJLIST_DEF
char *test = new char[ strlen(nm) + 1 ];
strcpy( test, nm );

char *res = objlist->create_name( test );
if ( res != NULL ) 
	{
	name->set(res);
	delete res;
	}
else name->set(test);
delete test;

name->update_widget();
if ( GTK_IS_WIDGET(ctree) ) gtk_ctree_node_set_text( ctree, ctree_node, 3, name->value() );
}



//**************************************
// Set Picking name
//**************************************
void Object3D::display( glview *view )
{
OBJLIST_DEF
pick_name = objlist->get_pick_name();
glLoadName( pick_name );
}


//**************************************
// Set Color
//**************************************
void Object3D::set_color()
{
PREF_DEF 
if ( selected ) pref->objsel_color->gl_set_rgb();
else pref->obj_color->gl_set_rgb();
}

void Object3D_with_material::set_color()
{
PREF_DEF 
if ( selected ) pref->objsel_color->gl_set_rgb();
else 
	if ( ! texture->gl_set_material() ) pref->obj_color->gl_set_rgb();
}

//**************************************
// Add to tree
//**************************************
void Object3D::add_to_tree( GtkWidget *tree, GtkCTreeNode *parent_node, GtkCTreeNode *sibling, const gchar *pixspe )
{
ctree = GTK_CTREE(tree);
gchar *titre[] = { NULL, NULL, (gchar*)obj_names[type], name->value() };

INTERF_DEF
GdkColor transparent;
char *pixmap = NULL;
if ( object_pix == NULL )
	{
	pixmap = (char*)pixspe;
	//pixmap = gnome_pixmap_file( ( pixmap == NULL ) ? "Truevision/object_default.xpm" : pixspe );
	pixmap = tv_get_pixmap( ( pixmap == NULL ) ? (char*)"object_default.xpm" : (char*)pixspe );
	object_pix = gdk_pixmap_create_from_xpm( interf->get_gdkwin(), &object_mask, &transparent, pixmap );
	delete pixmap;
	}
ctree_node = gtk_ctree_insert_node( ctree, parent_node, sibling, titre, 10, object_pix, object_mask, object_pix, object_mask, FALSE, TRUE );
gtk_ctree_node_set_row_data( ctree, ctree_node, (gpointer)this );

if ( visibility_pix == NULL )
	{
	//pixmap = gnome_pixmap_file( "Truevision/object_visible.xpm" ); 
	pixmap = tv_get_pixmap( "object_visible.xpm"  );	
	visibility_pix = gdk_pixmap_create_from_xpm( interf->get_gdkwin(), &visibility_mask, &transparent, pixmap );
	delete pixmap;
	}
if ( !hidden->value() ) gtk_ctree_node_set_pixmap( ctree, ctree_node, 0, visibility_pix, visibility_mask );

if ( render_pix == NULL )
	{
	//pixmap = gnome_pixmap_file( "Truevision/render.xpm" );
	pixmap = tv_get_pixmap( "render.xpm"  );	
	render_pix = gdk_pixmap_create_from_xpm( interf->get_gdkwin(), &render_mask, &transparent, pixmap );
	delete pixmap;
	}
if ( render->value() ) gtk_ctree_node_set_pixmap( ctree, ctree_node, 1, render_pix, render_mask );
}

void Object3D::destroy()
{
gtk_ctree_remove_node( GTK_CTREE(ctree), ctree_node );
delete this;
}


//**************************************
// Editeur
//**************************************
void Object3D::edit_widget_base( GtkWidget *wid  )
{
OBJLIST_DEF
bool tt = true;
objlist->clear_current_param();
widget = wid;

// Type de l'objet
GtkWidget *frame = gtk_frame_new(NULL);
gtk_box_pack_start( GTK_BOX(wid), frame, FALSE, TRUE, 0 );
GtkWidget *label = gtk_label_new( obj_names[type] );
gtk_container_add( GTK_CONTAINER(frame), label );

// Nom
name->get_widget( wid, tt );
name->connect_signal( GTK_SIGNAL_FUNC(sign_entry), this );
name->connect_signal2( GTK_SIGNAL_FUNC(sign_entry2), this );

// Container
GtkWidget *scrolled = gtk_scrolled_window_new( NULL, NULL );
gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
gtk_box_pack_start( GTK_BOX(wid), scrolled, TRUE, TRUE, 4 );
GtkWidget *viewp = gtk_viewport_new( NULL, NULL );
gtk_viewport_set_shadow_type( GTK_VIEWPORT(viewp), GTK_SHADOW_ETCHED_IN /*GTK_SHADOW_NONE*/ );
gtk_container_add( GTK_CONTAINER(scrolled), viewp );
edit_cont = gtk_vbox_new( FALSE, 0 );
gtk_container_set_border_width( GTK_CONTAINER(edit_cont), 1 );
gtk_container_add( GTK_CONTAINER(viewp), edit_cont );
}

void Object3D::edit_widget( GtkWidget *wid , bool solid_object  )
{
bool tt = true;
edit_widget_base( wid );
hidden->get_widget( edit_cont, tt );
hidden->connect_signal( GTK_SIGNAL_FUNC(sign_hidden_changed), this );
render->get_widget( edit_cont, tt );
render->connect_signal( GTK_SIGNAL_FUNC(sign_render_changed), this );

if ( !solid_object ) return;
hollow->get_widget( edit_cont, tt );
no_shadow->get_widget( edit_cont, tt );
inverse->get_widget( edit_cont, tt );
}

//**************************************
// Frame
//**************************************
void Object3D::new_frame( GtkWidget *wid, const gchar *nom )
{
GtkWidget *Frame = gtk_frame_new( nom );
gtk_box_pack_start( GTK_BOX(wid), Frame, FALSE, TRUE, 4 );
frame = gtk_vbox_new( FALSE, 0 );
gtk_container_add( GTK_CONTAINER(Frame), frame );
gtk_container_set_border_width( GTK_CONTAINER(frame), 2 );
}

//**************************************
// Pref_changed
//**************************************
void Object3D::pref_changed()
{
hidden->pref_changed();
render->pref_changed();
hollow->pref_changed();
no_shadow->pref_changed();
inverse->pref_changed();
list.invalidate();
}

//**************************************
// Destroy editor
//**************************************
void Object3D::destroy_editor()
{
flush();
gtk_widget_destroy( widget );
hidden->clear_widget();
render->clear_widget();
hollow->clear_widget();
no_shadow->clear_widget();
name->clear_widget();
inverse->clear_widget();
}

//**************************************
// Set visibility pix
//**************************************
void Object3D::set_visibility_pix()
{
if ( !hidden->value() ) gtk_ctree_node_set_pixmap( ctree, ctree_node, 0, visibility_pix, visibility_mask );
else gtk_ctree_node_set_text( ctree, ctree_node, 0, NULL );
}

void Object3D::set_render_pix()
{
if ( render->value() ) gtk_ctree_node_set_pixmap( ctree, ctree_node, 1, render_pix, render_mask );
else gtk_ctree_node_set_text( ctree, ctree_node, 1, NULL );
}

//**************************************
// MOUSE
//**************************************
/*void Object3D::mouse_translate( float dest[3], float normal[3], float ox, float oy, float x, float y )
{
//float xoffset = x - ox;
//float yoffset = y - oy;

}*/


//**************************************
// Output to povray
//**************************************
void Object3D::output_to_povray( ofstream & file )
{
if ( hollow->value() ) file << "\n\thollow ";
if ( no_shadow->value() ) file << "\n\tno_shadow";
if ( inverse->value() ) file << "\n\tinverse";
//file << "\n\t";
}


void Object3D::save_basics( ofstream & file )
{
SCENE_DEF
scene->set_save_progress();
name->save( file );
hidden->save( file );
hollow->save( file );
render->save( file );
no_shadow->save( file );
inverse->save( file );
}

bool Object3D::load_basics( ifstream & file, char *tag )
{
if ( name->load( file, tag ) ) return true;
if ( hidden->load( file, tag ) ) return true;
if ( hollow->load( file, tag ) ) return true;
if ( render->load( file, tag ) ) return true;
if ( no_shadow->load( file, tag ) ) return true;
if ( inverse->load( file, tag ) ) return true;
return false;
}

void Object3D::set_load_progress( ifstream & file )
{
SCENE_DEF
scene->set_load_progress( file );
}
