//*****************************************************************************************
// Truevision - a 3d modeler for gnome and povray
//
// povfe.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 <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <signal.h>
#include "include/povfe.h"
#include "include/dlgutils.h"
#include "include/preferences.h"
#include <sys/wait.h>
#include <zlib.h>
#include "config.h"
#include "include/scene.h"
#include "include/tvio.h"

// Output file format definitions
const int file_type_num = 4;
const char *file_type_list[file_type_num] = { "PNG", "PPM", "TGA", "TGA+RLE" };
const char *file_type_output[file_type_num] = { "N", "P", "T", "C" };
const char *default_ofile = "Untitled";

// Default settings for rendering
const int anti_met_num = 2;
const char *anti_met_list[anti_met_num] = { N_("Adaptative"), N_("Recursive") };
const int image_max_size = 5000;

// Image size presets
const int size_presets_num = 7;
const char *size_presets_names[ size_presets_num ] = { "None", "160x120", "320x240", "640x480", "800x600", "1024x768", "1280x1024" };
const int size_presets_width[ size_presets_num ] = { 0, 160, 320, 640, 800, 1024, 1280 };
const int size_presets_heigth[ size_presets_num ] = { 0, 120, 240, 480, 600, 768, 1024 };

const char *option_box_help_sections[] = {
	"sect-gui-rendopt1",  "sect-gui-rendopt2",  "sect-gui-rendopt3",  
	"sect-gui-rendopt4",  "sect-gui-rendopt5",  "sect-gui-rendopt6",  
	"sect-gui-rendopt7",  "sect-gui-rendopt8" };
	
// Debug stream
//ofstream debug( "debug.txt" );



