text: #pragma once
  
  #include <GL/glew.h>
  #include <GLFW/glfw3.h>
  
  #define SCR_WIDTH 1000
  #define SCR_HEIGHT 800
  
  class WaterFrameBuffers 
  {
  protected:
  	static int REFLECTION_WIDTH;
  	static int REFRACTION_WIDTH;
  
  private:
  	static int REFLECTION_HEIGHT; 
  	static int REFRACTION_HEIGHT;
  
  public:
  	unsigned int reflectionFrameBuffer;
  	unsigned int reflectionTexture;
  	unsigned int reflectionDepthBuffer;
  	unsigned int refractionFrameBuffer;
  	unsigned int refractionTexture;
  	unsigned int refractionDepthTexture;
  
  public:
  	WaterFrameBuffers()
  	{
  		
  	}
  
  	void init()
  	{
  		initialiseReflectionFrameBuffer();
  		initialiseRefractionFrameBuffer();
  	}
  
  	void cleanUp() 
  	{
  		glDeleteFramebuffers(1, &reflectionFrameBuffer);
  		glDeleteTextures(1, &reflectionTexture);
  		glDeleteRenderbuffers(1, &reflectionDepthBuffer);
  		glDeleteFramebuffers(1, &refractionFrameBuffer);
  		glDeleteTextures(1, &refractionDepthTexture);
  	}
  
  	inline void bindReflectionFrameBuffer() 
  	{
  		bindFrameBuffer(reflectionFrameBuffer, REFLECTION_WIDTH, REFLECTION_HEIGHT);
  	}
  
  	inline void bindRefractionFrameBuffer() 
  	{
  		bindFrameBuffer(refractionFrameBuffer, REFRACTION_WIDTH, REFRACTION_HEIGHT);
  	}
  
  	void unbindCurrentFrameBuffer()
  	{
  		glBindFramebuffer(GL_FRAMEBUFFER, 0);
  		glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);
  	}
  
  	inline unsigned int getReflectionTexture() 
  	{
  		return reflectionTexture;
  	}
  
  	inline unsigned int getRefractionDepthTexture() 
  	{
  		return refractionDepthTexture;
  	}
  
  public:
  	void initialiseReflectionFrameBuffer() 
  	{
  		reflectionFrameBuffer = createFrameBuffer();
  		reflectionTexture = createTextureAttachment(REFLECTION_WIDTH, REFLECTION_HEIGHT);
  		reflectionDepthBuffer = createDepthBufferAttachment(REFLECTION_WIDTH, REFLECTION_HEIGHT);
  		unbindCurrentFrameBuffer();
  	}
  
  	void initialiseRefractionFrameBuffer() 
  	{
  		refractionFrameBuffer = createFrameBuffer();
  		refractionTexture = createTextureAttachment(REFRACTION_WIDTH, REFRACTION_HEIGHT);
  		refractionDepthTexture = createDepthTextureAttachment(REFRACTION_WIDTH, REFRACTION_HEIGHT);
  		unbindCurrentFrameBuffer();
  	}
  
  	void bindFrameBuffer(int frameBuffer, int width, int height)
  	{
  		glBindTexture(GL_TEXTURE_2D, 0);
  		glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
  		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  		glViewport(0, 0, width, height);
  	}
  
  	unsigned int createFrameBuffer() 
  	{
  		unsigned int frameBuffer;
  		glGenFramebuffers(1, &frameBuffer);
  		glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
  		glDrawBuffer(GL_COLOR_ATTACHMENT0);
  		return frameBuffer;
  	}
  
  	int createTextureAttachment(int width, int height)
  	{
  		unsigned int texture;
  		glGenTextures(1, &texture);
  		glBindTexture(GL_TEXTURE_2D, texture);
  		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
  		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  		glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0);
  		return texture;
  	}
  
  	int createDepthTextureAttachment(int width, int height)
  	{
  		unsigned int texture;
  		glGenTextures(1, &texture);
  		glBindTexture(GL_TEXTURE_2D, texture);
  		glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
  		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  		glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture, 0);
  		return texture;
  	}
  
  	int createDepthBufferAttachment(int width, int height) 
  	{
  		unsigned int depthBuffer;
  		glGenRenderbuffers(1, &depthBuffer);
  		glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
  		glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
  		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
  			depthBuffer);
  		return depthBuffer;
  	}
  };
  
  int WaterFrameBuffers::REFLECTION_WIDTH = 1280;
  int WaterFrameBuffers::REFRACTION_WIDTH = 1280 / 2;
  
  int WaterFrameBuffers::REFLECTION_HEIGHT = 720;
  int WaterFrameBuffers::REFRACTION_HEIGHT = 720 / 2;