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

//**************************************
// Définitions
//**************************************
const int sampling_type_num = 3;
const char *sampling_type_list[sampling_type_num] = {
	N_("Monte Carlo integration"),
	N_("Distributive sampling"),
	N_("Adaptative sampling"),
	};

int PovTexMedia::count=0;

PovTexMedia::PovTexMedia( app_objs *appref, char *tagname, void (*asuicidal_func)(gpointer, gpointer), gpointer amother ) : MaterialItem( app_ref, tagname )
{
num = ++count;
char text[25];
sprintf( text, "Media #%u", num );
set_name( text );
item_type = TV_MITEM_MEDIA;

suicidal_func = asuicidal_func;
mother = amother;
tree_store = NULL;

intervals = new TvWidget_int( N_("Intervals"), "INTERV", NULL, app_ref, 10 );
intervals->set_range( 1000, 1, 1 );
sample_min = new TvWidget_int( N_("min sample"), "SAMPMIN", NULL, app_ref, 1 );
sample_min->set_range( 1000, 1, 1 );
sample_max = new TvWidget_int( N_("max sample"), "SAMPMAX", NULL, app_ref, 1 );
sample_max->set_range( 1000, 1, 1 );
confidence = new TvWidget_float( N_("Confidence"), "CONF", NULL, app_ref, 0.9 );
confidence->set_range( 0.9999, 0.0001, 0.1, 4 );
variance = new TvWidget_float( N_("Variance"), "VAR", NULL, app_ref, 0.00782 );
variance->set_range( 1, 0.0001, 0.1, 5 );
ratio = new TvWidget_float( N_("Ratio"), "RATIO", NULL, app_ref, 1 );
ratio->set_range( 1, 0, 0.1, 3 );
jitter = new TvWidget_float( N_("Jitter"), "JITTER", NULL, app_ref, 0 );
jitter->set_range( 100, 0, 0.1, 3 );
aa_level = new TvWidget_int( N_("Antialiasing level"), "AALEVEL", NULL, app_ref, 4 );
aa_level->set_range( 100, 1, 1 );
aa_threshold = new TvWidget_float( N_("Antialiasing threshold"), "AATHRES", NULL, app_ref, 0.1 );
aa_threshold->set_range( 100, 0, 0.1, 3 );
sampling_method = new TvWidget_option_combo( N_("Sampling method"), "METHOD", NULL, app_ref );
sampling_method->set_list( sampling_type_list, sampling_type_num, 0 );


absorption = new TvWidget_pigment_rb( N_("Absorption"), "ABSORP", NULL, app_ref );
absorption->set( 0, 0, 0, 0 );
emission = new TvWidget_pigment_rb( N_("Emission"), "EMIT", NULL, app_ref );
emission->set( 0, 0, 0, 0 );
scattering = new TvWidget_scattering_rb( N_("Scattering"), "SCATTER", NULL, app_ref );
transfo = new TvWidget_transformation_rb( N_("Transformation"), "TRANSFO", NULL, app_ref );
}


PovTexMedia::PovTexMedia( PovTexMedia & ref ) : MaterialItem( ref )
{
set_name( ref.get_name() );
item_type = TV_MITEM_MEDIA;

intervals = new TvWidget_int( *ref.intervals );
sample_min = new TvWidget_int( *ref.sample_min );
sample_max = new TvWidget_int( *ref.sample_max );
confidence = new TvWidget_float( *ref.confidence );
variance = new TvWidget_float( *ref.variance );
ratio = new TvWidget_float( *ref.ratio );
sampling_method = new TvWidget_option_combo( *ref.sampling_method );
jitter = new TvWidget_float( *ref.jitter );
aa_level = new TvWidget_int( *ref.aa_level );
aa_threshold = new TvWidget_float( *ref.aa_threshold );

absorption = new TvWidget_pigment_rb( *ref.absorption );
emission = new TvWidget_pigment_rb( *ref.emission );
scattering = new TvWidget_scattering_rb( *ref.scattering );
transfo = new TvWidget_transformation_rb( *ref.transfo );

for ( unsigned int i = 0 ; i < ref.density_liste.size() ; i++ )
	{
	PovTexDensity *item =  new PovTexDensity( *ref.density_liste[i] );
	density_liste.push_back( item );
	}
}