//**************************************************************
// Constructor
//**************************************************************
PovrayFE::PovrayFE( app_objs *appref )
{
	app_ref = appref;
	PREF_DEF
	start_button = NULL;
	progress_bar = NULL;
	pipe_console_name = NULL;
	options_box = NULL;
	render_box = NULL;
	fifo_console = NULL;
	cons_dlg = NULL;
	render_status = false;
	options_selected_page = 0;

	// Options for rendering process
	filename = new TvWidget_path( N_("Output file"), "OFILE", NULL, app_ref, default_ofile );
	tv_widgets.push_back( filename );
	fimage_type = new TvWidget_option_combo( N_("File format"), "FORMAT", NULL, app_ref );
	fimage_type->set_list( file_type_list, file_type_num, 0 );
	tv_widgets.push_back( fimage_type );

	width = new TvWidget_int( N_("Width"), "W", NULL, app_ref,  640 );
	width->set_range( image_max_size, 1, 1 );
	tv_widgets.push_back( width );

	height = new TvWidget_int( N_("Height"), "H", NULL, app_ref, 480 );
	height->set_range( image_max_size, 1, 1 );
	tv_widgets.push_back( height );

	start_col = new TvWidget_int( N_("Starting column"), "SC", NULL, app_ref, 1 );
	start_col->set_range( image_max_size, 1, 1 );
	tv_widgets.push_back( start_col );
	start_row = new TvWidget_int( N_("Starting row"), "SR", NULL, app_ref, 1 );
	start_row->set_range( image_max_size, 1, 1 );
	tv_widgets.push_back( start_row );
	end_col = new TvWidget_int( N_("Ending column"), "EC", NULL, app_ref, image_max_size );
	end_col->set_range( image_max_size, 1, 1 );
	tv_widgets.push_back( end_col );
	end_row = new TvWidget_int( N_("Ending row"), "ER", NULL, app_ref, image_max_size );
	end_row->set_range( image_max_size, 1, 1 );
	tv_widgets.push_back( end_row );
	
	quality = new TvWidget_int( N_("Quality"), "QUA", NULL, app_ref, 9 );
	quality->set_range( 11, 1, 1 );
	tv_widgets.push_back( quality );
	alpha = new TvWidget_bool( N_("Use alpha (png & tga only)"), "ALPHA", _("Set background as a transparent color"), app_ref, false );
	tv_widgets.push_back( alpha );
	bits_per_color = new TvWidget_int( N_("Bits per color (png only)"), "BPC", NULL, app_ref, 8 );
	bits_per_color->set_range( 16, 5, 1 );
	tv_widgets.push_back( bits_per_color );
	radiosity = new TvWidget_bool( N_("Use radiosity (experimental)"), "RADIO", NULL, app_ref, false );
	tv_widgets.push_back( radiosity );

	set_spacing = new TvWidget_bool_activator( N_("Set spacing"), "SSPACE", NULL, app_ref, false );
	tv_widgets.push_back( set_spacing );
	spacing = new TvWidget_float( N_("Spacing"), "PSPACE", NULL, app_ref, 1 );
	spacing->set_range( 100, 0, 0.1, 2 );
	tv_widgets.push_back( spacing );
	set_count = new TvWidget_bool_activator( N_("Set count"), "SCOUNT", NULL, app_ref, false );
	tv_widgets.push_back( set_count );
	photon_count = new TvWidget_int( N_("Count"), "PCOUNT", NULL, app_ref, 2000 );
	photon_count->set_range( 100000, 0, 10 );
	tv_widgets.push_back( photon_count );
	
	use_media = new TvWidget_bool( N_("Use media photons"), "PMEDIA", NULL, app_ref, false );
	tv_widgets.push_back( use_media );
	max_steps = new TvWidget_int( N_("Max steps"), "PMTSEP", NULL, app_ref, 1 );
	spacing->set_range( 100, 0.1, 1 );
	tv_widgets.push_back( max_steps );
	media_factor = new TvWidget_float( N_("Factor"), "PMFACT", NULL, app_ref, 1.0 );
	media_factor->set_range( 100, 0, 0.1, 2 );
	tv_widgets.push_back( media_factor );
	
	gather_min = new TvWidget_int( N_("Gather minimum"), "GMAX", NULL, app_ref, 20 );
	photon_count->set_range( 1000, 0, 1 );
	tv_widgets.push_back( gather_min );
	gather_max = new TvWidget_int( N_("Gather maximum"), "GMIN", NULL, app_ref, 100 );
	gather_max->set_range( 1000, 0, 1 );
	tv_widgets.push_back( gather_max );

	set_gradius = new TvWidget_bool_activator( N_("Set gather radius for surfaces"), "SGRADIUS", NULL, app_ref, false );
	tv_widgets.push_back( set_gradius );
	gradius = new TvWidget_float( N_("Radius"), "GRADIUS", NULL, app_ref, 0 );
	gradius->set_range( 100, 0, 0.1, 2 );
	tv_widgets.push_back( gradius );
	set_gradius_med = new TvWidget_bool_activator( N_("Set gather radius for medias"), "SGRADIUSM", NULL, app_ref, false );
	tv_widgets.push_back( set_gradius_med );
	gradius_med = new TvWidget_float( N_("Radius"), "GRADIUSM", NULL, app_ref, 0 );
	gradius_med->set_range( 100, 0, 0.1, 2 );
	tv_widgets.push_back( gradius_med );
	gradius_mult = new TvWidget_float( N_("Surfaces radius multiplier"), "GRADMULT", NULL, app_ref, 1 );
	gradius_mult->set_range( 1, 0, .1, 2 );
	tv_widgets.push_back( gradius_mult );
	gradius_med_mult = new TvWidget_float( N_("Medias radius multiplier"), "GRADMULTM", NULL, app_ref, 1 );
	gradius_med_mult->set_range( 1, 0, .1, 2 );
	tv_widgets.push_back( gradius_med_mult );
	
	photon_jitter = new TvWidget_float( N_("Jitter"), "PJITTER", NULL, app_ref, 0.4 );
	photon_jitter->set_range( 50, 0, 0.1, 2 );
	tv_widgets.push_back( photon_jitter );
	autostop = new TvWidget_float( N_("Auto stop"), "AUTOSTOP", NULL, app_ref, 1.0 );
	autostop->set_range( 1, 0, 0.1, 2 );
	tv_widgets.push_back( autostop );
	photon_adc = new TvWidget_float( N_("ADC bailout"), "PADC", NULL, app_ref, 0.0039 );
	photon_adc->set_range( 1, 0, 0.1, 4 );
	tv_widgets.push_back( photon_adc );
	photon_max_trace = new TvWidget_int( N_("Max trace level"), "PMAXT", NULL, app_ref, 5 );
	photon_max_trace->set_range( 100, 1, 1 );
	tv_widgets.push_back( photon_max_trace );
	photon_thres_perc = new TvWidget_float( N_("Expand thresholds percentage"), "PTHRESP", NULL, app_ref, 0.2 );
	photon_thres_perc->set_range( 1, 0, 0.01,  2 );
	tv_widgets.push_back( photon_thres_perc );
	photon_thres_min = new TvWidget_int( N_("Expand thresholds minimum"), "PTHRESM", NULL, app_ref, 40 );
	photon_thres_min->set_range( 1000, 0, 1 );
	tv_widgets.push_back( photon_thres_min );
	
	
	antialias = new TvWidget_bool( N_("Antialiasing"), "ANTI", NULL, app_ref, true );
	tv_widgets.push_back( antialias );
	anti_met = new TvWidget_option_combo( N_("Method"), "AMET", NULL, app_ref );
	anti_met->set_list( anti_met_list, anti_met_num, 0 );
	tv_widgets.push_back( anti_met );
	anti_depth = new TvWidget_int( N_("Depth (adaptative mode only)"), "ADEPTH", NULL, app_ref, 2 );
	anti_depth->set_range( 10, 1, 1 );
	tv_widgets.push_back( anti_depth );
	threshold = new TvWidget_float( N_("Threshold"), "THRES", NULL, app_ref, 0.3 );
	threshold->set_range( 1, 0, 0.1 );
	tv_widgets.push_back( threshold );
	jitter = new TvWidget_bool( N_("Use jitter"), "JITTER", NULL, app_ref, true );
	tv_widgets.push_back( jitter );
	jamount = new TvWidget_float( N_("Jitter amount"), "JAMOUNT", NULL, app_ref, 0.5 );
	jamount->set_range( 1, 0, 0.1 );
	tv_widgets.push_back( jamount );
	
	display = new TvWidget_bool( N_("Display"), "DISP", _("Display computed image during calculation"), app_ref, true );
	tv_widgets.push_back( display );
	iconified  = new TvWidget_bool( N_("Start iconified"), "ICO", NULL, app_ref, false );
	tv_widgets.push_back( iconified );
	greyscale = new TvWidget_bool( N_("Display as greyscale"), "GREY", NULL, app_ref, false );
	tv_widgets.push_back( greyscale );
	owncmap  = new TvWidget_bool( N_("Use own color map"), "CMAP", NULL, app_ref, false );
	tv_widgets.push_back( owncmap );

	bounding_thres = new TvWidget_int( N_("Bounding box threshold"), "BBT", NULL, app_ref, 25 );
	bounding_thres->set_range( 50, 1, 1 );
	tv_widgets.push_back( bounding_thres );
	light_buff = new TvWidget_bool( N_("Disable light buffer"), "LIBU", NULL, app_ref, false );
	tv_widgets.push_back( light_buff );
	vista  = new TvWidget_bool( N_("Disable vista buffer"), "VIBU", NULL, app_ref, false );
	tv_widgets.push_back( vista );
	draw_vista  = new TvWidget_bool( N_("Draw vista"), "ICO", NULL, app_ref, false );
	tv_widgets.push_back( draw_vista );
	
	adc_bailout = new TvWidget_float(  N_("Adc bailout"), "ADCBO", NULL, app_ref, 0.0039 );
	adc_bailout->set_range( 1, 0, 0.1, 4 );
	tv_widgets.push_back( adc_bailout );
	ambient_light  = new TvWidget_color( N_("Ambient Light"), "ALIGHT", NULL, app_ref );
	ambient_light->set( 1, 1, 1 );
	tv_widgets.push_back( ambient_light );
	noisegen = new TvWidget_noise_generator( N_("Global noise generator"), "NOISEGEN", NULL, app_ref );
	tv_widgets.push_back( noisegen );
	hf_gray_16 = new TvWidget_bool( N_("heightfield  output"), "HF", NULL, app_ref, false );
	tv_widgets.push_back( hf_gray_16 );
	irid_wavelength = new TvWidget_color( N_("Irid wavelength"), "IVL", NULL, app_ref );
	irid_wavelength->set( 0.25, 0.18, 0.14 );
	tv_widgets.push_back( irid_wavelength );
	max_trace_level = new TvWidget_int( N_("Max trace level"), "MTL", NULL, app_ref, 5 );
	max_trace_level->set_range( 100, 1, 1 );
	tv_widgets.push_back( max_trace_level );
	max_intersections = new TvWidget_int( N_("Max intersections"), "MITS", NULL, app_ref, 64 );
	max_intersections->set_range( 1024, 32, 16 );
	tv_widgets.push_back( max_intersections );
	number_of_waves = new TvWidget_int( N_("Number of waves"), "NOW", NULL, app_ref, 10 );
	number_of_waves->set_range( 100, 0, 1 );
	tv_widgets.push_back( number_of_waves );

	// Radiosity
	brightness = new TvWidget_float( N_("Brightness"), "RBRI", NULL, app_ref, 1.0 );
	brightness->set_range( 100, 0, 0.11, 3 );
	tv_widgets.push_back( brightness );
	count = new TvWidget_int( N_("Count"), "COUNT", NULL, app_ref, 35 );
	count->set_range( 1000, 1, 10 );
	tv_widgets.push_back( count );
	error_bound = new TvWidget_float( N_("Error bound"), "EBOUND", NULL, app_ref, 1.8 );
	error_bound->set_range( 1, 0, 0.01, 4 );
	tv_widgets.push_back( error_bound );
	gray_threshold = new TvWidget_float( N_("Gray threshold"), "GRAYT", NULL, app_ref, 0 );
	gray_threshold->set_range( 1, 0, 0.01, 4 );
	tv_widgets.push_back( gray_threshold );
	low_error_factor = new TvWidget_float( N_("Low error factor"), "LEF", NULL, app_ref, 0.5 );
	low_error_factor->set_range( 1, 0, 0.01, 4 );
	tv_widgets.push_back( low_error_factor );
	minimum_reuse = new TvWidget_float( N_("Minimum reuse"), "MINIR", NULL, app_ref, 0.015 );
	minimum_reuse->set_range( 1, 0, 0.1, 4 );
	tv_widgets.push_back( minimum_reuse );
	nearest_count = new TvWidget_int( N_("Nearest count"), "NCOUNT", NULL, app_ref, 5 );
	nearest_count->set_range( 10, 0, 1 );
	tv_widgets.push_back( nearest_count );
	recursion_limit = new TvWidget_int( N_("Recursion limit"), "RECLIM", NULL, app_ref, 3 );
	recursion_limit->set_range( 20, 1, 1 );
	tv_widgets.push_back( recursion_limit );
	rad_adc_bailout = new TvWidget_float( N_("ADC Bailout"), "RADADC", NULL, app_ref, 0.01 );
	rad_adc_bailout->set_range( 1, 0, 0.1, 4 );
	tv_widgets.push_back( rad_adc_bailout );
	always_sample = new TvWidget_bool( N_("Always sample"), "ALWSAMP", NULL, app_ref, true );
	tv_widgets.push_back( always_sample );
	max_sample = new TvWidget_float( N_("Max sample"), "MAXSAMP", NULL, app_ref, -1 );
	max_sample->set_range( 100, -1, 0.1, 4 );
	tv_widgets.push_back( max_sample );
	rad_media = new TvWidget_bool( N_("Affected by media"), "RADMED", NULL, app_ref, false );
	tv_widgets.push_back( rad_media );
	rad_normal = new TvWidget_bool( N_("Affected by normal"), "RADNORM", NULL, app_ref, false );
	tv_widgets.push_back( rad_normal );
	pretrace_start = new TvWidget_float( N_("Pretrace start"), "PRETST", NULL, app_ref, 0.08 );
	pretrace_start->set_range( 1, 0, 0.01, 4 );
	pretrace_end = new TvWidget_float( N_("Pretrace end"), "PRETED", NULL, app_ref, 0.04 );
	pretrace_end->set_range( 1, 0, 0.01, 4 );


	// Scene description
	author = new TvWidget_entry( N_("Author"), "AUTH", NULL, app_ref );
	author->set( pref->author->value() );
	tv_widgets.push_back( author );
	description = new TvWidget_text( N_("Description"), "DESC", NULL, app_ref );
	tv_widgets.push_back( description );
}


