#pragma once
#include "renderer.h"
#include "camera.h"
#include "point_cloud.h"
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <vector>

class SplatFtbShader : public Renderer {
	struct VertexData {
		vec3 position = vec3(0, 0, 0);
		vec3 color = vec3(0, 0, 0);
		vec3 normal = vec3(0, 0, 0);
		float size = 0;
	};

	std::vector<VertexData> vertexBuffer;

	PointCloud& pointcloud;
	Camera& camera;
	glm::vec3 cameraDir;
	glm::mat4& modelT;
	float& pSizeT;
	ColorShade colorShade;
	bool accurateSort = false;

	static constexpr size_t SAMPLE_RES = 32;
	float footprint[SAMPLE_RES * SAMPLE_RES];

	GLuint splatProgram;
	GLuint blendProgram;
	GLuint stencilProgram;
	GLuint backgroundProgram;

	GLuint layerFramebuffer;
	GLuint textureColor;
	GLuint textureAlphaWeight;
	GLuint layerStencil;
	GLuint compositeFramebuffer;
	GLuint compositeColor;
	GLuint compositeStencil;
	
	GLuint vbo = 0, vao = 0, ebo = 0, textureId = 0;
	GLuint quadVAO, quadVBO;
	GLuint elementCount = 0;

	static constexpr float AMBIENT_I = 0.2f;
	static constexpr float DIFFUSE_I = 0.7f;
	static constexpr float SPECULAR_I = 0.7f;
	static constexpr float SPECULAR_POW = 4.0f;

	void generateFootprint();
	void generateShaderProgram();
	void generateFramebuffers();
	void generateModelBuffers();

	void loadVertexData(bool realloc);
	void updateUniforms();
	void setLayerElements(unsigned int* elements, unsigned int n);
	void drawLayer();

public:
	SplatFtbShader(PointCloud& pointcloud, Camera& camera, glm::mat4& modelT, float& pSizeT, ColorShade colorShade);
	~SplatFtbShader();
	void ChangeColorShade(ColorShade colorShade);
	void ReloadPointCloud();
	void ChangeSortMode(bool accurate);

	void Begin();
	void Draw();
};