PovTexMedia::~PovTexMedia()
{
delete intervals;
delete sample_min;
delete sample_max;
delete confidence;
delete variance;
delete ratio;
delete sampling_method;
delete jitter;
delete aa_level;
delete aa_threshold;
delete absorption;
delete emission;
delete scattering;
delete transfo;
for ( unsigned int i = 0 ; i < density_liste.size() ; i++ )
	delete density_liste[i];
}		



void PovTexMedia::add_to_tree( GtkTreeView *view, GtkTreeStore *store, GtkTreeSelection *selection, GtkTreeIter *parent, GtkTreeIter *sibling )
{
MaterialItem::add_to_tree( view, store, selection, parent, sibling );
for ( unsigned int i = 0 ; i < density_liste.size() ; i++ )
	density_liste[i]->add_to_tree( view, store, selection, &node_iter );
}

void PovTexMedia::remove_from_tree()
{
for ( unsigned int i = 0 ; i < density_liste.size() ; i++ )
	density_liste[i]->remove_from_tree();
MaterialItem::remove_from_tree();
}

void PovTexMedia::save_node_state()
{
MaterialItem::save_node_state();
for ( unsigned int i = 0 ; i < density_liste.size() ; i++ )
	density_liste[i]->save_node_state();
}


void PovTexMedia::edit_widget( GtkWidget *box )
{
PREF_DEF
bool tt = pref->tooltips->value();
MaterialItem::edit_widget( box, _("Media") );

GtkWidget *vbox = gtk_vbox_new( FALSE, 0 );
gtk_box_pack_start( GTK_BOX(edit_cont), vbox, TRUE, TRUE, 0 );

GtkWidget *frame_box = new_table( vbox, _("General"), 10 );
	sampling_method->get_widget( frame_box, tt, 1 );
	intervals->get_widget( frame_box, tt, 2 );
	sample_min->get_widget( frame_box, tt, 3 );
	sample_max->get_widget( frame_box, tt, 4 );
	confidence->get_widget( frame_box, tt, 5 );
	variance->get_widget( frame_box, tt, 6 );
	ratio->get_widget( frame_box, tt, 7 );
	jitter->get_widget( frame_box, tt, 8 );
	aa_level->get_widget( frame_box, tt, 9 );
	aa_threshold->get_widget( frame_box, tt, 10 );

absorption->get_widget_rb( vbox, tt );
emission->get_widget_rb( vbox, tt );
scattering->get_widget_rb( vbox, tt );
transfo->get_widget_rb( vbox, tt );

GtkWidget *del_button = gtk_button_new_with_label( _("Delete this media") );
gtk_box_pack_start( GTK_BOX(vbox), del_button, FALSE, TRUE, 2 );
gtk_signal_connect( GTK_OBJECT(del_button), "clicked", GTK_SIGNAL_FUNC(sign_media_delete), this );

GtkWidget *add_button = gtk_button_new_with_label( _("Add density") );
gtk_box_pack_start( GTK_BOX(vbox), add_button, FALSE, TRUE, 2 );
gtk_signal_connect( GTK_OBJECT(add_button), "clicked", GTK_SIGNAL_FUNC(sign_media_add_density), this );

gtk_widget_show_all( widget );
}

void PovTexMedia::destroy_widget()
{
MaterialItem::destroy_widget();
intervals->clear_widget();
sample_min->clear_widget();
sample_max->clear_widget();
confidence->clear_widget();
variance->clear_widget();
ratio->clear_widget();
sampling_method->clear_widget();
jitter->clear_widget();
aa_level->clear_widget();
aa_threshold->clear_widget();
absorption->clear_widget();
emission->clear_widget();
scattering->clear_widget();
transfo->clear_widget();
}