//*****************************************************
// Destructor
//*****************************************************
PovrayFE::~PovrayFE()
{
	if ( fifo_console != NULL ) { 
		pclose( fifo_console ); 
		fifo_console = NULL; 
	}
	for ( register unsigned int i = 0 ; i < tv_widgets.size() ; i++ )
		delete tv_widgets[i];
}


//********************************************************
// Progress bar 
//********************************************************
void PovrayFE::get_progress_bar( GtkWidget *box, bool tt )
{
	progress_bar = gtk_progress_bar_new();
	gtk_box_pack_start( GTK_BOX(box), progress_bar, FALSE, FALSE, 5 );
	gtk_progress_bar_update( GTK_PROGRESS_BAR(progress_bar), 0 );
	gtk_progress_set_show_text( GTK_PROGRESS(progress_bar), TRUE );
	gtk_progress_set_text_alignment( GTK_PROGRESS(progress_bar), 0.5, 0.3 );
}


//********************************************************
// Get Pipe line
//
// Read a line from a pipe
// sleep when nothing available
//********************************************************
bool PovrayFE::get_pipe_line( int file, char *buffer, int size )
{
	//debug << "\nStart reading from pipe !"; debug.flush();
	char ch;
	int i = 0;
	while ( i < size ) {
		int res = read( file, &ch, 1 );
		if ( res == 0 ) 
			continue;
		if ( res == -1 && errno == EAGAIN ) {
			sleep(1);
			continue;
		}
		if ( res == -1 ) 
			return false;
		if ( ch == '\n' || ch == '\r' ) 
			break;
		buffer[i++] = ch;
	}
	buffer[i] = '\0';
	//debug << "\nRead one line from pipe !"; debug.flush();
	return true;
}


//*****************************************************
// Reset defaults
//
// used at new scene creation 
//*****************************************************
void PovrayFE::reset_defaults()
{
	options_selected_page = 0;

	filename->set( (char*)default_ofile );
	fimage_type->set( 0 );

	width->set( 640 );
	height->set( 480 );
	
	start_col->set( 1 );
	start_row->set( 1 );
	end_col->set( image_max_size );
	end_row->set( image_max_size );

	quality->set( 9 );
	alpha->set( false );
	bits_per_color->set( 8 );
	radiosity->set( false );

	antialias->set( true );
	anti_met->set( 0 );
	anti_depth->set( 2 );
	threshold->set( 0.3 );
	jitter->set( true );
	jamount->set(0.5);

	set_spacing->set( false );
	spacing->set( 1 );

	display->set( true );
	iconified->set( false );
	greyscale->set( false );
	owncmap->set( false );

	bounding_thres->set( 25 );
	light_buff->set( false );
	vista->set( false );
	draw_vista->set( false );

	adc_bailout->set( 0.0039 );
	ambient_light->set( 1, 1, 1 );
	noisegen->set( 1 );
	hf_gray_16->set( false );
	irid_wavelength->set( 0.25, 0.18, 0.14 );
	max_trace_level->set( 5 );
	max_intersections->set( 64 );
	number_of_waves->set(10);

	brightness->set( 1 );
	count->set( 35 );
	error_bound->set( 1.8 );
	gray_threshold->set( 0 );
	low_error_factor->set( 0.5 );
	minimum_reuse->set( 0.015 );
	nearest_count->set( 5 );
	recursion_limit->set( 3 );
	rad_adc_bailout->set( 0.01 );
	always_sample->set( true );
	max_sample->set( -1 );
	rad_media->set( false );
	rad_normal->set( false );
	pretrace_start->set( 0.08 );
	pretrace_end->set( 0.04 );


	// Scene description
	description->clear();
	PREF_DEF
	author->set( pref->author->value() );
}


//*************************************************
// Flush
//
// Flush widgets at option box close
//*************************************************
void PovrayFE::flush()
{
	for ( register unsigned int i = 0 ; i < tv_widgets.size() ; i++ )
		tv_widgets[i]->flush();
}

//*************************************************
// Pref changed
//
// Preferences change notification 
//*************************************************
void PovrayFE::pref_changed()
{
	for ( register unsigned int i = 0 ; i < tv_widgets.size() ; i++ )
		tv_widgets[i]->pref_changed();
}



