#include <stdio.h>
#include <iostream.h>
#include <wb/error.hpp>
#include <3D/Objectlight.hpp>
#include <wb/conio.h>
#include <3D/objects/Quader.hpp>
#include <3D/Camera.hpp>
#include <wb/GDevice.hpp>
#include <3D/Scene.hpp>
#include <3D/Surface.hpp>
#include <3D/Lights.hpp>
#include <wb/math.hpp>
#include <wb/parse.hpp>
#include <3D/Textur.hpp>
#pragma	hdrstop
#include <3D/Scenery/atmosphere.hpp>

#ifdef	__MSDOS__
#include <etc/pcemu.hpp>
#else
#ifndef	sgi
#include <process.h>
#endif
#include <unistd.h>
#endif

#define	CLOUDSx

main(int argc,char*argv[])
{
double	sonne_altitude =  70,	// Sonne 20 Grad ueber Horizont
				// Sun at 20 degrees above the horizon
	sonne_azimuth  = 180;	// Sonne genau im Westen (auf der x-Achse)
				// (x-Achse entspricht West-Ost Richtung,
				//  y-Achse entspricht Nord-Sued Richtung)
				// Sun exactly in western direction (on x-axis)
				// (x-axis corresponds to East-West direction,
				//  y-axis corresponds to North-South direction)

	// Hoehe ueber Meerespiegel
	// Height above sea level
double	Standhoehe = 1.500;

	//
	// Ggf. Sonnenstand und Standhoehe von der Kommandozeile einlesen
	//  (z.B. Option -sun10,180  oder -mm=150 an beliebiger Stelle)
	//
	// Optionally get Sun's position from the command line parameters
	//  (e.g. option -sun10,180 or -mm=150 at an arbitrary position)
	//
	option(argc,argv,"sun%lg,%lg",&sonne_altitude,&sonne_azimuth);
	option(argc,argv,"mm=%lg",&Standhoehe);

vector3	Standpunkt(1, 0,Standhoehe);	// Standpunkt im Osten        |  Observer at East
vector3	Blickpunkt(0, 0,Standhoehe);	// Blick von dort nach Westen |	 ... looking to the West

	option(argc,argv,"view=%lg",&Blickpunkt.z);

	//
	// Definition der Beobachterposition
	//
	// Definition of the position of the Observer
	//
Camera		  Kamera(Standpunkt,Blickpunkt);


	//
	// waagrechter Bildwinkel ist 50 Grad
	//
	// horizontal viewing angle is 50 degrees
	//
int	vangle = 50;
	option(argc,argv,"angle=%d",&vangle);

	//
	// Definition des Abbildungsmediums
	//
	// Definition of the "optical instrument"
	//
Standardobjektiv  Stdlens(vangle);

	//
	// "Aufsetzen" des Objektives
	//
	// "Screwing up" the lens
	//
	Kamera.use(Stdlens);

	// Das Welt-Objekt !
	// The World-Object !
Scene	Welt;


	// Radius of the Earth
const	double	Erdradius = 6350000.0;	  // 6350 km

	// Central point for the planet Earth
const	vector3	Erdmitte(0,0,-Erdradius);

	//
	// Definition der Erdoberflaeche
	//
	// Definition of the Earth's surface
	//	   
#if	1
Surface	Sand = s_weiss;			// (white Sand)
Sphere	Erdkruste(Erdmitte,Erdradius,Sand);
#else
Surface	H2O = s_water;		       // (alternatively water)
#if	1
vnoise	Meer(H2O,0.05,.1);	       // (with some waves ?)
Transformed_Surface Tmeer1(Meer), Tmeer2(Meer);
	Tmeer1.scale(vector3(10,1,1));
	Tmeer2.scale(vector3(10,1,1));
	Tmeer2.rotz(45*M_PI/180.);

Two_Surfaces Tmeer(Tmeer1, Tmeer2);

Sphere	Erdkruste(Erdmitte,Erdradius,Tmeer);
#else
Sphere	Erdkruste(Erdmitte,Erdradius,H2O);
#endif
#endif


	Welt.add(Erdkruste);
	Erdkruste.name="Erdkruste";

#if	1
	//
	// Definition der Erdatmosphaere
	//
	// Definition of the Earth's atmosphere
	//
double	water = ziemlich_klar,	// rather clear
	odepth = 8E-6;

	option(argc,argv,"water=%lg",&water);
	option(argc,argv,"air=%lg",&odepth);

Atmosphere  atm(Erdkruste,
//		ziemlich_klar,	// Wasserdampfgehalt
		water,		// Wasserdampfgehalt         | "steamness" factor
		0,		// Brechungsindex-1	     | refraction index - 1
		odepth);	// Optische Dichte der Luft  | optical depth of the air
//		8E-6);		// Optische Dichte der Luft
//		4E-6);		// Optische Dichte der Luft
//		7E-6);		// Optische Dichte der Luft

	Welt.add(atm);

	//
	// Wenn sich der Beobachter innerhalb der Atmosphaere befindet,
	// muss dies dem Weltobjekt mitgeteilt werden (dzt. geschieht dies
	// noch nicht automatisch - zuviele Unsicherheitsfaktoren)
	//
	// If the observer is within the atmosphere, this has to be told
	// to the world object. This is not done automatically because of
	// too much uncerntainties...
	//
	if (Standhoehe<=Stratosphere_limit)
		Welt.Inside.push(&atm);

	//
	// Iterationstiefe (in Meter, falls > 0) bzw. Anzahl der
	// Iterationsschritte ( falls < 0 ) zum Loesen der
	// Strahlungstransportgleichung (Extinktion, Streuung, Transmission)
	// Verwendet zur Berechnung des Himmelsblaues und des Abendrotes
	//
	// Iteration width (in metres, if >0), or number of 
	// iteration points (if <0), used for the numerical solution
	// of the Radiation Transfer Equation (extinction, scattering, transmission).
	// Used for the computation of the sky's blueness and the evening redding.
	//
	atm.Luft.optical_depth = -7;
	option(argc,argv,"steps=%lg",&atm.Luft.optical_depth);

Atmosphere::Layer Wolkenschicht(atm,2000,4000);

	if (option(argc,argv,"clouds"))
	{
		//
		// Definition einer Wolkenschicht im Bereich 2000m - 4000m
		//
		// Definition of a cloud layer at height 2000m - 4000m
		//
		Welt.add(Wolkenschicht);

		//
		// Wie bei der Atmosphaerendefinition...
		//
		// As at the definition of the atmosphere...
		//
		if (Standhoehe>=2000 && Standhoehe<=4000)
			Welt.Inside.push(&Wolkenschicht);

		//
		// Parameter, die die Wolkenmorphologie bestimmen:
		// Parameter, which determine the morphology of the clouds:
		//
		// double sharpness ............ Kantenschaerfe, je groesser, desto
		//			          abrupter die Begrenzung der Wolken
		//				 Shaerpness of the cloud's edges. The bigger this
		//				  number, the sharper the clouds.
		// double density .............. Maximale Dichte des Wasserdampfes; je
		//			          groesser, desto massiver die Wolke
		//				 Maximal density of the steam within the clouds.
		//				  The bigger, the more massive is the cloud.
		// vector3 scale ............... Dehnung der Wolkenmassen in eine
		//			          bestimmte Richtung
		//				 Scaling of the clouds into the given direction
		// int complexity .............. In welchem Masse treten Substrukturen
		//			          auf ? (Je groesser, desto mehr)
		//				 How prominent are substructures ?
		//				  (The bigger, the more structures are visible)
		//
		Wolkenschicht.sharpness  =  4; //img17
		option(argc,argv,"sharp=%lg",&Wolkenschicht.sharpness);
	//	Wolkenschicht.sharpness  = 32;	img16
	//	Wolkenschicht.sharpness  =  8;	img15
	//	Wolkenschicht.density    = 3E-4;	img0-img13
	//	Wolkenschicht.scale      = .25*vector3(.2,1,1);
	//	Wolkenschicht.scale      = .0025*vector3(.1,1,1);
	//	Wolkenschicht.scale      = 25.*vector3(.1,1,1);
	//	Wolkenschicht.scale      = 2.5*vector3(.2,1,1); img13
	//	Wolkenschicht.complexity = 2; //4

		Wolkenschicht.scale      = vector3(.2,1,1);
		option(argc,argv,"scale=(%lg,%lg,%lg)",
			&Wolkenschicht.scale.x,
			&Wolkenschicht.scale.y,
			&Wolkenschicht.scale.z	);

		Wolkenschicht.complexity = 2; //4
	//	Wolkenschicht.density    = 3E-4;
		Wolkenschicht.density    = 3E-5; // img17

		Wolkenschicht.setoptical_depth(-7);
	//	Wolkenschicht.setoptical_depth(-23);

		option(argc,argv,"cmplx=%d",&Wolkenschicht.complexity);
		option(argc,argv,"cdens=%lg",&Wolkenschicht.density);
	}
#endif
	//
	// Definition der Sonne
	//
	// Definition of the Sun
	//
Amun_Re Sonne(sonne_altitude*M_PI/180,sonne_azimuth*M_PI/180);
	Welt.add(Sonne);


	//
	// Belichtungszeit. Kann ggf. durch Kommandozeilenoption geaendert
	// 		    werden.
	//
	// Exposure time. May be overriden by command line parameters.
	//
	Kamera.Exposure_time= 1.0;
	option(argc,argv,"time=%lg",&Kamera.Exposure_time);


	//
	// Das Ausgabemedium wird von der Kommandozeile festgelegt.
	// Ohne Parameter erscheint eine Hilfeseite und das Programm wird
	// beendet.
	//
	// The output medium (screen, file) is beeing defined by command line
	// parameters. Without parameters a help screen will be displayed and
	// the program terminates.
	//
Camera::Frame	  frame(argc,argv);


	if (fork()) return 0;
	nice(5);

	//
	// Das Bild berechnen...
	//
	// Do the computation...
	//
	Kamera.expose(Welt,frame);

	//
	// Wenn das Ausgabemedium (der "Film") keine Datei ist (also
	// filename()==NULL ), d.h. eine Bildschirmausgabe erfolgt, dann
	// auf einen Tastendruck warten, andernfalls sofort beenden.
	//
	// If the output device (the "film") is not a file (therefore
	// the filename()==NULL), i.e. there is no direct screen output,
	// then wait for a key, elsewhere terminate now.
	//
	if (Kamera.Film && !Kamera.Film->filename()) getch();


	return 0;
}
