/* particle_node.h
	scenegraph node for particle systems (fire, snow)
	
*/

#pragma once

#include <memory>

#include "geometry_node.h"

class particle_node : public geometry_node {
public:

	//methods
	particle_node();
	particle_node(std::vector<GLfloat>& pts, std::vector<GLfloat>& prtcls, GLuint tex_particle, GLuint tex_particle2, GLuint particle_dimension,
			const std::string& render_path = "../../shader/fire_render", const std::string& update_path = "../../shader/fire_update");
	virtual ~particle_node();
	bool init();

	//render methods
	virtual void pre_render();
	virtual void render();

	void set_render_shader(std::tr1::shared_ptr<Shader> rs) {render_shader = rs;}
	void set_update_shader(std::tr1::shared_ptr<Shader> us) {update_shader = us;}
	void set_modelview_matrix(glm::mat4& m) {modelview_matrix = &m;}
	void set_perspective_matrix(glm::mat4& m) {perspective_matrix = &m;}
	void set_delta(const float d) {delta = d;}
	void set_forcefield(const glm::vec3 forcefield) {force_field = forcefield; has_forcefield = true;} //caution: not all shaders have a force_field uniform
	GLuint get_particle_lookup_width() {return particle_lookup_width;}
	void set_default_framebuffer(const GLuint fbo) {default_framebuffer = fbo;}
	void set_depth_enabled(const bool b) {depth_enabled = b;}
	bool get_depth_enabled() const {return depth_enabled;}
	GLuint get_lookup_texture() const {return texture_lookup[1 - flip];}
	GLuint get_vao_id() const {return vao_id;}
	virtual glm::vec3 get_dimension() const {return dimension;}
	virtual void set_dimension(const glm::vec3 dim) {dimension = dim;}
	virtual void set_burn_speed(const float speed) {burn_speed = speed;}

private:
	//members
	std::vector<GLfloat> points;		//points for referencing each texel
	std::vector<GLfloat> particles;	//initial particle data
	GLuint particle_lookup_width; //dimensions of the texture storing the particle
	GLuint vertex_vbo_id, vao_id;
	GLuint texture_particle, texture_particle2, texture_particle3;  //texture handles
	GLuint texture_lookup[2]; //handle for the lookup textures
	GLuint framebuffer_lookup[2]; //framebuffer for both textures
	GLuint default_framebuffer; //currently used fbo
	//locations for shader variables
	//render shader
	GLint vertex_location,
		lookup_texture_location,
		texture_location, texture_location2, texture_location3,
		//update shader
		size_location,
		time_location,
		vertex_update_location,
		lookup_texture_update_location;
	GLint flip; //switching read and write framebuffers
	glm::mat4 * modelview_matrix;
	glm::mat4 * perspective_matrix;

	//burn speed update
	float delta;
	float burn_speed;

	//forcefield
	glm::vec3 force_field;
	bool has_forcefield;

	//depth check
	bool depth_enabled;

	//available shaders
	std::tr1::shared_ptr<Shader> render_shader;
	std::tr1::shared_ptr<Shader> update_shader;

	//view_frustrum culling
	glm::vec3 dimension;

	//members
	void update(); //update particles
};