//********************************************************
// Options box
//
// Raise the option box
//********************************************************
void PovrayFE::raise_options_box()
{
	if ( GTK_IS_DIALOG(options_box) ) {
		gdk_window_raise( options_box->window );
		return;
	}
	opt_applied = false;

	PREF_DEF
	bool tt = pref->tooltips->value();

	for ( register unsigned int i = 0 ; i < tv_widgets.size() ; i++ )
		tv_widgets[i]->store();

	options_box = gtk_dialog_new_with_buttons( _("Povray options"), NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_OK, GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_HELP, GTK_RESPONSE_HELP,NULL );
	g_signal_connect( G_OBJECT(options_box), "response", G_CALLBACK(sign_povfe_opt_click), this );
	g_signal_connect( G_OBJECT(options_box), "close", G_CALLBACK(sign_povfe_opt_destroy), this );
	if ( pref->save_dlg_geo->value() ) {
		if ( pref->ropt_xpos->value() < 0 ) 
			pref->ropt_xpos->set(0);
		if ( pref->ropt_ypos->value() < 0 ) 
			pref->ropt_ypos->set(0);	
		gtk_widget_set_uposition( options_box, pref->ropt_xpos->value(), pref->ropt_ypos->value() );
		gtk_window_set_default_size( GTK_WINDOW(options_box), pref->ropt_xsize->value(), pref->ropt_ysize->value() );
	}

	// Container
	options_notebk = gtk_notebook_new();
	gtk_notebook_set_scrollable( GTK_NOTEBOOK(options_notebk), TRUE );
	gtk_box_pack_start( GTK_BOX(GTK_DIALOG(options_box)->vbox), options_notebk, FALSE, TRUE, 5 );
	GtkWidget *box1, *box2, *vbox, *hbox;

	// PAGE Quality
	vbox = dlg_new_page( options_notebk, N_("Quality") );
		hbox = dlg_simple_box_frame( _("General"), vbox );
		dlg_double_box( hbox, box1, box2 );		
		quality->get_widget( box1, tt );
		bits_per_color->get_widget( box1, tt );
		alpha->get_widget( box2, tt );
		
	// Frame antialiasing
	dlg_double_box_frame( _("Antialiasing"), vbox, box1, box2 );
		antialias->get_widget( box1, tt );
		anti_met->get_widget( box1, tt );
		anti_depth->get_widget( box1, tt );
		jitter->get_widget( box1, tt );	
		jamount->get_widget( box2, tt );
		threshold->get_widget( box2, tt );


	// PAGE Global settings
	vbox = dlg_new_page( options_notebk, _("Scene settings") );
	hbox = dlg_simple_box_frame( _("General"), vbox );
		ambient_light->get_widget( hbox, tt );
		number_of_waves->get_widget( hbox, tt );
		irid_wavelength->get_widget( hbox, tt );
		noisegen->get_widget( hbox, tt );


	// PAGE Radiosity
	vbox = dlg_new_page( options_notebk, _("Radiosity") );		
	hbox = dlg_simple_box_frame( _("General"), vbox );
		radiosity->get_widget( hbox, tt );
		dlg_double_box( hbox, box1, box2 );		
		brightness->get_widget( box1, tt );	
		gray_threshold->get_widget( box1, tt );
		count->get_widget( box1, tt );
		nearest_count->get_widget( box1, tt );
		rad_adc_bailout->get_widget( box1, tt );
		always_sample->get_widget( box2, tt );
		max_sample->get_widget( box2, tt );
		rad_media->get_widget( box1, tt );
		rad_normal->get_widget( box1, tt );
		minimum_reuse->get_widget( box2, tt );
		//distance_maximum->get_widget( box2, tt );
		error_bound->get_widget( box2, tt );
		low_error_factor->get_widget( box2, tt );
		pretrace_start->get_widget( box2, tt );
		pretrace_end->get_widget( box2, tt );

	// PAGE Photons
	vbox = dlg_new_page( options_notebk, _("Photons") );		
	hbox = dlg_simple_box_frame( _("Number of photons"), vbox );
	dlg_double_box( hbox, box1, box2 );	
	GtkWidget *abox = gtk_hbox_new( TRUE, TRUE );	
	gtk_box_pack_start( GTK_BOX(box2), abox, TRUE, TRUE, 0 );
		set_spacing->get_widget( box1, tt );
		spacing->get_widget( abox, tt );
		set_spacing->set_target( abox );
		set_spacing->update_widget();
		abox = gtk_hbox_new( TRUE, TRUE );	
		gtk_box_pack_start( GTK_BOX(box2), abox, TRUE, TRUE, 0 );
		set_count->get_widget( box1, tt );
		photon_count->get_widget( abox, tt );
		set_count->set_target( abox );
		set_count->update_widget();
		gather_min->get_widget( box1, tt );
		gather_max->get_widget( box2, tt );
		hbox = dlg_simple_box_frame( _("Media interaction"), vbox );
		dlg_double_box( hbox, box1, box2 );	
		use_media->get_widget( box1, tt );
		max_steps->get_widget( box2, tt );
		media_factor->get_widget( box2, tt );
		hbox = dlg_simple_box_frame( _("Gather radius"), vbox );
		dlg_double_box( hbox, box1, box2 );	
		abox = gtk_hbox_new( TRUE, TRUE );	
		gtk_box_pack_start( GTK_BOX(box2), abox, TRUE, TRUE, 0 );
		set_gradius->get_widget( box1, tt );
		gradius->get_widget( abox, tt );
		set_gradius->set_target( abox );
		set_gradius->update_widget();
		gradius_mult->get_widget( box2, tt );
		abox = gtk_hbox_new( TRUE, TRUE );	
		gtk_box_pack_start( GTK_BOX(box2), abox, TRUE, TRUE, 0 );
		set_gradius_med->get_widget( box1, tt );
		gradius_med->get_widget( abox, tt );
		set_gradius_med->set_target( abox );
		set_gradius_med->update_widget();
		gradius_med_mult->get_widget( box2, tt );
		hbox = dlg_simple_box_frame( _("Tracing options"), vbox );
		dlg_double_box( hbox, box1, box2 );	
		photon_jitter->get_widget( box1, tt );
		autostop->get_widget( box1, tt );
		photon_adc->get_widget( box2, tt );
		photon_max_trace->get_widget( box2, tt );
		photon_thres_perc->get_widget( box1, tt );
		photon_thres_min->get_widget( box2, tt );

	// PAGE Performances
	vbox = dlg_new_page( options_notebk, _("Performances") );
	hbox = dlg_simple_box_frame( _("General"), vbox );
		dlg_double_box( hbox, box1, box2 );		
		bounding_thres->get_widget( box1, tt );
		light_buff->get_widget( box1, tt );
		vista->get_widget( box2, tt );
		draw_vista->get_widget( box2, tt );
		
	// Frame Limits
	hbox = dlg_simple_box_frame( _("Limits"), vbox );
		dlg_double_box( hbox, box1, box2 );
		adc_bailout->get_widget( box1, tt );
		max_trace_level->get_widget( box1, tt );
		max_intersections->get_widget( box2, tt );

	// PAGE Display
	vbox = dlg_new_page( options_notebk, _("Display") );
	hbox = dlg_simple_box_frame( _("General"), vbox );
		display->get_widget( hbox, tt );
		//mosaic->get_widget( hbox, tt );
		iconified->get_widget( hbox, tt );
		owncmap->get_widget( hbox, tt );
		greyscale->get_widget( hbox, tt );

	// PAGE OUTPUT
	vbox = dlg_new_page( options_notebk, _("Output") );
	// Frame File
	hbox = dlg_simple_box_frame( _("File options"), vbox );
		filename->get_widget( hbox, tt );	
		fimage_type->get_widget( hbox, tt );
		hf_gray_16->get_widget( hbox, tt );

	// Frame Size
	hbox = dlg_simple_box_frame( _("Size"), vbox );
		dlg_double_box( hbox, box1, box2 );
		width->get_widget( box1, tt );
		height->get_widget( box2, tt );
       presets = new TvWidget_option_combo( N_("Size presets"), NULL, NULL, app_ref );
		presets->set_list( size_presets_names, size_presets_num, 0 );
		for ( int i = 0 ; i < size_presets_num ; i++ ) 
			if ( size_presets_width[i] == width->value() && size_presets_heigth[i] == height->value() ) {
				presets->set(i);
				break;
			}
		presets->get_widget( box1, tt );
		presets->connect_signal( GTK_SIGNAL_FUNC(sign_povfe_presets), this );
				
	// Frame partial
	hbox = dlg_simple_box_frame( _("Partial render"), vbox );
		dlg_double_box( hbox, box1, box2 );
		start_col->get_widget( box1, tt );
		start_row->get_widget( box2, tt );
		end_col->get_widget( box1, tt );
		end_row->get_widget( box2, tt );


	// PAGE MISC
	vbox = dlg_new_page( options_notebk, _("About scene") );
	// Frame partial
	hbox = dlg_simple_box_frame( _("Description"), vbox );
	author->get_widget( hbox, tt );
	description->get_widget( hbox, tt );

gtk_widget_show_all(options_box);
gtk_notebook_set_page( GTK_NOTEBOOK(options_notebk), options_selected_page );
}


