//*****************************************************************************************
// 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.  */ 
//*******************************************************************************************
#ifndef TV_OBJ3D_H
#define TV_OBJ3D_H
using namespace std;
#include <iostream>
#include <fstream>

#include "gnome.h"
#include "GL/gl.h"
#include "GL/glu.h"
//#include "gtkgl/gtkglarea.h"

#include "objparam.h"
#include "main.h"
#include "glview.h"
#include "dlgutils.h"

class ObjectLayer;

//**************************************
// Object Types
//**************************************
enum obj3d {
	TV_OBJ3D_CAMERA = 0,
	TV_OBJ3D_POINTLIGHT,
	TV_OBJ3D_SPOTLIGHT,
	TV_OBJ3D_CYLLIGHT,
	TV_OBJ3D_AREALIGHT,
	TV_OBJ3D_BOX,
	TV_OBJ3D_SPHERE,
	TV_OBJ3D_CYLINDER,
	TV_OBJ3D_CONE,
	TV_OBJ3D_BKGD,
	TV_OBJ3D_CSGUNION,
	TV_OBJ3D_CSGMERGE,
	TV_OBJ3D_CSGINTERSECTION,
	TV_OBJ3D_CSGDIFFERENCE,	
	TV_OBJ3D_PLANE,
	TV_OBJ3D_SKY,
	TV_OBJ3D_TORUS,
	TV_OBJ3D_AMEDIA,
	TV_OBJ3D_DISC,
	TV_OBJ3D_HEIGHTFIELD,
	TV_OBJ3D_SUPERELLIPSOID,
	TV_OBJ3D_FOG,
};
typedef obj3d Object3DType;

enum obj3dcat {
	TV_OBJ3D_NOCAT = 0,
	TV_OBJ3D_LIGHTS,
	TV_OBJ3D_OBJECTS,
	TV_OBJ3D_ATMOS1,
	TV_OBJ3D_ATMOS2,
};
typedef obj3dcat Object3DCategory;




//**************************************
// Classe de base pour les objets 3D
//**************************************
class Object3D {
	#define SENDER ((Object3D*)data)
	friend void sign_entry( GtkWidget *wid, gpointer data ) { SENDER->name_changed(); }
	friend void sign_entry2( GtkWidget *wid, GdkEvent *ev, gpointer data ) { SENDER->name_changed(); }
	friend void sign_hidden_changed( GtkWidget *wid, gpointer data ) { SENDER->set_visibility_pix(); }
	friend void sign_render_changed( GtkWidget *wid, gpointer data ) { SENDER->set_render_pix(); }	
	#undef SENDER

	protected:
		Object3D *parent;
		ObjectLayer *layer;
		Object3DType type;
		Object3DCategory category;
		int pick_name;
		static app_objs *app_ref;
		GlDisplayList list;
		bool update_solid_list, update_wire_list;
		GtkWidget *widget;
		GtkWidget *nm_entry;
		
		GtkCTree *ctree;
		GtkCTreeNode *ctree_node;
		static GdkPixmap *visibility_pix, *visibility_mask;
		static GdkPixmap *render_pix, *render_mask;
		GdkPixmap *object_pix, *object_mask;
		void set_visibility_pix();
		void set_render_pix();

	protected:
		TvWidget_entry *name;
		ObjParam_bool *hidden;
		ObjParam_bool *render;
		ObjParam_bool *no_shadow;
		ObjParam_bool *hollow;
		ObjParam_bool *inverse;
		bool selected;
		GtkWidget *frame;
		GtkWidget *edit_cont;

		void set_name( char *name );
		void new_frame( GtkWidget *wid, const gchar *name );
		virtual void set_color();
		void name_changed();
		
	public:
		Object3D( app_objs *appref );
		Object3D( Object3D & ref );
		virtual ~Object3D();

		virtual Object3D *duplicate_yourself() { return NULL; }
		Object3DType get_type() { return type; }
		Object3DCategory get_category() { return category; }
		char *get_name() { return name->value(); }
		GtkCTreeNode *get_node() { return ctree_node; }
		Object3D *get_parent() { return parent; }
		virtual void set_layer( ObjectLayer *lay ) { layer = lay; }
		ObjectLayer *get_layer() { return layer; }

		virtual void display( glview *view);
		void invalidate_list() { list.invalidate(); }

		virtual void add_to_tree( GtkWidget *tree, GtkCTreeNode *parent, GtkCTreeNode *sibling, const gchar *pixmap = NULL );
		void remove_from_tree() { if ( ctree_node != NULL ) gtk_ctree_remove_node( ctree, ctree_node );  }
		virtual void save_tree() {};
		void toggle_visibility() { hidden->toggle(); hidden->update_widget(); }
		void toggle_render() { render->toggle(); render->update_widget(); }

		virtual void edit_widget( GtkWidget *wid ) { edit_widget( wid, true ); }
		virtual void edit_widget( GtkWidget *wid, bool solid_object );
		void edit_widget_base( GtkWidget *wid );
		virtual void destroy_editor();
		virtual void pref_changed();
		virtual void flush() {}

		virtual void mouse_drag( struct drag_info *drag ) {}
		virtual float *get_location() { return NULL; }
		virtual Rotation *get_rotation() { return NULL; }

		virtual void output_to_povray( ofstream & file );
		void ctree_node_select() { selected = true; gtk_ctree_select( ctree, ctree_node ); }
		void select() { selected = true; list.invalidate(); }
		void unselect();
		virtual void destroy();
		
		virtual void save( ofstream & file ) {}
		virtual void save_basics( ofstream & file );
		virtual bool load( ifstream & file, char *tag ) { return false; }
		virtual bool load_basics( ifstream & file, char *tag );
		void set_load_progress( ifstream & file );
		virtual void get_materials( vector<Material*> & mlist ) {}

		virtual bool is_group() { return false; }
		void set_parent( Object3D *obj ) { parent = obj; }
		virtual void duplicate_object( Object3D *obj ) {}
		virtual void remove_object( Object3D *obj ) {}
		virtual void paste_object( Object3D *obj ) {}		
		virtual void move_child_up( Object3D *obj ) {}
		virtual void move_child_down( Object3D *obj ) {}
		virtual int get_child_pos( Object3D *obj ) { return -1; }
		virtual void insert_child( Object3D *obj, int position ) {}
		virtual bool has_as_ancester( Object3D *obj )  { return false; }
		
		bool pick_test( int name ) { return ( name == pick_name ) ? true : false; }
		void set_list_item_style( GtkStyle *style ) { if ( ctree_node != NULL ) gtk_ctree_node_set_row_style( ctree, ctree_node, style ); }
};

class Object3D_with_material : public Object3D {
	protected:
		ObjParam_texref *texture;

	public:
		Object3D_with_material( app_objs *appref ) : Object3D( appref ) { texture = new ObjParam_texref( _("Material"), "MAT", NULL, app_ref, false ); }
		Object3D_with_material( Object3D_with_material & ref ) : Object3D( ref ) { texture = new ObjParam_texref( *ref.texture );  }
		~Object3D_with_material() { delete texture; }

		//virtual void flush() { texture->flush(); }
		virtual void set_color();
		virtual void destroy_editor() { flush(); Object3D::destroy_editor(); }
		virtual void save( ofstream & file ) { Object3D::save( file ); texture->save( file ); }
		virtual bool load_basics( ifstream & file, char *tag ) { if ( Object3D::load_basics( file, tag ) ) return true; return texture->load( file, tag ); }
		virtual void get_materials( vector<Material*> & mlist ) { texture->get_material( mlist );}
};

#endif
