/*
- solar_final3.cpp
- primitive solarsystem for metalab cg-workshop
- "camera" is fixed on northpole of first planet
- dont forget to change the parameters for the camara if you change the params of the first planet
- key s is turbo on/off
-
- thanks to kyrah for the workshop, wizard23, marius, nex for all the support
- feel free to use it
-
- max - cygenb0ck@stealth.at
-
*/

#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <SDL/SDL.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#include <SDL.h>
#endif

#include <stdio.h>
#include <unistd.h>
#include <list>
using namespace std;

float cameraPosition = 0;
float cameraSpeed = 0.04;
float timeshift = 1;

void drawSphere(float radius, GLint slices=50, GLint stacks=50);
class planet {
	float d,r,v,cR,cG,cB,p;
	list<planet *> moons;
	public:
		planet (float, float, float, float, float, float);
		void addPlanet(planet &moon){
			moons.push_back(&moon);
		}
		void draw ();
};

planet::planet (float a, float b, float c, float cd, float ce, float cf){
	d = a;
	r = b;
	v = c;
	p = 0;
	cR = cd;
	cG = ce;
	cB = cf;
}

void planet::draw (){
	glPushMatrix();
	p = p+timeshift*v;
	if ( p>360 ){
		p=p-360;
	}
	glRotatef (p,0,1,0);
	glTranslatef(d,0,0);
	glColor3f(cR,cG,cB);
	drawSphere(r);
	
	list<planet*>::iterator i;
	for(i=moons.begin(); i != moons.end(); ++i ){
		(*i)->draw();
	}
	
	glPopMatrix();
}

void drawSphere(float radius, GLint slices, GLint stacks)
{
	GLUquadricObj* q = gluNewQuadric();
	gluQuadricDrawStyle (q, GLU_FILL);
	gluQuadricNormals   (q, GLU_SMOOTH);
	gluSphere (q, radius, slices, stacks);
	gluDeleteQuadric(q);
}

void myinit(int width, int height) 
{
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glEnable(GL_DEPTH_TEST);
	glViewport(0, 0, width, height);  
	
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(90.0, (float)width/(float)height, 0.1, 1000.0);
	
	glMatrixMode(GL_MODELVIEW);
}

void mydisplay(planet &sun)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  
	glLoadIdentity();  
	
	cameraPosition = cameraPosition + cameraSpeed*timeshift;
	if (cameraPosition > 360){
		cameraPosition = cameraPosition - 360;
	}
	
	gluLookAt(30, 2.4, 0.0,  // eye
            15.0, 5.0, 0.0, // center
            0.0, 10.0, 0.0); // up


	glRotatef(-cameraPosition,0,1,0);

	sun.draw();
	
	SDL_GL_SwapBuffers();
}

int main(int argc, char ** argv){
	int width = 1300, height = 950;

	// Initialize SDL
	
	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
		fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
		return -1;
	}

	if (!SDL_SetVideoMode(width, height, 32, SDL_OPENGL)) {
		fprintf(stderr, "Unable set SDL video mode: %s\n", SDL_GetError());
		SDL_Quit();
		return -1;
	}

	SDL_WM_SetCaption("SDL/OpenGL intro", NULL);  // window title
	myinit(width, height);  // initialize OpenGL

	planet sun (0, 5, 0,		0.9, 0.7, 0);
	
	planet earth (30,2.2,0.04,	0.5,0.5,1); //r,g,b
	planet earth_moon (10,1.3,0.05,	0.6,0.6,0.6);
	planet moon_moon (6,1,0.02,	0.2,0.2,0.2);
	sun.addPlanet(earth);
	earth.addPlanet(earth_moon);
	earth_moon.addPlanet(moon_moon);
	
	planet mars(60,3.4,0.03,		0.8,0.2,0.2);
	planet mars_moon (12.3,1.2,0.02,	0.6,0.4,0.4);
	planet moon_moon2 (3.5,0.5,0.031,	0.5,0.5,0.5);
	sun.addPlanet(mars);
	mars.addPlanet(mars_moon);
	mars_moon.addPlanet(moon_moon2);
	
	planet saturn (90,3.2,0.02, 	0.3,0.6,0.0);
	planet titan (8,1.4,0.08,	0.5,0.5,0.5);
	sun.addPlanet(saturn);
	saturn.addPlanet(titan);
	
	planet neptun (130,2.5,0.01,	0.0,0.7,0.2);
	planet erebus (5,1.0,0.1,	0.3,0.3,0.3);
	sun.addPlanet (neptun);
	neptun.addPlanet(erebus);
	
	// main application loop
	bool done = false;
	while (!done) {
		mydisplay(sun);
		SDL_Event event;
		while (SDL_PollEvent(&event)) {
			if (event.type == SDL_QUIT) done = true;
			if (event.type == SDL_KEYDOWN) {
				switch(event.key.keysym.sym) {
					case SDLK_ESCAPE:
						done = true;
					break;
					case SDLK_s:
						timeshift = (timeshift>1?1:20);
					break;
				}
			}
		}
	}

	SDL_Quit();
	return 0;
}