//
#pragma once

#include <memory>
#include <conio.h>
#include <ctime>

#include "demo_base.h"
#include "common.hpp"
#include "shader.hpp"
#include "geometry_shader.hpp"
#include "tga.h"
#include "transformation_node.h"
#include "geometry_node.h"
#include "object_node.h"
#include "particle_node.h"
#include "model.h"
#include "frustrum.h"
#include "spline.h"
#include "odsm_source.h"

//for sound
#include "fmod.hpp"
#include "fmod_errors.h"


class demo_abgabe1 : public demo_base
{
public:
	demo_abgabe1(void);
	virtual ~demo_abgabe1(void);

	virtual bool init();

protected:
	enum tex_indices {BG, ALTAR, NALTAR, TREE1, NTREE1, TERRAIN, RUIN, NRUIN, TREE2, NTREE2, 
		TREE3, NTREE3, TREE4, NTREE4, CELTICCROSS,  NCELTICCROSS, 
		FENCEPOST, NFENCEPOST, FIREPLACE, NFIREPLACE, WATCHTOWER, NWATCHTOWER, 
		FIRE_PARTICLE_1, FIRE_PARTICLE_2, 
		LOADSCREEN_TEX, LOADSCREEN_SHA, LOADSCREEN_MOD, 
		TERRAIN2, SNOWFLAKE1, LOADSCREEN_END, BLA, NUM_TEXTURES};

	//models
	Model object_model, tree_1_model, tree_2_model, tree_3_model, tree_4_model, altar_model;
	Model celtic_cross_model, fence_post_model, fireplace_model, watchtower_model;
	Model back_model, window_model, door_model;
	Model test_model; //just for testing purposes!

	object_node bg;

	GLuint texture[NUM_TEXTURES];
	GLuint shadow_tex_ID;
	GLuint shadow_FBO;

	//available shaders
	std::auto_ptr<Shader> texture_shader;
	std::auto_ptr<Shader> shadowmap_gen;
	std::auto_ptr<Shader> texture_cm;
	std::auto_ptr<Shader> texture_simple;
	std::auto_ptr<Shader> texture_normalmap;
	//std::auto_ptr<Shader> texture_terrain;
	std::auto_ptr<Shader> gauss_vertical;
	std::auto_ptr<Shader> gauss_horizontal;
	std::auto_ptr<Shader> pp_dof;
	std::auto_ptr<Shader> depthmap_gen;
	std::auto_ptr<geometry_shader> shadow_r2cm; //cubemap shadowmap generation shader
	std::auto_ptr<Shader> texture_odsm;
	std::tr1::shared_ptr<Shader> snow_shadow;
	std::tr1::shared_ptr<Shader> snow_render;
	
	//lights
	glm::vec3 light_0, transformed_light_0,
				light_1, transformed_light_1; //corner fireplace light

	//shadowmapping members
	glm::mat4 perspective_shadow;
	glm::mat4 lightview_matrix; //used for shadowmapping
	GLfloat poly_offset_factor, poly_offset_units; //anti shadow acne factors
	GLuint sm_width, sm_height;
	int soft_shadows;
	GLuint offset_tex;
	//odsm shadowmapping
	GLuint odsm_tex_ID;
	GLuint odsm_FBO;
	glm::mat4 perspective_odsm;
	glm::mat4 cm_rots[6]; //rotation matrices for each cubemap face
	glm::mat4 cm_trans;
	GLfloat* view_odsm[6]; //view matrices for each cubemap face
	GLuint cubemap_dim;
	odsm_source corner_fire_shadow;
	bool enable_odsm;
	float ultra_shadows;


	//scenegraph
	scene_node root;
	transformation_node object_root, fireplace_position, altar_position; //group node for all objects
	object_node light, light1, model, tree1, tree2, tree3, tree4, altar, celtic_cross, fence_post, fireplace, fireplace2, watchtower;
	object_node tree5, tree6, tree7, tree8, tree9, tree10, tree11, tree12, tree13, tree14, fence_post2, celtic_cross2;
	object_node tree15, tree16, tree17, tree18, tree19, tree20, tree21;
	object_node altar2, celtic_cross3, celtic_cross4, celtic_cross5, celtic_cross6;
	object_node back, door, windows;
	object_node test_node;
	particle_node fire_node, snow_node, corner_fire_node; //adding whatever_node to avoid weird stack variable error