//********************************************************
// Options box
//
// Callbacks
//********************************************************
void PovrayFE::opt_box_clicked( int button )
{
	switch( button ) {
		case GTK_RESPONSE_OK:
			flush();
			close_opt_box();
			break;

		case GTK_RESPONSE_APPLY:
			flush();
			opt_applied = true;
			break;

		case GTK_RESPONSE_HELP:
			{
			int sel = gtk_notebook_get_current_page( GTK_NOTEBOOK(options_notebk) ) ;
			truevision_help_display( "truevision.xml",  (char*)option_box_help_sections[sel], NULL );	
			}
			break;

		default:
		case GTK_RESPONSE_CANCEL:
			if ( opt_applied ) 
				unapply_opt_box();
			close_opt_box();
			break;
	}
}


//********************************************************
// Close options box
//********************************************************
void PovrayFE::close_opt_box()
{
	options_selected_page = gtk_notebook_get_current_page( GTK_NOTEBOOK(options_notebk) );
	PREF_DEF
	if ( pref->save_dlg_geo->value() ) {
		gint x,y;
		gdk_window_get_root_origin( options_box->window, &x, &y );
		pref->ropt_xpos->set( x );
		pref->ropt_ypos->set( y );
		pref->ropt_xsize->set( options_box->allocation.width );
		pref->ropt_ysize->set( options_box->allocation.height );
	}
	if ( options_box != NULL ) 
		gtk_widget_destroy( options_box );
	options_box = NULL;
	for ( register unsigned int i = 0 ; i < tv_widgets.size() ; i++ )
		tv_widgets[i]->clear_widget();
	delete presets;
}

//********************************************************
// Unapply options box
//********************************************************
void PovrayFE::unapply_opt_box()
{
	for ( register unsigned int i = 0 ; i < tv_widgets.size() ; i++ )
		tv_widgets[i]->restore();
}


//********************************************************
// Update width / height from size presets
//********************************************************
void PovrayFE::size_preset_choice()
{
	if ( presets == NULL ) 
		return;
	presets->flush();
	int val = presets->value();
	if ( val < 1 ) 
		return;
	width->set( size_presets_width[ val ] );
	width->update_widget();
	height->set( size_presets_heigth[ val ] );
	height->update_widget();
}



//****************************************************************************
// Render box
//
// Raise render box
//****************************************************************************
void PovrayFE::raise_render_box()
{
	if ( GTK_IS_WIDGET(render_box) ) {
		gdk_window_raise( render_box->window );
		return;
	}
	PREF_DEF
	bool tt = pref->tooltips->value();

	render_box = gtk_window_new( GTK_WINDOW_TOPLEVEL );
	gtk_window_set_decorated( GTK_WINDOW(render_box), TRUE );
	gtk_window_set_title( GTK_WINDOW(render_box), _("Render") );
	gtk_window_set_policy( GTK_WINDOW(render_box), FALSE, FALSE, TRUE );
	gtk_signal_connect( GTK_OBJECT(render_box), "delete_event", GTK_SIGNAL_FUNC(sign_povfe_rend_destroy), this );
	if ( pref->save_dlg_geo->value() ) {
		if ( pref->rdlg_xpos->value() < 0 ) 
			pref->rdlg_xpos->set(0);
		if ( pref->rdlg_ypos->value() < 0 ) 
			pref->rdlg_ypos->set(0);	
		gtk_widget_set_uposition( render_box, pref->rdlg_xpos->value(), pref->rdlg_ypos->value() );
	}

	GtkWidget *vbox = gtk_vbox_new( FALSE, 0 );
	gtk_container_set_border_width( GTK_CONTAINER(vbox), 7 );
	gtk_container_add( GTK_CONTAINER(render_box), vbox );

	
	GtkWidget *lab = gtk_label_new( _("Persistence of Vision Front-end") );
	gtk_box_pack_start( GTK_BOX(vbox), lab, TRUE, TRUE, 0 );

	get_progress_bar( vbox, tt );

	status = gtk_label_new( _("Click 'start' to render the scene") );
	gtk_box_pack_start( GTK_BOX(vbox), status, TRUE, TRUE, 0 );

	GtkWidget *hbox = gtk_hbox_new( FALSE, 5 );
	gtk_box_pack_start( GTK_BOX(vbox), hbox, FALSE, TRUE, 4 );
	time_lab = gtk_label_new( _("Elapsed time : ") );
	gtk_box_pack_start( GTK_BOX(hbox), time_lab, FALSE, TRUE, 20 );
	time_lab = gtk_label_new( "--:--:--" );
	gtk_box_pack_start( GTK_BOX(hbox), time_lab, FALSE, TRUE, 0 );
	GtkWidget *label = gtk_label_new( N_("When render is over, click on image") );
	gtk_box_pack_start( GTK_BOX(vbox), label, FALSE, TRUE, 0 );

	GtkWidget *sep = gtk_hseparator_new();
	gtk_box_pack_start( GTK_BOX(vbox), sep, TRUE, TRUE, 8 );

	GtkWidget *button_box = gtk_hbutton_box_new();
	gtk_button_box_set_layout( GTK_BUTTON_BOX(button_box), GTK_BUTTONBOX_SPREAD );
	gtk_button_box_set_spacing( GTK_BUTTON_BOX(button_box), 10 );
	gtk_box_pack_start( GTK_BOX(vbox), button_box, FALSE, FALSE, 0 );

	start_label = gtk_label_new( _("Start") );
	start_button = gtk_button_new();
	gtk_signal_connect( GTK_OBJECT(start_button), "clicked", GTK_SIGNAL_FUNC(sign_povfe_start_stop_clicked), this );
	gtk_container_add( GTK_CONTAINER(start_button), start_label );
	gtk_container_add( GTK_CONTAINER(button_box), start_button );

	GtkWidget *button = gtk_button_new_with_label( _("Console") );
	gtk_container_add( GTK_CONTAINER(button_box), button );
	gtk_signal_connect( GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(sign_povfe_console), this );

	button = gtk_button_new_with_label( _("Options") );
	gtk_container_add( GTK_CONTAINER(button_box), button );
	gtk_signal_connect( GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(sign_options_box), this );

	button = gtk_button_new_with_label( _("Close") );
	gtk_container_add( GTK_CONTAINER(button_box), button );
	gtk_signal_connect( GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(sign_povfe_rend_close), this );


	// Console text
	cons_box = gtk_hbox_new( TRUE, 5 );
	cons_text = gtk_text_view_new( );
	gtk_container_add( GTK_CONTAINER(cons_box), cons_text );
	
	gtk_widget_show_all( render_box );
}

//***************************************************
// Close render box
//***************************************************
void PovrayFE::close_render_box()
{ 
	PREF_DEF
	if ( pref->save_dlg_geo->value() ) {
		gint x,y;
		gdk_window_get_root_origin( render_box->window, &x, &y );
		pref->rdlg_xpos->set( x );
		pref->rdlg_ypos->set( y );
	}
	stop_rendering_scene( false );
	if ( render_box != NULL ) 
		gtk_widget_destroy( render_box ); 
	render_box = NULL; 
	close_console_dlg(); 
	gtk_widget_destroy(cons_box); 
}


//*********************************************************
// Start stop
//
// Start button callback
//*********************************************************
void PovrayFE::start_stop_clicked()
{
	if ( render_status == false )
	// Start
	start_render();
	else
	// Stop
	stop_render(  );
}

//*********************************************************
// Start render
//
// start rendering image
// called from button, menu or shortcut
//*********************************************************
void PovrayFE::start_render()
{
	gtk_label_set_text( GTK_LABEL(status), _("Initialiasing render...") );
	gtk_label_set_text( GTK_LABEL(start_label), _("Stop") );
	gtk_action_set_sensitive( start_render_action, FALSE );
	gtk_action_set_sensitive( stop_render_action, TRUE );
	start_rendering_scene();
}


//*********************************************************
// Stop render
//
// stop rendering image
// called from button, menu or shortcut
//*********************************************************
void PovrayFE::stop_render()
{
	stop_rendering_scene(false);
}

