//*****************************************************************************************
// Truevision - a 3d modeler for gnome and povray
//
// julia.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.  */ 
//*******************************************************************************************
#include "include/julia.h"
#include "include/viewmanager.h"
#include "include/objectlist.h"
#include "include/tvio.h"
#include "include/preferences.h"

const int algebra_type_num = 2;
const gchar * algebra_type_list[ algebra_type_num ] = { N_("Quaternion"), N_("Hypercomplex") };
const char * algebra_type_output[ algebra_type_num ] = { "quaternion", "hypercomplex" };

const int function_num = 16;
const gchar * function_list[ function_num ] = { "sqr", "cube", "exp", "reciprocal",  "sin", "asin"
	"sinh", "asinh", "cos", "acos", "cosh", "acosh", "tan", "atan", "tanh", "atanh", "log"	};

//**************************************
// Constructeur
//**************************************
Julia::Julia( app_objs *appref ) : Object3D_with_material( appref )
{
type = TV_OBJ3D_JULIA;
category = TV_OBJ3D_OBJECTS;
set_name( "Julia" );

// Base
julia_param = new ObjParam_vector4( N_("Parameter"), "PARAM", NULL, app_ref, false );
julia_param->set( 0, 0, 0, 0 );
algebra = new ObjParam_option_combo(  N_("Algebra type"), "ALG", NULL, app_ref, false );
algebra->set_list( algebra_type_list, algebra_type_num, 0 );
function = new ObjParam_option_combo(	N_("Function"), "FUNC", NULL, app_ref, false );
function->set_list( function_list, function_num, 0 );
max_iteration = new ObjParam_int( N_("Max Iteration"), "MAXIT", NULL, app_ref, false, 20 );
max_iteration->set_range( 500, 1, 1 );
precision = new ObjParam_float( N_("Precision"), "PRESC", NULL, app_ref, false, 20 );
precision->set_range( 500, 0, 1, 4 );
slice = new ObjParam_vector4( N_("Slice"), "SLI", NULL, app_ref, false );
slice->set( 0, 0, 0, 1 );
distance = new ObjParam_float( N_("Distance"), "DIST", NULL, app_ref, 0, false );
distance->set_range( 50, -50, 0.1, 6 );	
	
// Transformation
translate = new ObjParam_point( N_("Translation"), "TRANS", NULL, app_ref, true );
translate->set( 0, 0, 0 );
scale = new ObjParam_scale( N_("Scale"), "SCALE", NULL, app_ref, true );
scale->set( 0.2, 0.2, 0.2 );
rotation = new ObjParam_rotation( N_("Rotation"), "ROT", NULL, app_ref, true );
rotation->set( 0, 0, 0 );
}

Julia::Julia( Julia & ref ) : Object3D_with_material( ref )
{
translate = new ObjParam_point( *ref.translate );
scale = new ObjParam_scale( *ref.scale );
rotation = new ObjParam_rotation( *ref.rotation );
julia_param = new ObjParam_vector4( *ref.julia_param );
algebra = new ObjParam_option_combo( *ref.algebra );
function = new ObjParam_option_combo( *ref.function );
max_iteration = new ObjParam_int( *ref.max_iteration );
precision = new ObjParam_float( *ref.precision );
distance = new ObjParam_float( *ref.distance );
slice = new ObjParam_vector4( *ref.slice );
}

Julia::~Julia()
{
delete translate;
delete scale;
delete rotation;
delete julia_param;
delete algebra;
delete function;
delete max_iteration;
delete precision;
delete distance;
delete slice;
}

//**************************************
// Display
//**************************************
void Julia::display( glview *view, bool set_col )
{
/*if ( hidden->value() ) return;
if ( translate->changed() || scale->changed() || rotation->changed()  )
	list.invalidate();

Object3D::display( view );	
if ( ! list.exec() )
	{
	// mise à zero des parametres
	translate->unchange();
	scale->unchange();
	rotation->unchange();

	// creation de la liste si necessaire
	list.begin();
	glPushMatrix();

	if ( set_col ) set_color();
	
	// Position et direction
	gfloat x, y, z;
	gfloat a, b, c;
	translate->get( x, y, z );
	glTranslatef( x, y, z );
	scale->get( a, b, c );
	glScalef( a, b, c );
	rotation->gl_rotate();

	glPopMatrix();
	list.end();

	}*/
}