void PovTexMedia::flush()
{
intervals->flush();
sample_min->flush();
sample_max->flush();
confidence->flush();
variance->flush();
ratio->flush();
sampling_method->flush();
jitter->flush();
aa_level->flush();
aa_threshold->flush();
absorption->flush();
emission->flush();
scattering->flush();
transfo->flush();
}

void PovTexMedia::output_to_povray( ofstream & file )
{
file << "\n\t\tmedia {";
file << "\n\t\t\tintervals ";
intervals->output_to_povray( file );
file << "\n\t\t\tsamples ";
sample_min->output_to_povray( file );
file << ", ";
sample_max->output_to_povray( file );
file << "\n\t\t\tconfidence ";
confidence->output_to_povray( file );
file << "\n\t\t\tvariance ";
variance->output_to_povray( file );
file << "\n\t\t\tratio ";
ratio->output_to_povray( file );
file << "\n\t\t\tmethod " << sampling_method->value() + 1;
file << "\n\t\t\tjitter ";
jitter->output_to_povray( file );
file << "\n\t\t\taa_level ";
aa_level->output_to_povray( file );
file << "\n\t\t\taa_threshold ";
aa_threshold->output_to_povray( file );

file << "\n\t\t\tabsorption ";
absorption->output_to_povray( file );
file << "\n\t\t\temission ";
emission->output_to_povray( file );
scattering->output_to_povray( file );

for ( unsigned int i = 0 ; i < density_liste.size() ; i ++ )
	density_liste[i]->output_to_povray( file );

transfo->output_to_povray( file );
file << "\n\t\t}";
}


void PovTexMedia::save( ofstream & file )
{
file << "\nMEDIA{";
name->save( file );
expand->save( file );
intervals->save( file );
sample_min->save( file );
sample_max->save( file );
confidence->save( file );
variance->save( file );
ratio->save( file );
sampling_method->save( file );
jitter->save( file );
aa_level->save( file );
aa_threshold->save( file );
absorption->save( file );
emission->save( file );
scattering->save( file );

for ( unsigned int i = 0 ; i < density_liste.size() ; i ++ )
	density_liste[i]->save( file );

transfo->save( file );
file << "} ";
}


bool PovTexMedia::load( ifstream & file, char * ltag )
{
if ( strcmp( "MEDIA", ltag ) ) return false;
char * tag = NULL;

do
	{
	tag = tvio_get_next_tag( file );
	if ( tag == NULL ) break;
	if (name->load( file , tag ) ) continue;	
	if (expand->load( file , tag ) ) continue;	
	if (intervals->load( file , tag ) ) continue;
	if (sample_min->load( file , tag ) ) continue;
	if (sample_max->load( file , tag ) ) continue;	
	if (confidence->load( file , tag ) ) continue;
	if (variance->load( file , tag ) ) continue;
	if (ratio->load( file , tag ) ) continue;
	if (sampling_method->load( file , tag ) ) continue;
	if (jitter->load( file , tag ) ) continue;
	if (aa_level->load( file , tag ) ) continue;
	if (aa_threshold->load( file , tag ) ) continue;
	if (absorption->load( file , tag ) ) continue;	
	if (emission->load( file , tag ) ) continue;
	if (scattering->load( file , tag ) ) continue;
	if (transfo->load( file , tag ) ) continue;	
	
	if ( ! strcmp( "DENSITY", tag ) ) 
		{
		PovTexDensity *newone = new PovTexDensity( app_ref, "DENSITY", sign_media_density_suicide, (gpointer)this );
		newone->load( file, tag );
		density_liste.push_back( newone );
		continue;
		}
	tvio_skip_section( file );
	}
while( tag != NULL );
return true;
}


