//*****************************************************************************************
// Truevision - a 3d modeler for gnome and povray
//
// fog.cc
//
// Christian Spoer <spoer@gmx.de>
//
// Vincent LE PRINCE <vincentleprince@users.sourceforge.net>
// Christian Spoer <spoer@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/fog.h"
#include "include/viewmanager.h"
#include "include/objectlist.h"
#include "include/tvio.h"
#include "include/preferences.h"

//**************************************
// Constructor
//**************************************
Fog::Fog( app_objs *appref ) : Object3D( appref )
{
	type = TV_OBJ3D_FOG;
	category = TV_OBJ3D_ATMOS1;
	set_name( "Fog" );

	rotation = new ObjParam_rotation( N_("UP-Vector"), "ROT", NULL, app_ref, true );
	rotation->set( 0, 0, 0 );
	
	distance = new ObjParam_float (N_("Distance"), "DIST", NULL, app_ref, true, 50.0);
	distance->set_range (1000, 0, 1, 6);
	color = new ObjParam_color (N_("Color"),"COLOR",NULL,app_ref, false);
	color->set (0.5,0.5,0.5);
	transmit  = new ObjParam_float( N_("Transmit"), "TRANS", NULL, app_ref, false, 0 );
	transmit->set_range( 1, 0, 0.01, 6 );
	filter = new ObjParam_float( N_("Filter"), "FILT", NULL, app_ref, false, 0 );
	filter->set_range( 1, 0, 0.01, 6 );
	
	use_turbu = new ObjParam_bool_activator ( N_("Use Turbulence"), "TURB_USED", NULL, app_ref, false, false);
	turbulence = new ObjParam_point ( N_("Turbulence"), "TURB", NULL, app_ref, true );
	turbulence->set( 0, 0, 0 );
	turbulence->set_range( 1, -1, 0.01, 6 );
	turbu_dep = new ObjParam_float ( N_("Depth"), "TDEP", NULL, app_ref, true, 0.5);
	turbu_dep->set_range (100, 0, 0.05, 6);
	omega = new ObjParam_float ( N_("Omega"), "OMEG", NULL, app_ref, true, 0.5);
	omega->set_range (100, 0, 0.1, 6);
	lambda = new ObjParam_float ( N_("Lambda"), "LAMB", NULL, app_ref, true, 2.0);
	lambda->set_range (100, 0, 0.1, 6);
	octaves = new ObjParam_int ( N_("Octaves"), "OCTA", NULL, app_ref, true, 2);
	octaves->set_range (10, 1, 6);
	
	ground_fog = new ObjParam_bool_activator(N_("Groundfog"), "GFOG", NULL, app_ref, true, false);
	fog_offset = new ObjParam_float (N_("Offset"), "OFFS", NULL, app_ref, true, 0.1);
	fog_offset->set_range (100, 0, 0.1, 6);
	fog_alt = new ObjParam_float (N_("Alteration"), "ALT", NULL, app_ref, true, 0.1);
	fog_alt->set_range (100, 0, 0.1, 6);
	
}

Fog::Fog( Fog & ref ) : Object3D( ref )
{
	distance = new ObjParam_float ( *ref.distance );
	rotation = new ObjParam_rotation( *ref.rotation );
	color = new ObjParam_color ( *ref.color );
	transmit = new ObjParam_float( *ref.transmit );
	filter = new ObjParam_float( *ref.filter );
	use_turbu = new ObjParam_bool_activator ( *ref.use_turbu );
	turbulence = new ObjParam_point ( *ref.turbulence );
	turbu_dep = new ObjParam_float ( *ref.turbu_dep );
	omega = new ObjParam_float ( *ref.omega );
	lambda = new ObjParam_float ( *ref.lambda );
	octaves = new ObjParam_int ( *ref.octaves );
	ground_fog = new ObjParam_bool_activator ( *ref.ground_fog );
	fog_offset = new ObjParam_float ( *ref.fog_offset );
	fog_alt = new ObjParam_float ( *ref.fog_alt );
}

