/* scene.c */

#include "scene.h"

#include <stdio.h>
#include <stdlib.h>
#include "illum.h"

#if defined(SCENE_DEFAULT)
	#define TOTAL_OBJECTS	29
	static texture
		grass = {0},
		globe = {0}
	;
#elif defined(SCENE_CSGTEST)
	#define TOTAL_OBJECTS 2
	static texture
		grass = {0}
	;
#elif defined(SCENE_TEAPOT)
	#define TOTAL_OBJECTS	1024
	#include "scene-teapot.h"
#else
	#error "No scene defined."
#endif


static object_entry* ptrObjs[TOTAL_OBJECTS] = {0};

void scene_init(camera* c) {

	/* Common */

	int i;
	num ambient_intensity;
	tuple background_colour;
	view* theView = malloc(sizeof(view));
	
#if defined(SCENE_DEFAULT)
	
	/* Load textures */
	
	grass = texture_alloc("textures\\grass.png");
	globe = texture_alloc("textures\\mercator.png");
	
	/* Define materials */
	
	// Texture, DiffCol, SpecCol, Shininess, Reflect%, RefractiveIdx, Refract%	
	const material_t
		m_shiny_red  = {0, {0.7, 0.3, 0.2}, {0.4, 0.4, 0.4}, 100, 0.0 },
		m_shiny_blue = {0, {0.2, 0.3, 0.7}, {0.8, 0.8, 0.8}, 200, 0.3 },
		m_tex_globe  = {&globe, {0, 0, 1.}, {0.5, 0.5, 0.5}, 100, 0},
		m_bubble     = {0, {1.0, 1.0, 1.0}, {0.3, 0.3, 0.3}, 200, 0.0 , 1.1, 0.8},
	//  m_matt_green = {0, {0.1, 0.7, 0.1}, {0.0, 0.0, 0.0}, 0.0, 0.04},
		m_tex_grass  = {&grass, {0,0.4, 0}, {0.0, 0.0, 0.0}, 0.0, 0.00}
	;
	
	/* Create scene objects */
	
	ptrObjs[0] = object_new_sphere(m_bubble,
					geo_new(0.35, 0.6, 0.5), 0.25 );
	ptrObjs[1] = object_new_sphere  (m_tex_globe,
					geo_new(0.75, 0.2, 0.6), 0.15 );
	/*ptrObjs[2] = object_new_triangle(m_shiny_blue,
					geo_new(1,0,0.5), geo_new(1,1,0.5), geo_new(0,1,0.5) );*/
	ptrObjs[2] = object_new_box(m_shiny_red,
					geo_new(-0.2, 0.15, 0), geo_new(0.3, 0.1, 0.5) );
	ptrObjs[3] = object_new_plane(m_tex_grass,
					geo_new(0, 0, 0), geo_new(0, 1, 0) );
	
	int j;
	for (i = 0; i < 5; i++) for (j = 0; j < 5; j++) {
		ptrObjs[4 + i + (5*j)] = object_new_sphere( m_shiny_blue,
			geo_new( -0.1+(0.3*i), 0.4+(0.08*(i-j)), -0.0+(0.2*j) ), 0.05
		);
	}
	
	/* Lights */
	
	int lights_count = 2;
	lighting_t* lights  = malloc(lights_count * sizeof(lighting_t));
	lights[0].intensity = 0.6;
	lights[0].dir       = geo_unit( geo_new(2,5,3) );
	lights[1].intensity = 0.8;
	lights[1].dir       = geo_unit( geo_new(5,2,3) );
	
	ambient_intensity   = 0.1;
	background_colour   = geo_new(0.7, 0.7, 0.85);
	
	/* Viewport */	
	
	theView->eye_point  = geo_new(0.5, 0.5, 2.0);
	theView->look_at    = geo_new(0.5, 0.5, 0.0);
	theView->fov        = 50;
	
#elif defined(SCENE_CSGTEST)

	grass = texture_alloc("textures\\grass.png");
	const material_t
		m_sphere	= {0, {0.3, 0.4, 0.9}, {0.8, 0.8, 0.8}, 100, 0.2 },
		m_ground	= {&grass, {0,0.4, 0}, {0.0, 0.0, 0.0}, 0.0, 0.00}
	;
	
	ptrObjs[0] = object_new_plane(m_ground, geo_new(0,0,0), geo_new(0,1,0) );
	ptrObjs[1] = object_new_csg( m_sphere, OBJ_CSG_SUBTRACT,
		object_new_sphere(m_sphere, geo_new(0, 0.5, 0), 0.5),
		object_new_sphere(m_sphere, geo_new(0.25, 0.5, 0.25), 0.3)
	);
	
	int lights_count = 1;
	lighting_t* lights  = malloc(lights_count * sizeof(lighting_t));
	lights[0].intensity = 0.9;
	lights[0].dir       = geo_unit( geo_new( 2, 5, 3 ) );	
	ambient_intensity   = 0.4;
	background_colour   = geo_new(0.7, 0.7, 0.85);	
	theView->eye_point  = geo_new(0.5, 0.5, 2.0);
	theView->look_at    = geo_new(0, 0.5, 0.0);
	theView->fov        = 50;	
	
#elif defined(SCENE_TEAPOT)

	const material_t
		m_walls      = {0, {1.0, 1.0, 1.0}, {0.4, 0.5, 0.4}, 100, 0.4},
		m_teapot     = {0, {0.5, 1.0, 0.5}, {0.8, 0.8, 0.8},  80, 0.0}
	;
	
	ptrObjs[0] = object_new_plane(m_walls, geo_new(0, 3, 0), geo_new(0, 0, 1) );
	int j = 0;
	for (i = 1; i < TOTAL_OBJECTS; i++, j += 3) {
		ptrObjs[i] = object_new_triangle(m_teapot,
			object_teapot[j], object_teapot[j+1], object_teapot[j+2]
		);
	}
	
	int lights_count = 2;
	lighting_t* lights  = malloc(lights_count * sizeof(lighting_t));
	lights[0].intensity = 0.6;
	lights[0].dir       = geo_unit( geo_new(2,5,3) );
	lights[1].intensity = 0.8;
	lights[1].dir       = geo_unit( geo_new(2,-5,8) );	
	ambient_intensity   = 0.1;
	background_colour   = geo_new(0.4, 0.4, 0.4);	
	theView->eye_point  = geo_new(0.0, -5.0, 2.5);
	theView->look_at    = geo_new(0.0, 0.0, 1.0);
	theView->fov        = 50;
		
#endif
	
	/* Common */
	
	theView->width     = WIN_SIZE_X;
	theView->height    = WIN_SIZE_Y;	
	
	/* Tidy up */
	
	object_entry *scene = malloc( TOTAL_OBJECTS * sizeof(object_entry) );
	for (i = 0; i < TOTAL_OBJECTS; i++) scene[i] = * (ptrObjs[i]);
	
	camera theCamera = {
		theView, scene,  TOTAL_OBJECTS, lights,	lights_count,
		ambient_intensity, background_colour
	};
	*c = theCamera;
}

void scene_free(camera *c) {
	int i;
	
	free(c->v);
	free(c->scene);
	free(c->lights);
	
	for (i = 0; i < c->scene_count; i++) object_free(ptrObjs[i]);

#if defined(SCENE_DEFAULT)
	texture_free(&grass);
	texture_free(&globe);
#elif defined(SCENE_CSGTEST)
	texture_free(&grass);
#endif
}