void PovTexMedia::add_density()
{
PovTexDensity *newone = new PovTexDensity( app_ref, "DENSITY", sign_media_density_suicide, (gpointer)this );
density_liste.push_back( newone );
newone->add_to_tree( tree_view, tree_store, tree_selection, &node_iter );
}

void PovTexMedia::delete_density( PovTexDensity * density )
{
vector<PovTexDensity*>::iterator it = density_liste.begin();
while ( it != density_liste.end() )
	{
	if ( *it == density )
		{
		//gtk_ctree_select( ctree, ctree_node );
		select_tree_row();
		density->remove_from_tree();
		density_liste.erase( it );
		delete density;		
		break;
		}
	it++;
	}
}


bool PovTexMedia::paste( MaterialItem *item )
{
switch ( item->get_type() )
	{
	default :
		return false;
		break;
		
	case TV_MITEM_DENSITY:
		{
		PovTexDensity *dens = new PovTexDensity(  *(PovTexDensity*)item );
		density_liste.push_back( dens );
		dens->set_params( sign_media_density_suicide, (gpointer)this );
		dens->add_to_tree( tree_view, tree_store, tree_selection, &node_iter );
		}
		break;
	
	case TV_MITEM_MEDIA:
		{
		PovTexMedia *med = (PovTexMedia*)item;
		for ( unsigned int i = 0 ; i < density_liste.size() ; i ++ ) delete density_liste[i];
		density_liste.clear();
       for ( unsigned int i = 0 ; i < med->density_liste.size() ; i++ )
			{
			PovTexDensity *it =  new PovTexDensity( *(med->density_liste[i]) );
			it->set_params( sign_media_density_suicide, (gpointer)this );
			density_liste.push_back( it );
			}
			
		if ( GTK_IS_WIDGET(widget) )
			{
			gtk_widget_destroy( edit_cont );
			intervals->clear_widget();
			sample_min->clear_widget();
			sample_max->clear_widget();
			confidence->clear_widget();
			variance->clear_widget();
			ratio->clear_widget();
			sampling_method->clear_widget();
			jitter->clear_widget();
			aa_level->clear_widget();
			aa_threshold->clear_widget();
			absorption->clear_widget();
			emission->clear_widget();
			scattering->clear_widget();
			transfo->clear_widget();
			}
		intervals->copy( med->intervals );
		sample_min->copy( med->sample_min );
		sample_max->copy( med->sample_max );
		confidence->copy(med->confidence );
		variance->copy( med->variance );
		ratio->copy( med->ratio );
		sampling_method->copy( med->ratio );
		jitter->copy( med->ratio );
		aa_level->copy( med->ratio );
		aa_threshold->copy( med->ratio );
		absorption->copy(  med->absorption  );
		emission->copy( med->emission  );
		scattering->copy( med->scattering  );
		transfo->copy( med->transfo );

		GtkTreeIter *old_node = gtk_tree_iter_copy( &(med->node_iter) );
		add_to_tree( tree_view, tree_store, tree_selection, tree_node_parent, old_node );
		gtk_tree_selection_unselect_iter( tree_selection, &node_iter );
		select_tree_row();
		gtk_tree_iter_free( old_node );
	}
		break;
	}
return true;
}



//**************************************
// Scattering
//**************************************
const int scattering_type_num = 5;
const char *scattering_type_name[scattering_type_num] =
	{ N_("Isotropic"), N_("Mie hazy"), N_("Mie murky"), N_("Rayleigh"), N_("Henyey-Greenstein") };