Fog::~Fog()
{
	delete rotation;
	delete distance;
	delete color;
	delete transmit;
	delete filter;
	delete use_turbu;
	delete turbulence;
	delete turbu_dep;
	delete omega;
	delete lambda;
	delete octaves;
	delete ground_fog;
	delete fog_offset;
	delete fog_alt;
}

//**************************************
// Display
// only groundfog
//**************************************
void Fog::display( glview *view, bool set_col  )
{
if ( hidden->value() || !ground_fog->value() ) return;
if ( ground_fog->changed() || rotation->changed() || fog_offset->changed() || fog_alt->changed() || turbulence->changed() )
	list.invalidate();

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

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

	if ( set_col ) set_color();
	
	
	gfloat x, y, z, i, j;
	
	const gfloat pas = 0.2;	
	gfloat size =  0.5;
	
	x = 0.0;
	y = 0.0;
	z = 0.0;
	
	glTranslatef( x, y, z );
	rotation->gl_rotate();
	glBegin( GL_QUADS );

	for ( i = -size ; i < size ; i += pas )
		for ( j = -size ; j < size ; j += pas )
		{
				glVertex3f( i, 0, j );
				glVertex3f( i+pas, 0, j );
				glVertex3f( i+pas, 0, j+pas );
				glVertex3f( i, 0, j+pas );
		}
	
    glEnd();
	
	y = fog_offset->value();
	
	if ( y > 0.0)
	{
			glBegin( GL_QUADS );

		for ( i = -size ; i < size ; i += pas )
			for ( j = -size ; j < size ; j += pas )
			{
				glVertex3f( i, y, j );
				glVertex3f( i+pas, y, j );
				glVertex3f( i+pas, y, j+pas );
				glVertex3f( i, y, j+pas );
			}
	    glEnd();
	}
	y += fog_alt->value();
	if ( y > 0.0 )
	{
		glBegin( GL_QUADS );

		for ( i = -size ; i < size ; i += pas )
			for ( j = -size ; j < size ; j += pas )
			{
				glVertex3f( i, y, j );
				glVertex3f( i+pas, y, j );
				glVertex3f( i+pas, y, j+pas );
				glVertex3f( i, y, j+pas );
			}
	
	    	glEnd();
	}		
	glPopMatrix();
	list.end();
	}
}


//***********************************************
// Edit
//***********************************************
void Fog::edit_widget( GtkWidget *wid )
{
	PREF_DEF
	bool tt = pref->tooltips->value();
	// Options communes
	Object3D::edit_widget( wid, false );

	new_table( edit_cont, _("General settings"), 4 );
	distance->get_widget ( table, tt, 1 );
	color->get_widget( table, tt, 2 );
	filter->get_widget( table, tt, 3 );
	transmit->get_widget( table, tt, 4 );

	new_frame( edit_cont, _("Groundfog"));
	GtkWidget *box = gtk_vbox_new( FALSE, 0 );
	ground_fog->get_widget( frame, tt, box );
	gtk_box_pack_start( GTK_BOX(frame), box, TRUE, TRUE, 3 );
	//ground_fog->set_target( box );
	new_table_no_frame( box, 3 );
		rotation->get_widget( table, tt, 1 );
		fog_offset->get_widget( table, tt, 2 );
		fog_alt->get_widget( table, tt, 3 );
	//ground_fog->update_widget();
	
	new_frame ( edit_cont, _("Turbulence"));
	box = gtk_vbox_new( FALSE, 0);
	use_turbu->get_widget( frame, tt, box);
	gtk_box_pack_start( GTK_BOX(frame), box, TRUE, TRUE, 3);
	new_table_no_frame( box, 5 );
		turbulence->get_widget_no_button( table, tt, 1 );
		turbu_dep->get_widget( table, tt, 2 );
		octaves->get_widget( table, tt, 3 );
		omega->get_widget( table, tt, 4 );
		lambda->get_widget( table, tt, 5 );
	
	gtk_widget_show_all( wid );
}

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