//***********************************************
// Edit
//***********************************************
void Julia::edit_widget( GtkWidget *wid )
{
PREF_DEF
bool tt = pref->tooltips->value();
// Options communes
Object3D::edit_widget( wid );
	
// Base
new_table( edit_cont, _("General settings"), 7 );
	julia_param->get_widget( table, tt, 1 );
	julia_param->reduce_size();
	algebra->get_widget( table, tt, 2 );
	function->get_widget( table, tt, 3 );
	max_iteration->get_widget( table, tt, 4 );
	precision->get_widget( table, tt, 5 );
	slice->get_widget( table, tt, 6 );
	slice->reduce_size();
	distance->get_widget( table, tt, 7 );
	
// Options de geometrie
new_table( edit_cont, _("Transformation"), 3 );
	translate->get_widget( table, tt, 1 );
	scale->get_widget( table, tt, 2 );
	rotation->get_widget( table, tt, 3 );

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

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

switch( vmanager->get_pointer_mode() )
	{
	case TV_PMODE_SELECT:
	case TV_PMODE_TRANSLATE:
		translate->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 Julia::pref_changed()
{
Object3D::pref_changed();
translate->pref_changed();
scale->pref_changed();
rotation->pref_changed();
algebra->pref_changed();
function->pref_changed();
max_iteration->pref_changed();
precision->pref_changed();
slice->pref_changed();
distance->pref_changed();
julia_param->pref_changed();
}

//***********************************************
// Destroy editor
//***********************************************
void Julia::destroy_editor()
{
Object3D::destroy_editor();
translate->clear_widget();
scale->clear_widget();
texture->clear_widget();
rotation->clear_widget();
algebra->clear_widget();
function->clear_widget();
max_iteration->clear_widget();
precision->clear_widget();
slice->clear_widget();
distance->clear_widget();
julia_param->clear_widget();
}

//***********************************************
// Output to povray
//***********************************************
void Julia::output_to_povray_pass1( ofstream & file )
{
file << "\n\n// Julia fractal : " << name->value();
file << "\n#declare "; get_underscore_name( file ); file << " ="; 

file << "\njulia_fractal {\n\t";
julia_param->output_to_povray( file );
file << "\n\t" << algebra_type_output[ algebra->value() ];
file << "\n\t" << function_list[ function->value() ];
file << "\n\tmax_iteration " << max_iteration->value();
file << "\n\tprecision " << precision->value();
file << "\n\tslice ";
slice->output_to_povray( file );
file << " , " << distance->value();
float x, y, z;

Object3D_with_material::output_to_povray_pass1( file );
file << "\t";
rotation->output_to_povray( file );

scale->get( x, y, z );
file << "\n\tscale <" << x << ',' << y << ',' << z << ">";
translate->get( x, y, z );
file << "\n\ttranslate <" << x << "," << y << "," << -z << ">";
file << "\n}  ";
}

//***********************************************
// Save & load
//***********************************************
void Julia::save( ofstream & file )
{
file << "\nJULIA{\n";
save_basics( file );
translate->save( file );
scale->save( file );
rotation->save( file );
texture->save( file );
julia_param->save( file );
algebra->save( file );
function->save( file );
max_iteration->save( file );
precision->save( file );
slice->save( file );
distance->save( file );
file << "\n}";
}

bool Julia::load( ifstream & file, char *ltag )
{
if ( strcmp( ltag, "JULIA" ) ) 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 ( translate->load( file, tag ) ) continue;
 	if ( scale->load( file, tag ) ) continue;
 	if ( rotation->load( file, tag ) ) continue;
 	if ( algebra->load( file, tag ) ) continue;
 	if ( function->load( file, tag ) ) continue;
 	if ( max_iteration->load( file, tag ) ) continue;
 	if ( precision->load( file, tag ) ) continue;
 	if ( slice->load( file, tag ) ) continue;
 	if ( distance->load( file, tag ) ) continue;
 	if ( julia_param->load( file, tag ) ) continue;
	
	tvio_skip_section(file );
	} while ( tag != NULL );

return true;
}