TvWidget_scattering::TvWidget_scattering( const char *name, const char *sname, const char *tooltip, app_objs *appref )
 : TvWidget( name, sname, tooltip, appref )
{
use_scattering = new TvWidget_bool_activator( _("Use scattering"), "USED", NULL, app_ref, false );
color = new TvWidget_pigment( _("Color"), "COLOR", NULL, app_ref );
color->set( 0, 0, 0, 0, 0 );
type = new TvWidget_option_combo( _("Type"), "TYPE", NULL, app_ref );
type->set_list( scattering_type_name, scattering_type_num, 0 );
eccentricity = new TvWidget_float( _("Eccentricity"), "ECCENT", NULL, app_ref, 0.0 );
eccentricity->set_range( 1000, -1000, 0.1, 3 );
extinction = new TvWidget_float( _("Extinction"), "EXTINCT", NULL, app_ref, 1.0 );
extinction->set_range( 5.0, 0, 0.01, 3 );
}

TvWidget_scattering::TvWidget_scattering( TvWidget_scattering & ref ) : TvWidget( ref )
{
use_scattering = new TvWidget_bool_activator( *ref.use_scattering );
color = new TvWidget_pigment( *ref.color );
type = new TvWidget_option_combo( *ref.type );
eccentricity = new TvWidget_float( *ref.eccentricity );
extinction = new TvWidget_float( *ref.extinction );
}

TvWidget_scattering::~TvWidget_scattering()
{
delete use_scattering;
delete color;
delete type;
delete eccentricity;
delete extinction;
}

void TvWidget_scattering::get_widget_wnframe( GtkWidget *box, bool tt, bool frame )
{
if ( frame ) widget = dlg_simple_box_frame( name, box );
else 
	{
	widget = gtk_vbox_new( FALSE, 0 );
	gtk_box_pack_start( GTK_BOX(box), widget, FALSE, TRUE, 2 );
	}
use_scattering->get_widget_no_toggle( widget, tt );

GtkWidget *activated_box = gtk_vbox_new( FALSE, 0 );
gtk_box_pack_start( GTK_BOX(widget), activated_box, FALSE, FALSE, 0 );
use_scattering->set_target( activated_box );
	color->get_widget( activated_box, tt );
	GtkWidget *table = new_table_no_frame( activated_box, 3 );
	type->get_widget( table, tt, 5 );
	eccentricity->get_widget( table, tt, 4 );
	extinction	->get_widget( table, tt,3 );
use_scattering->update_widget();
}

void TvWidget_scattering::clear_widget()
{ 
widget = NULL;
use_scattering->clear_widget();
color->clear_widget();
type->clear_widget();
eccentricity->clear_widget();
extinction->clear_widget();
}

void TvWidget_scattering::flush()
{ 
if ( !GTK_IS_WIDGET(widget) ) return;
use_scattering->flush();
color->flush();
type->flush();
eccentricity->flush();
extinction->flush();
}

void TvWidget_scattering::output_to_povray( ofstream & file )
{
file << "\n\t\t\tscattering {\n\t\t\t\t";
file << type->value() + 1  << ", ";
color->output_to_povray( file );
if ( type->value() == 4 ) 
	{
	file << "\n\t\t\t\teccentricity ";
	eccentricity->output_to_povray( file );
	}
file << "\n\t\t\t\textinction ";
extinction->output_to_povray( file );

file << "\n\t\t\t}";
}

void TvWidget_scattering::save( ofstream & file )
{
TvWidget::save( file );
use_scattering->save( file );
type->save( file );
color->save( file );
eccentricity->save( file );
extinction->save( file );
file << "} ";
}

bool TvWidget_scattering::load( ifstream & file, char * ltag )
{
if ( strcmp( sname, ltag ) ) return false;
char * tag = NULL;

do
	{
	tag = tvio_get_next_tag( file );
	if ( tag == NULL ) break;
	if ( use_scattering->load( file , tag ) ) continue;
	if ( type->load( file , tag ) ) continue;
	if ( color->load( file , tag ) ) continue;
	if ( eccentricity->load( file , tag ) ) continue;
	if ( extinction->load( file , tag ) ) continue;
	tvio_skip_section( file );
	}
while( tag != NULL );
return true;
}
