#pragma once

#include "OpenGLRenderer.h"
#include "RenderPassDescriptor.h"
#include "ShaderTextureBindings.h"
#include "ShaderTypes.h"
#include "VideoIOFormat.h"

#include <functional>
#include <string>
#include <vector>

class OpenGLRenderPass
{
public:
	using LayerProgram = OpenGLRenderer::LayerProgram;
	using PassProgram = OpenGLRenderer::LayerProgram::PassProgram;
	using TextBindingUpdater = std::function<bool(const RuntimeRenderState&, LayerProgram::TextBinding&, std::string&)>;
	using GlobalParamsUpdater = std::function<bool(const RuntimeRenderState&, unsigned, unsigned, bool)>;

	explicit OpenGLRenderPass(OpenGLRenderer& renderer);

	void Render(
		bool hasInputSource,
		const std::vector<RuntimeRenderState>& layerStates,
		unsigned inputFrameWidth,
		unsigned inputFrameHeight,
		unsigned captureTextureWidth,
		VideoIOPixelFormat inputPixelFormat,
		unsigned historyCap,
		const TextBindingUpdater& updateTextBinding,
		const GlobalParamsUpdater& updateGlobalParams);

private:
	void RenderDecodePass(unsigned inputFrameWidth, unsigned inputFrameHeight, unsigned captureTextureWidth, VideoIOPixelFormat inputPixelFormat);
	std::vector<RenderPassDescriptor> BuildLayerPassDescriptors(
		const std::vector<RuntimeRenderState>& layerStates,
		std::vector<LayerProgram>& layerPrograms) const;
	void RenderLayerPass(
		const RenderPassDescriptor& pass,
		unsigned inputFrameWidth,
		unsigned inputFrameHeight,
		unsigned historyCap,
		const TextBindingUpdater& updateTextBinding,
		const GlobalParamsUpdater& updateGlobalParams);
	void RenderShaderProgram(
		GLuint layerInputTexture,
		GLuint sourceTexture,
		GLuint destinationFrameBuffer,
		PassProgram& passProgram,
		const RuntimeRenderState& state,
		unsigned inputFrameWidth,
		unsigned inputFrameHeight,
		unsigned historyCap,
		const TextBindingUpdater& updateTextBinding,
		const GlobalParamsUpdater& updateGlobalParams);

	OpenGLRenderer& mRenderer;
	ShaderTextureBindings mTextureBindings;
	mutable std::vector<RenderPassDescriptor> mPassScratch;
};