switch( vmanager->get_pointer_mode() )
	{

	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 Fog::pref_changed()
{
	Object3D::pref_changed();
	color->pref_changed();
	transmit->pref_changed();
	filter->pref_changed();
	use_turbu->pref_changed();
	turbulence->pref_changed();
	turbu_dep->pref_changed();
	octaves->pref_changed();
	omega->pref_changed();
	lambda->pref_changed();
	ground_fog->pref_changed();
	fog_offset->pref_changed();
	fog_alt->pref_changed();
	rotation->pref_changed();
}

//***********************************************
// Destroy editor
//***********************************************
void Fog::destroy_editor()
{
	Object3D::destroy_editor();
	color->clear_widget();
	transmit->clear_widget();
	filter->clear_widget();
	distance->clear_widget();
	use_turbu->clear_widget();
	turbulence->clear_widget();
	turbu_dep->clear_widget();
	octaves->clear_widget();
	omega->clear_widget();
	lambda->clear_widget();
	ground_fog->clear_widget();
	fog_offset->clear_widget();
	fog_alt->clear_widget();
	rotation->clear_widget();
}

//***********************************************
// Output to povray
//***********************************************
void Fog::output_to_povray_pass1( ofstream & file )
{
file << "\n\n// Fog : " << name->value();
file << "\n#declare "; get_underscore_name( file ); file << " ="; 
	
	file << "\n\n//Fog " << name->value();
	file << "\nfog {\n\t";
	
	if (ground_fog->value())
	{
		file << "\n\tfog_type 2";
		file << "\n\tfog_offset ";
		fog_offset->output_to_povray( file );
		file << "\n\tfog_alt ";
		fog_alt->output_to_povray( file );
		file << "\n\tup <0,1,0>";
		rotation->output_to_povray( file );
	}
	else
	{
		file << "\n\tfog_type 1";
	}
	
	file << "\n\tdistance ";
	distance->output_to_povray( file );
	
	file << "\n\tcolor ";
	file << "rgbft<" << color->get(0) << ',' << color->get(1) << ',';
	file << color->get(2) << ',' << filter->value() << ',' << transmit->value() << '>';		
	
	if (use_turbu->value())
	{
		file << "\n\tturbulence ";
		turbulence->TvWidget_point::output_to_povray( file );
		file << "\n\tturb_depth ";
		turbu_dep->output_to_povray ( file );
		file << "\n\toctaves ";
		octaves->output_to_povray ( file );
		file << "\n\tomega ";
		omega->output_to_povray ( file );
		file << "\n\tlambda ";
		lambda->output_to_povray ( file );
	}
	
	Object3D::output_to_povray_pass1( file );
	file << "\n}";
}



void Fog::save( ofstream & file )
{
	file << "\nFOG{\n";
	save_basics( file );
	color->save( file );
	transmit->save( file );
	filter->save( file );
	distance->save( file );
	use_turbu->save( file );
	turbulence->save( file );
	turbu_dep->save( file );
	octaves->save( file );
	omega->save( file );
	lambda->save( file );
	ground_fog->save( file );
	fog_offset->save( file );
	fog_alt->save( file );

	rotation->save( file );

	file << "\n}";
}

bool Fog::load( ifstream & file, char *ltag )
{
if ( strcmp( ltag, "FOG" ) ) 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 ( color->load( file, tag ) ) continue;
 	if ( filter->load( file, tag ) ) continue;
 	if ( transmit->load( file, tag ) ) continue; 	
	if ( distance->load( file, tag ) ) continue;
	if ( use_turbu->load( file, tag ) ) continue;
	if ( turbulence->load( file, tag ) ) continue;
	if ( turbu_dep->load( file, tag ) ) continue;
	if ( octaves->load( file, tag ) ) continue;
	if ( omega->load( file, tag ) ) continue;
	if ( lambda->load( file, tag ) ) continue;
	if ( ground_fog->load( file, tag ) ) continue;
	if ( fog_offset->load( file, tag ) ) continue;
	if ( fog_alt->load( file, tag ) ) continue;
 	if ( rotation->load( file, tag ) ) continue;
		
	tvio_skip_section(file );
	} while ( tag != NULL );

return true;
}