	//skybox
	GLuint skybox_texture;
	GLuint skybox_vao, skybox_vbo[3];
	GLuint loadscreen_vao, loadscreen_vbo[3];

	//frustrum culling
	frustrum view_frustrum;
	int number_culled;
	bool in_frustrum(const scene_node& node) const;
	bool frustrum_culling_enabled;

	//snow
	bool draw_snow;

	//sound variables
	FMOD::System *system;
	FMOD::Sound *sound;
	FMOD::Sound *wind;
	FMOD::Sound *fire;
	FMOD::Channel *channel;
	FMOD::Channel *channelwind;
	FMOD::Channel *channelfire;
	FMOD_RESULT result;
	unsigned int version;
	float volume;
	bool paused;
	bool isplaying;
	time_t lastseconds;
	time_t actualseconds;

	//light0 positions on the camera path
	glm::vec3 light0_pos1, light0_pos2, light0_pos3, light0_pos4,
		pos_delta1, pos_delta2, pos_delta3, pos_delta4;

	
	//post-processing dof
	GLuint fbo_id[3]; //fbo for drawing the scene
	GLuint scene_tex_id[3], depth_tex_id[3], depth_buffer[3]; //texture ids for scene and depth textures, and renderbuffer for depth
	GLuint pp_vao_id, pp_vbo[3];
	GLfloat pp_border; //screenspace border for post-processing
	GLuint depth_tex, depth_fbo; //ids for depth only fbo/texture
	bool dof_enabled;

	//-------------
	//functions
	//-------------
	void init_shadowmap();
	void init_offset_texture();

	virtual void draw();	//main drawing method
	virtual void cleanup();
	virtual void load_config(const std::string& filepath = "../../config.txt");
	
	virtual void process_keys();
	virtual void update_light(float factor);
	virtual void render_node(scene_node& node);
	virtual void render_shadowmap(scene_node& node); //render the shadowmap
	virtual void render_depthmap(scene_node& node); //depthmap for dof
	void render_odsm(scene_node& node); //render omni-directional shadow mapping
	void init_odsm();
	virtual void init_particles();
	virtual void init_loadscreen(const Shader &shader, GLuint *vbo_id, GLuint *vao_id);
	virtual void draw_loadscreen(scene_node& node, GLuint texture_id );
	//skybox
	virtual bool init_skybox();
	virtual void draw_skybox();
	//loading and initializing objects
	virtual bool load_terrain();
	virtual bool load_trees();
	virtual bool load_stones();
	virtual bool load_ruin();
	//error processing of the sound system
	void errcheck(FMOD_RESULT result);
	//soundsystem
	bool init_soundsystem();
	//post_processing dof
	void init_postprocess();
	bool demo_abgabe1::init_fbo(); //init fbos for post-processing
	void draw_postprocess(const Shader& shader, GLuint source_tex_id, GLuint z_tex_id);
	//automatic camerapath
	void camerapath();
	void preparecampath();
	void preparefirepath();
	bool automcamera;
	Spline spline;
	Spline firespline;
	std::vector<glm::vec3>::iterator ep1;
	std::vector<glm::vec3>::iterator et1;
	std::vector<glm::vec3>::iterator ep2;
	std::vector<glm::vec3>::iterator et2;
	std::vector<glm::vec3>::iterator cp1;
	std::vector<glm::vec3>::iterator ct1;
	std::vector<glm::vec3>::iterator cp2;
	std::vector<glm::vec3>::iterator ct2;
	std::vector<glm::vec3>::iterator fep1;
	std::vector<glm::vec3>::iterator fet1;
	std::vector<glm::vec3>::iterator fep2;
	std::vector<glm::vec3>::iterator fet2;
	std::vector<glm::vec3>::iterator fcp1;
	std::vector<glm::vec3>::iterator fct1;
	std::vector<glm::vec3>::iterator fcp2;
	std::vector<glm::vec3>::iterator fct2;
	int maxfactor;
	float timespline;
	float timefire;
	bool endscreen;
	bool blackscreen;
	bool licht1;
	bool licht2;
	bool licht3;
	bool licht4;
	bool windsound;
	bool kamin;
	int cntcam;
	int cntwind;
	void updatefire();
	void init_light_positions();

};