//*********************************************************
// Start rendering scene
//
// create a temp pov file & invoke povray
//*********************************************************
bool PovrayFE::start_rendering_scene()
{
	// Scene
	SCENE_DEF
	scene_file = scene->get_temp_povray_file();
	render_status = true;

	// Clear the console
	GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(cons_text) );
	GtkTextIter start, end;
	gtk_text_buffer_get_bounds( buffer, &start, &end );
	gtk_text_buffer_delete( buffer, &start, &end );

	// Check if destination directory exists && output file != NULL
	bool nodir = false;
	if ( filename->value() == NULL ) 
		filename->set( (char*)default_ofile );
	int len = strlen( filename->value() );
	char *path = new char[ len + 1 ];
	strcpy( path,  filename->value() );
	for (  ; path[len] != '/' && len != 0 ; len-- )  {}
	path[len] = '\0';
	if ( access( path, F_OK ) == -1 && len != 0 ) {
		app_warning( _("Can't write output file to directory"), path );
		nodir = true;
	}

	// Create pipes
	int res;
	pipe_console_name = get_temp_filename();
	res = mkfifo( pipe_console_name, S_IRUSR | S_IWUSR  );
	if ( res != 0 ) {
		app_warning( _("Can't create output pipe"), path );
		return false;
	}

	// Create arguments for launching povray
	PREF_DEF
	char *args[256];
	int arg_num = 0;
	
	// Set rendere command to use,  from preferences
	args[arg_num++] = pref->povcmd->value();
	
	// pause when render finished
	char arg_p[] ="+P";
	args[arg_num++] = arg_p;
	
	// verbose mode on
	char arg_v[] = "+V";
	args[arg_num++] = arg_v;
	
	// Redirect all streams to console pipe
	char arg_ga[ strlen(pipe_console_name) + 5 ];
	sprintf( arg_ga, "+GA%s", pipe_console_name );
	args[arg_num++] = arg_ga;

	// Set povray window title  - WARNING X-Window version specific argument
	char arg_title[] = "-title \"Persistence of vision\"";
	args[arg_num++] = arg_title;
	//args[arg_num++] = nodir ? (char*)default_ofile : filename->value();

	// Set the scene file
	char arg_i[ strlen(scene_file) + 5 ];
	sprintf( arg_i, "+I%s", scene_file );
	args[arg_num++] = arg_i;

	// Set output file name
	char *output = nodir ? (char*)default_ofile : filename->value();
	char arg_o[ strlen(output) + 5 ];
	sprintf( arg_o, "+O%s", output );
	args[arg_num++] = arg_o;
	
	// Set image height
	char arg_h[10] ;
	sprintf( arg_h, "+H%u", height->value() );
	args[arg_num++] = arg_h;

	// Set image width
	char arg_w[10] ;
	sprintf( arg_w, "+W%u", width->value() );
	args[arg_num++] = arg_w;

	// Set render quality level
	char arg_q[10] ;
	sprintf( arg_q, "+Q%u", quality->value() );
	args[arg_num++] = arg_q;
	
	// Set image output format
	char arg_f[4] ;
	if ( fimage_type->value() == 0 ) {
		// if we use the png file format, set bit per color option
		sprintf( arg_f, "+F%s%u", file_type_output[fimage_type->value()], bits_per_color->value() );
		args[arg_num++] = arg_f;
	} else {
		sprintf( arg_f, "+F%s", file_type_output[fimage_type->value()] );
		args[arg_num++] = arg_f;
	}		

	// Set the starting column
	char arg_sc[10] ;
	sprintf( arg_sc, "+SC%u", start_col->value() );
	args[arg_num++] = arg_sc;

	// Set the starting row
	char arg_sr[10] ;
	sprintf( arg_sr, "+SR%u", start_row->value() );
	args[arg_num++] = arg_sr;
	
	// Set the ending col
	char arg_ec[10] ;
	sprintf( arg_ec, "+EC%u", end_col->value() );
	args[arg_num++] = arg_ec;

	// Set the ending row
	char arg_er[10] ;
	sprintf( arg_er, "+ER%u", end_row->value() );
	args[arg_num++] = arg_er;

	// Shall we use X-window display 
	if ( display->value() ) {
		if ( ! greyscale->value() ) {
			char arg_d[] = "+D";
			args[arg_num++] = arg_d;
		} else {
			char arg_d[] = "+D0G";
			args[arg_num++] = arg_d;
		}		
	}
	
	// Shall we start with an iconified display
	if ( iconified->value() ) {
		char arg_icon[] = "-iconic";
		args[arg_num++] = arg_icon;
	}
	
	// Shall we use our own color map
	if ( owncmap->value() ) {
		char arg_cmap[] = "-owncmap";
		args[arg_num++] = arg_cmap;
	}
	
	// Set radiosity
	if ( radiosity->value() ) {
		char arg_qr[] = "+QR" ;
		args[arg_num++] = arg_qr;
	}
	
	// Set alpha channel on / off
	if ( radiosity->value() ) {
		char arg_ua[] = "+UA" ;
		args[arg_num++] = arg_ua;
	}

	// set antialiasing & parameters
	if ( antialias->value() ) {
		// antialiasing & threshold
		char arg_a[5];
		sprintf( arg_a, "+A%1.1f", threshold->value() );
		args[arg_num++] = arg_a;
		
		// antialiasing method
		char arg_am[5];
		sprintf( arg_am, "+AM%u", anti_met->value()+1 );
		args[arg_num++] = arg_am;
		
		// antialiasing depth ( recursive mode )
		char arg_r[5];
		sprintf( arg_r, "+R%u", anti_depth->value() );
		args[arg_num++] = arg_r;

		// Jitter
		if ( jitter->value() ) {
			char arg_j[5];
			sprintf( arg_j, "+J%1.1f", jamount->value() );
			args[arg_num++] = arg_j;
		}
	}

	// Set bounding box threshold
	if ( bounding_thres->value() != 25 ) {
		char arg_mb[10];
		sprintf( arg_mb, "+MB%u", bounding_thres->value() );
		args[arg_num++] = arg_mb;
	}
	
	// Set light buffers on
	if ( light_buff->value() ) {
		char arg_ul[] = "+UL";
		args[arg_num++] = arg_ul;
	}
	
	// Set light vistas on
	if ( vista->value() ) {
		char arg_uv[] = "+UV";
		args[arg_num++] = arg_uv;
	}
	
	// Set light vistas display on
	if ( vista->value() ) {
		char arg_ud[] = "+UD";
		args[arg_num++] = arg_ud;
	}
	
	args[ arg_num++ ] = NULL;

	// Debug command arguments
	/*cout << "\ninvoking povray with command : \n\t";
	for ( int i = 0 ; i < arg_num-1 ; i++ ) {
		cout << args[i] << " ";
	}
	cout.flush();*/
	
	// Fork and launch povray
	povray_pid = fork();
	if ( povray_pid == -1 ) 
		return false;
	if ( povray_pid == 0 ) {
		if ( execve( *args, args, app_ref->envp ) == -1 ) {
			exit(-1);
			unlink( pipe_console_name );
		}
		exit(-1);
	}

	// Thread de lecture de la console
	pthread_attr_t thread_attr2;
	pthread_attr_init( &thread_attr2 );
	//pthread_attr_setdetachstate( &thread_attr2, PTHREAD_CREATE_JOINABLE  );
	pthread_attr_setdetachstate( &thread_attr2, PTHREAD_CREATE_DETACHED  );
	
	if( pthread_create( &console_thread, &thread_attr2, read_console_thread, this ) ) {
		app_warning( _("Cannot create status reading thread !") ); 
		stop_rendering_scene( false );
		return false; 	
	}

	return true;
}


