/* class demo_shadow
   test shadow mapping
*/

#pragma once

#include <memory>

#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 "model.h"


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

	virtual bool init();

protected:
	enum tex_indices {BG, TREE, YELLOW, STONE, NUM_TEXTURES};
	GLuint bg_vbo_id[4], bg_vao_id;
	//model matrix (no view matrix included)
	glm::mat4 view_matrix;
	glm::vec2 near_far;

	//models
	Model object_model, object_model2, cube;

	GLuint texture[NUM_TEXTURES];

	//available shaders
	std::auto_ptr<Shader> texture_shader;
	std::auto_ptr<Shader> shadowmap_gen;
	std::auto_ptr<geometry_shader> shadow_r2cm; //cubemap shadowmap generation shader
	std::auto_ptr<Shader> texture_odsm;
	
	//light
	glm::vec3 light_0, transformed_light_0;
	glm::mat4 lightview_matrix;

	//shadowmapping stuff
	//odsm: omni-directional shadow mapping
	GLuint shadow_tex_ID;
	GLuint shadow_FBO;
	GLfloat poly_offset_factor, poly_offset_units; //anti shadow acne factors
	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 jittering
	GLuint offset_size;
	GLuint offset_tex;

	//scenegraph
	scene_node root, object_root;
	object_node bg, ground, right_side, light, model, model2;

	//functions
	void init_bg(const Shader &shader, GLuint *vbo_id, GLuint *vao_id);
	void init_shadowmap();
	void init_odsm();
	void init_offsets();

	virtual void draw();	//main drawing method
	virtual void cleanup();
	
	virtual void process_keys();
	void update_light(float factor);
	void render_node(scene_node& node);
	void render_shadowmap(scene_node& node); //render the shadowmap
	void render_odsm(scene_node& node); //render omni-directional shadow mapping
};