//*****************************************************************************************
// Truevision - a 3d modeler for gnome and povray
//
// disc.cc
//
// Christian Spoer <spoer@gmx.de>
//
// 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.  */
//*******************************************************************************************
#include "include/disc.h"
#include "include/viewmanager.h"
#include "include/objectlist.h"
#include "include/tvio.h"
#include "include/preferences.h"

/* Some <math.h> files do not define M_PI... */
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

//**************************************
// Constructeur
//**************************************
Disc::Disc( app_objs *appref ) : Object3D_with_material( appref )
{
	type = TV_OBJ3D_DISC;
	category = TV_OBJ3D_OBJECTS;
	set_name( "Disc" );
	
	// Base
	location = new ObjParam_point( N_("Location"), "LOC", NULL, app_ref, true );
	location->set( 0, 0, 0 );
	scale = new ObjParam_scale( N_("Scale"), "SIZE", NULL, app_ref, true );
	scale->set( 1, 1, 1 );
	radius = new ObjParam_float( N_("Radius"), "RADI", NULL, app_ref, true, 0.5 );
	radius->set_range( 100, 0, 0.1, 4 );
	hole_radius = new ObjParam_float( N_("Hole radius"), "HORA", NULL, app_ref, true, 0.0 );
	hole_radius->set_range( 100, 0, 0.1, 4 );
	rotation = new ObjParam_rotation( N_("Rotation"), "ROT", NULL, app_ref, true );
	rotation->set( 0, 0, 0 );
}

Disc::Disc( Disc & ref ) : Object3D_with_material( ref )
{
	location = new ObjParam_point( *ref.location );
	scale = new ObjParam_scale( *ref.scale );
	rotation = new ObjParam_rotation( *ref.rotation );
	radius = new ObjParam_float( *ref.radius );
	hole_radius = new ObjParam_float( *ref.hole_radius );
}

Disc::~Disc()
{
	delete location;
	delete scale;
	delete rotation;
	delete radius;
	delete hole_radius;
}

//**************************************
// Display
//**************************************
void Disc::display( glview *view, bool set_col )
{
	if ( hidden->value() ) return;
	if ( location->changed() || scale->changed() || rotation->changed() || radius->changed() || hole_radius->changed() )
		list.invalidate();
		
	Object3D::display( view );	
	if ( set_col ) set_color();
	if ( ! list.exec() )
		{
		// mise à zero des parametres
		location->unchange();
		scale->unchange();
		rotation->unchange();
		radius->unchange();
		hole_radius->unchange();
	
		// creation de la liste si necessaire
		list.begin();
		glPushMatrix();
	
	
		// Position et direction
		gfloat a, b, c;
		location->get( a, b, c );
		glTranslatef( a, b, c );
		scale->get( a, b, c );
		glScalef( a, b, c );
		rotation->gl_rotate();

       GLUquadricObj *quadobj = gluNewQuadric();
       if ( !quadobj ) { app_warning( N_("Out of memory" ) ); return;  }
		gluQuadricDrawStyle( quadobj, GLU_FILL );
		gluQuadricNormals( quadobj, GLU_SMOOTH );
		gluQuadricOrientation( quadobj, GLU_OUTSIDE );
       gluDisk(quadobj, hole_radius->value(), radius->value(),16, 1);


   	glEnd();

	glPopMatrix();
	list.end();
	}
}


//***********************************************
// Edit
//***********************************************
void Disc::edit_widget( GtkWidget *wid )
{
	PREF_DEF
	bool tt = pref->tooltips->value();
	// Options communes
	Object3D::edit_widget( wid );
	
	// Options de geometrie
	new_table( edit_cont, _("General settings"), 5 );
		location->get_widget( table, tt, 1 );
		hole_radius->get_widget( table, tt, 2 );
		radius->get_widget( table, tt, 3 );
		scale->get_widget( table, tt, 4 );
		rotation->get_widget( table, tt, 5 );

	get_texture_widgets( edit_cont, tt );
	
	gtk_widget_show_all( wid );
}

//***********************************************
// Mouse drag
//***********************************************
void Disc::mouse_drag( struct drag_info *drag )
{
	VMAN_DEF
	OBJLIST_DEF

	switch( vmanager->get_pointer_mode() )
	{
	case TV_PMODE_SELECT:
		case TV_PMODE_TRANSLATE:
			location->mouse_drag( drag );
			break;
	
		case TV_PMODE_SCALE:
			{ scale->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 Disc::pref_changed()
{
	Object3D::pref_changed();
	location->pref_changed();
	scale->pref_changed();
	rotation->pref_changed();
	radius->pref_changed();
	hole_radius->pref_changed();
}

//***********************************************
// Destroy editor
//***********************************************
void Disc::destroy_editor()
{
	Object3D::destroy_editor();
	location->clear_widget();
	scale->clear_widget();
	texture->clear_widget();
	rotation->clear_widget();
	radius->clear_widget();
	hole_radius->clear_widget();
}

//***********************************************
// Output to povray
//***********************************************
void Disc::output_to_povray_pass1( ofstream & file )
{
file << "\n\n// Disc : " << name->value();
file << "\n#declare "; get_underscore_name( file ); file << " ="; 
	
	float x, y, z;
	
	// Check if the radius of the hole is greater than the
	// outer radius.
	if ( hole_radius->value() > radius->value())
	{
		x = radius->value();
		radius->set( hole_radius->value());
		hole_radius->set( x);
	}
	
	file << "\n\n//Disc " << name->value();
	file << "\ndisc {\n\t";
	file << "<0.0, 0.0, 0.0>";
	file << "<0.0, 0.0, 1.0>";
	file << radius->value() << ", " << hole_radius->value();
	Object3D_with_material::output_to_povray_pass1( file );
	
	scale->get( x, y, z );
	file << "\n\tscale <" << x << ", " << y << ", " << z << ">";
	rotation->output_to_povray( file );
	location->get( x, y, z );
	file << "\n\ttranslate <" << x << "," << y << "," << -z << "> \n\t";
	//if ( ring->value() ) file << "\n\tring";
	file << "\n}";
}


void Disc::save( ofstream & file )
{
	file << "\nDISC{\n";
	save_basics( file );
	location->save( file );
	scale->save( file );
	rotation->save( file );
	radius->save( file );
	hole_radius->save( file );
	texture->save( file );
	file << "\n}";
}

bool Disc::load( ifstream & file, char *ltag )
{
	if ( strcmp( ltag, "DISC" ) ) return false;
set_load_progress( file );

	char * tag = NULL;
	do {
		tag = tvio_get_next_tag( file );
		if ( tag == NULL ) break;
		
		if ( load_basics( file, tag ) ) continue;
	 	if ( location->load( file, tag ) ) continue;
 		if ( scale->load( file, tag ) ) continue;
 		if ( rotation->load( file, tag ) ) continue;
 		if ( radius->load( file, tag ) ) continue;
 		if ( hole_radius->load( file, tag ) ) continue;
			
		tvio_skip_section(file );
	} while ( tag != NULL );

	return true;
}