//******************************************************************
// Stop rendering scene
//
// Kill povray and delete temp file
//******************************************************************
void PovrayFE::stop_rendering_scene( bool from_thread )
{
	if ( render_status == false ) 
		return;
	kill( povray_pid, 6 );
	close( pipe_console_id );
	if ( ! from_thread ) 
		pthread_cancel( console_thread );
	unlink( scene_file );
	unlink( pipe_console_name );
	delete pipe_console_name;
	delete scene_file;
	waitpid( povray_pid, NULL, 0 );

	if ( from_thread ) gdk_threads_enter();
	gtk_label_set_text( GTK_LABEL(start_label), _("Start") );
	gtk_progress_bar_update( GTK_PROGRESS_BAR(progress_bar), 0 );
	gtk_label_set_text( GTK_LABEL(status), _("Done.") );
	gtk_label_set_text( GTK_LABEL(time_lab), "--:--:--" );
	gdk_flush();
	if ( from_thread ) gdk_threads_leave();

	render_status = false;
	//gtk_widget_set_sensitive( start_render_menu_item, TRUE );
	//gtk_widget_set_sensitive( stop_render_menu_item, FALSE );
	gtk_action_set_sensitive( start_render_action, TRUE );
	gtk_action_set_sensitive( stop_render_action, FALSE );
}



//******************************************************************
// Read console pipe
//
// read povray output from pipe 
//******************************************************************
void PovrayFE::read_console_pipe()
{
	pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL );
	//pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
	pipe_console_id = open( pipe_console_name, O_RDONLY | O_SYNC | O_NDELAY );
	//pipe_console_id = open( pipe_console_name, O_RDONLY  );
	if (  pipe_console_id== -1 ) {
		app_warning( _("Cannot read povray output !") );
		stop_rendering_scene( false );	 	
		return;
	}

	// DEBUG Ouverture du fichier
	//ofstream filez( "pov.log", ios::out );
	//filez.setf( ios::fixed, ios::floatfield );

	char console_line[255];
	bool finished = false;
	bool print;
	int image_line = 0;
	char time[20];
	int hauteur = height->value();
	int line_num = 0;

	bool parsing_done = false;
	bool photons_done= false;
	bool rendering = false; 
	bool bslabs_done = false;

	// Parsing povray output
	while ( finished == false ) {
		pthread_testcancel();
		bool res = get_pipe_line( pipe_console_id, console_line, 254 );
		if ( res == false ) 
			finished = true;
		strcat( console_line, "\n" );
		//filez << console_line; filez.flush();
	
		print = true;
		line_num++;

		if ( strstr( console_line, "Done" ) != NULL ) {
			finished = true;
			gdk_threads_enter();			
			gtk_progress_bar_update( GTK_PROGRESS_BAR(progress_bar), 1 );
			gtk_label_set_text( GTK_LABEL(status), _("Click on image to close it...") );
			while ( gtk_events_pending() ) 
				gtk_main_iteration();
			gdk_flush();
			gdk_threads_leave();			
		}


		if ( !parsing_done && strstr( console_line, "Parsing" ) != NULL ) {
			parsing_done = true;
			gdk_threads_enter();
			gtk_label_set_text( GTK_LABEL(status), _("Parsing...") );
			while ( gtk_events_pending() ) 
				gtk_main_iteration();
			gdk_flush();
			gdk_threads_leave();
		}

		if ( !bslabs_done && strstr( console_line, "Creating bounding slabs" ) != NULL ) {
			bslabs_done = true;
			gdk_threads_enter();
			gtk_label_set_text( GTK_LABEL(status), _("Creating bounding slabs...") );
			while ( gtk_events_pending() ) 
				gtk_main_iteration();
			gdk_flush();
			gdk_threads_leave();
		}

		if ( !photons_done && strstr( console_line, "Building Photon Maps" ) != NULL ) {
			photons_done = true;
			gdk_threads_enter();
			gtk_label_set_text( GTK_LABEL(status), _("Building photon maps...") );
			while ( gtk_events_pending() ) 
				gtk_main_iteration();
			gdk_flush();
			gdk_threads_leave();
		}


		if ( !rendering && ( strstr( console_line, "Rendering line" ) != NULL )    ) {			
			rendering = true;
			gdk_threads_enter();
			gtk_label_set_text( GTK_LABEL(status), _("Rendering") );
			gtk_progress_bar_update( GTK_PROGRESS_BAR(progress_bar), 0 );
			while ( gtk_events_pending() ) 
				gtk_main_iteration();
			gdk_flush();
			gdk_threads_leave();
		}
			
		if ( rendering ) {
			char *substr = strstr( console_line, "Rendering line " );
			if ( substr != NULL ) {
				print = false;
				sscanf( substr + 15, "%u of", &image_line );
				float prog = (float)(image_line) / (float)hauteur;
				strncpy( time, console_line, 9 ); time[9] = '\0';
	
				gdk_threads_enter();			
				if ( prog > 0.01 ) 
					gtk_progress_bar_update( GTK_PROGRESS_BAR(progress_bar), prog );
				gtk_label_set_text( GTK_LABEL(time_lab), time );			
				gdk_flush();
				gdk_threads_leave();		
			}				
		}

		if ( strstr( console_line, "command not found" ) ) {
			stop_rendering_scene( true );
			gdk_threads_enter();
			app_warning( _("Povray command not found. Please set path in preferences.") );
			gdk_flush();
			gdk_threads_leave();
			pthread_exit(NULL); 
		}

		bool error = false;
		if ( strstr( console_line, "Error" ) != NULL ) error = true;
		if ( strstr( console_line, "error" ) != NULL ) error = true;
		if ( strstr( console_line, "Possible" ) != NULL ) error = true;
		if ( error ) {
			gdk_threads_enter();
			app_warning( _("Error while executing povray ! See console for details") );
			gdk_flush();
			gdk_threads_leave();
		}

		if ( finished == true  && parsing_done == false  && error == false ) {
			gdk_threads_enter();
			app_warning( _("Povray command not found. Please set path in preferences.") );
			gdk_flush();
			gdk_threads_leave();
		}

		// Copy povray output to tv rendering console
		if ( print ) {
			gdk_threads_enter();	
			GtkTextBuffer *buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW(cons_text) );
			GtkTextIter end;
			gtk_text_buffer_get_end_iter( buffer, &end );
			gtk_text_buffer_insert( buffer, &end, console_line, -1 );
			gdk_flush();
			gdk_threads_leave();
		}
	}

	pthread_testcancel();
	stop_rendering_scene( true );
	//filez.close();
	pthread_exit(NULL);
}


//***********************************************
// Console dialog
//
// Raise the dialog
//***********************************************
void PovrayFE::raise_console_dlg()
{
	if ( cons_dlg != NULL )
		return;
	PREF_DEF

	cons_dlg = gtk_dialog_new_with_buttons( _("Rendering console"), NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL );
	gtk_window_set_policy( GTK_WINDOW(cons_dlg), TRUE, TRUE, FALSE );
	g_signal_connect( G_OBJECT(cons_dlg), "close", G_CALLBACK(sign_povfe_cons_click), this );
	g_signal_connect( G_OBJECT(cons_dlg), "response", G_CALLBACK(sign_povfe_cons_destroy), this );
	if ( pref->save_dlg_geo->value() ) {
		if ( pref->con_xpos->value() < 0 ) 
			pref->con_xpos->set(0);
		if ( pref->con_ypos->value() < 0 ) 
			pref->con_ypos->set(0);	
		gtk_widget_set_uposition( cons_dlg, pref->con_xpos->value(), pref->con_ypos->value() );
		gtk_window_resize( GTK_WINDOW(cons_dlg), pref->con_xsize->value(), pref->con_ysize->value() );
	}
	
	GtkWidget *scroll = gtk_scrolled_window_new( NULL, NULL );
	gtk_container_set_border_width( GTK_CONTAINER(scroll), 5 );
	gtk_container_add( GTK_CONTAINER(GTK_DIALOG(cons_dlg)->vbox), scroll );
	gtk_widget_reparent( cons_text, scroll );
	gtk_widget_show_all(cons_dlg);
}

