//*****************************************************************************************
// Truevision - a 3d modeler for gnome and povray
//
// object3d.cc
//
// Vincent LE PRINCE <vincentleprince@users.sourceforge.net>
// 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.  */ 
//*******************************************************************************************
#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 "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,
	TV_OBJ3D_LIGHTGROUP,
	TV_OBJ3D_BLOB,
	TV_OBJ3D_BLOBSPHERE,
	TV_OBJ3D_BLOBCYLINDER,
	TV_OBJ3D_TEXT,
	TV_OBJ3D_LATHE,
	TV_OBJ3D_LINK,
	TV_OBJ3D_GROUP,
	TV_OBJ3D_PRISM,
	TV_OBJ3D_ISOSURFACE,
	TV_OBJ3D_JULIA,
	TV_OBJ3D_PARAMETRIC,
	TV_OBJ3D_POVSCRIPT, 
	TV_OBJ3D_SPHERESWEEP,
	TV_OBJ3D_BICUBIC,
	TV_OBJ3D_SCRIPTOBJ,
};
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 bool sign_entry2( GtkWidget *wid, GdkEvent *ev, gpointer data ) { SENDER->name_changed(); return false; }
	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;
		
		static GtkTreeStore *tree_store;
		static GtkWidget *tree_view;
		static GtkTreeSelection *tree_selection;
		GtkTreeIter node_iter;
		GtkTreeIter *parent_node_iter;
		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;
		ObjParam_bool *no_image;
		ObjParam_bool *no_reflection;
		ObjParam_bool *double_illuminate;
		bool selected;
		GtkWidget *frame, *table;
		GtkWidget *edit_cont;

		void check_name();
		void new_frame( GtkWidget *wid, char *name );
		void new_table( GtkWidget *wid, char *name, int rows );
		void new_table_no_frame( GtkWidget *box, int rows );
		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(); }
		char *get_type_name();
		void get_underscore_name( ofstream & file );
		GtkTreeIter *get_node() { return &node_iter; }
		Object3D *get_parent() { return parent; }
		virtual void set_layer( ObjectLayer *lay ) { layer = lay; }
		ObjectLayer *get_layer() { return layer; }

		virtual void display( glview *view, bool set_color = true );
		void invalidate_list() { list.invalidate(); }
		virtual void set_color();

		virtual void add_to_tree( GtkWidget *view, GtkTreeStore *store, GtkTreeSelection *sel, GtkTreeIter *parent, GtkTreeIter *sibling, const gchar *pixmap = NULL );
		void remove_from_tree() { gtk_tree_store_remove( tree_store, &node_iter );  }
		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 float get_strength_radius() { return 1; }
		virtual float get_strength( float x, float y, float z ) { return 0; }
		virtual bool changed() { return false; }
		virtual void unchange() {}

		virtual void output_to_povray_pass1( ofstream & file );
		virtual void output_to_povray_pass2( ofstream & file ) { if ( !render->value() ) return; file << "\n\tobject {"; get_underscore_name( file ); file << "}"; }
		void tree_node_select() { selected = true; gtk_tree_selection_select_iter( tree_selection, &node_iter ); }
		void set_name( char *name );
		void select() { selected = true; /*list.invalidate();*/ }
		void unselect();
		virtual void destroy();
		virtual void undo( Object3D *copy ) {}
		virtual void push_undo_item();
		
		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; }
		virtual int get_children_num() { return 0; }
		virtual Object3D* get_children( int i ) { return NULL; }
		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; }
		
		virtual 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 ); }
		
		void help_on_object();

		// Access methods
		bool is_hidden() { return hidden->value(); }
		bool is_render() { return render->value(); };
		bool is_no_shadow() { return no_shadow->value(); };
		bool is_hollow() { return hollow->value(); };
		bool is_inverse() { return inverse->value(); };
		bool is_no_image() { return no_image->value(); };
		bool is_no_reflection() { return no_reflection->value(); };
		bool is_double_illuminate() { return double_illuminate->value(); };
		bool is_selected() { return selected; }
		
		void set_hidden( bool val ) { hidden->set( val ); hidden->update_widget(); }
		void set_render( bool val ) { render->set( val ); render->update_widget(); }
		void set_no_shadow( bool val ) { no_shadow->set( val ); no_shadow->update_widget(); }
		void set_hollow( bool val ) { hollow->set( val ); hollow->update_widget(); }
		void set_inverse( bool val ) { inverse->set( val ); inverse->update_widget(); }
		void set_no_image( bool val ) { no_image->set( val ); no_image->update_widget(); }
		void set_no_reflection( bool val ) { no_reflection->set( val ); no_reflection->update_widget(); }
		void set_double_illuminate( bool val ) { double_illuminate->set( val ); double_illuminate->update_widget(); }
};

class Object3D_with_material : public Object3D {
	protected:
		ObjParam_texref *texture;
		ObjParam_bool *target, *refraction, *reflection, *collect, *pass_through;
		ObjParam_float *spacing;

	public:
		Object3D_with_material( app_objs *appref );
		Object3D_with_material( Object3D_with_material & ref );
		~Object3D_with_material();

		//virtual void flush() { texture->flush(); }
		virtual void set_color();
		virtual void destroy_editor();
		virtual void save_basics( ofstream & file );
		virtual bool load_basics( ifstream & file, char *tag );
		virtual void get_materials( vector<Material*> & mlist ) { texture->get_material( mlist ); }
		void get_texture_widgets( GtkWidget *wid, bool tt );
		virtual void output_to_povray_pass1( ofstream & file );

		// Access methods
		bool is_target() { return target->value(); }
		bool is_refraction() { return refraction->value(); }
		bool is_reflection() { return reflection->value(); }
		bool is_collect() { return collect->value(); }
		bool is_pass_through() { return pass_through->value(); }
		void set_target( bool val ) { target->set( val ); }
		void set_refraction( bool val ) { refraction->set( val ); }
		void set_reflection( bool val ) { reflection->set( val ); }
		void set_collect( bool val ) { collect->set( val ); }
		void set_pass_through( bool val ) { pass_through->set( val ); }
		float get_spacing() { return spacing->value(); }
		void set_spacing( float sp ) { spacing->set( sp ); } 
};

#endif