//***********************************************
// Destroy console
//***********************************************
void PovrayFE::close_console_dlg()
{
	if ( ! GTK_IS_DIALOG(cons_dlg) ) 
		return;
	PREF_DEF
	if ( pref->save_dlg_geo->value() ) {
		gint x,y;
		gdk_window_get_root_origin( cons_dlg->window, &x, &y );
		pref->con_xpos->set( x );
		pref->con_ypos->set( y );
		pref->con_xsize->set( cons_dlg->allocation.width );
		pref->con_ysize->set( cons_dlg->allocation.height );
	}

	gtk_widget_reparent( cons_text, cons_box );
	gtk_widget_destroy( cons_dlg );
	cons_dlg = NULL;
}



//***********************************************
// Save
//
// Save front end options in scene file
//***********************************************
void PovrayFE::save( ofstream & file )
{
	file << "\nRENDER_OPTIONS{\n";
	for ( unsigned int i = 0 ; i < tv_widgets.size() ; i++ ) 
		tv_widgets[i]->save( file );
	file << "\n}";
}

//***********************************************
// Load
//
// Load front end options from a scene file
//***********************************************
bool PovrayFE::load( ifstream & file, char *ltag )
{
	if ( strcmp( ltag, "RENDER_OPTIONS" ) ) 
		return false;

	char * tag = NULL;
	do {
		tag = tvio_get_next_tag( file );
		bool found = false;
		if ( tag == NULL ) 
			break;
		for ( unsigned int i = 0 ; i < tv_widgets.size() ; i++ )
			if( tv_widgets[i]->load( file, tag ) ) { 
				found = true; 
				break; 
			}
		if ( found ) 
			continue;
		tvio_skip_section(file );
	} while ( tag != NULL );

	return true;
}


//***********************************************
// Output to povray
//
// Output renderer options to povray pov file
//***********************************************
void PovrayFE::output_to_povray( ofstream & file )
{
	PREF_DEF
	file << "\n\n// Global settings\nglobal_settings {";
	file << "\n\tadc_bailout " << adc_bailout->value();
	file << "\n\tambient_light "; ambient_light->output_to_povray( file );
	noisegen->output_to_povray( file );
	file << "\n\tassumed_gamma " << pref->gamma->value();
	if ( hf_gray_16->value() ) 
		file << "\n\thf_gray_16 ";
	file << "\n\tirid_wavelength "; irid_wavelength->output_to_povray( file );
	file << "\n\tmax_trace_level " << max_trace_level->value();
	file << "\n\tmax_intersections " << max_intersections->value();
	file << "\n\tnumber_of_waves " << number_of_waves->value();

	if ( radiosity->value() ) {
		file << "\n\tradiosity {";
		file << "\n\t\tbrightness " << brightness->value();
		file << "\n\t\tcount " << count->value();
		//file << "\n\t\tdistance_maximum " << distance_maximum->value();
		file << "\n\t\terror_bound " << error_bound->value();
		file << "\n\t\tgray_threshold " << gray_threshold->value();
		file << "\n\t\tlow_error_factor " << low_error_factor->value();
		file << "\n\t\tminimum_reuse " << minimum_reuse->value();
		file << "\n\t\tnearest_count " << nearest_count->value();
		file << "\n\t\trecursion_limit " << recursion_limit->value();
		file << "\n\t\tadc_bailout " << rad_adc_bailout->value();
		file << "\n\t\talways_sample " << always_sample->value();
		file << "\n\t\tmax_sample " << max_sample->value();
		file << "\n\t\tmedia " << rad_media->value();
		file << "\n\t\tnormal " << rad_normal->value();
		file << "\n\t\tpretrace_start " << pretrace_start->value();
		file << "\n\t\tpretrace_end " << pretrace_end->value();	
		file << "\n\t\t}";
	}

 	// Photons
	file << "\n\tphotons {";
	if ( set_spacing->value() ) 
		file << "\n\t\tspacing " << spacing->value();
	if ( set_count->value() ) 
		file << "\n\t\tspacing " << count->value();
	file << "\n\t\tgather " << gather_min->value() << "," << gather_max->value();
	if ( use_media->value() ) 
		file << "\n\t\tmedia " << max_steps->value() << "," << media_factor->value();
	file << "\n\t\tjitter " << jitter->value();
	file << "\n\t\tmax_trace_level " << photon_max_trace->value();
	file << "\n\t\tadc_bailout " << photon_adc->value();
	file << "\n\t\tautostop " << autostop->value();
	file << "\n\t\texpand_thresholds " << photon_thres_perc->value() << "," << photon_thres_min->value();
	file << "\n\t\tradius ";
	if ( set_gradius->value() ) 
		file << gradius->value();
	file << "," << gradius_mult->value() << ",";
	if ( set_gradius_med->value() ) 
		file << gradius_med->value();
	file << "," << gradius_med_mult->value();
	file << "\n\t}";

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


//***********************************************
// Output to povray
//
// Output renderer options to povray ini file
//***********************************************
void  PovrayFE::output_to_povray_ini( ofstream & file, char *fname )
{
	file << "\n; Input options";
	file << "\nInput_File_Name=" << fname;
	
	file << "\n\n; Geometry options";
	file << "\nHeight=" << height->value();
	file << "\nWidth=" << width->value();
	file << "\nStart_Column=" << start_col->value();
	file << "\nStart_row=" << start_row->value();
	file << "\nEnd_Column=" << end_col->value();
	file << "\nEnd_Row=" << end_row->value();
	
	file << "\n\n; Display options";
	file << "\nDisplay=" << ( display->value() ? "on" : "off" );
	file << "\nDraw_vistas=" << ( draw_vista->value() ? "on" : "off" );
		
	file << "\n\n; Output options";
	file << "\nOutput_File_Name=" << filename->value();
	file << "\nOutput_File_Type=" << file_type_output[fimage_type->value()];
	file << "\nOutput_Alpha=" << alpha->value();
	file << "\nBits_Per_Color=" << bits_per_color->value();
	file << "\nQuality=" << quality->value();
	file << "\nRadiosity=" <<  ( radiosity->value() ? "on" : "off" );
	
	file << "\n\n; Antialiasing options";
	file << "\nAntialias=" << ( antialias->value() ? "on" : "off" );
	file  << "\nSampling_Method=" << anti_met->value();
	file << "\nAntialias_threshold=" << threshold->value();
	file << "\nJitter=" << ( jitter->value() ? "on" : "off" );
	file << "\nJitter_Amount=" << jamount->value();
	file << "\nAntialias_Depth=" << anti_depth->value();
	
	file << "\n\n; Bounding control options";
	file << "\nBounding_Threshold=" << bounding_thres->value();
	file << "\nLight_Buffer=" << ( light_buff->value() ? "on" : "off" );
	file << "\nVista_Buffer=" <<  ( vista->value() ? "on" : "off" );
	
	file << "\n\n; Misc options";
	file << "\nContinue_Trace=on";
	file << "\nTest_Abort=on";
	file << "\nPause_When_Done=on";
}
