Преглед на файлове

Merge GLRenderer.h with GLRenderer.cpp

Daniele Bartolini преди 12 години
родител
ревизия
521f9dc5a8
променени са 3 файла, в които са добавени 520 реда и са изтрити 577 реда
  1. 0 2
      engine/CMakeLists.txt
  2. 520 5
      engine/renderers/backend/gl/GLRenderer.cpp
  3. 0 570
      engine/renderers/backend/gl/GLRenderer.h

+ 0 - 2
engine/CMakeLists.txt

@@ -483,7 +483,6 @@ if (LINUX)
 	)
 
 	list (APPEND RENDERERS_HEADERS
-		renderers/backend/gl/GLRenderer.h
 		renderers/backend/gl/glx/GLContext.h
 	)
 
@@ -616,7 +615,6 @@ if (WINDOWS)
 	)
 
 	list (APPEND RENDERERS_HEADERS
-		renderers/backend/gl/GLRenderer.h
 		renderers/backend/gl/wgl/GLContext.h
 		renderers/backend/gl/wgl/wglext.h
 	)

+ 520 - 5
engine/renderers/backend/gl/GLRenderer.cpp

@@ -37,15 +37,42 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include <algorithm>
 #include "Allocator.h"
 #include "Assert.h"
-#include "Types.h"
-#include "GLRenderer.h"
+#include "Device.h"
+#include "GLContext.h"
+#include "Hash.h"
 #include "Log.h"
-#include "Vector4.h"
 #include "Matrix3x3.h"
 #include "Matrix4x4.h"
-#include "Device.h"
-#include "Hash.h"
+#include "Renderer.h"
+#include "Resource.h"
 #include "StringUtils.h"
+#include "Types.h"
+#include "Vector4.h"
+#include "VertexFormat.h"
+
+//-----------------------------------------------------------------------------
+static const char* gl_error_to_string(GLenum error)
+{
+	switch (error)
+	{
+		case GL_INVALID_ENUM: return "GL_INVALID_ENUM";
+		case GL_INVALID_VALUE: return "GL_INVALID_VALUE";
+		case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
+		case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
+		default: return "UNKNOWN_GL_ERROR";
+	}
+}
+
+//-----------------------------------------------------------------------------
+#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
+	#define GL_CHECK(function)\
+		function;\
+		do { GLenum error; CE_ASSERT((error = glGetError()) == GL_NO_ERROR,\
+				"OpenGL error: %s", gl_error_to_string(error)); } while (0)
+#else
+	#define GL_CHECK(function)\
+		function;
+#endif
 
 namespace crown
 {
@@ -86,6 +113,13 @@ const GLenum TEXTURE_WRAP_TABLE[] =
 	GL_REPEAT
 };
 
+//-----------------------------------------------------------------------------
+struct GLTextureFormatInfo
+{
+	GLenum internal_format;
+	GLenum format;
+};
+
 //-----------------------------------------------------------------------------
 const GLTextureFormatInfo TEXTURE_FORMAT_TABLE[PixelFormat::COUNT] =
 {
@@ -180,6 +214,487 @@ ShaderUniform::Enum name_to_stock_uniform(const char* uniform)
 	return ShaderUniform::COUNT;
 }
 
+//-----------------------------------------------------------------------------
+struct VertexBuffer
+{
+	//-----------------------------------------------------------------------------
+	void create(size_t size, const void* data, VertexFormat::Enum format)
+	{
+		GL_CHECK(glGenBuffers(1, &m_id));
+		CE_ASSERT(m_id != 0, "Failed to create buffer");
+		GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, m_id));
+		GL_CHECK(glBufferData(GL_ARRAY_BUFFER, size, data, (data == NULL) ? GL_STREAM_DRAW : GL_STATIC_DRAW));
+		GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
+
+		m_size = size;
+		m_format = format;
+	}
+
+	//-----------------------------------------------------------------------------
+	void update(size_t offset, size_t size, const void* data)
+	{
+		GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, m_id));
+		GL_CHECK(glBufferSubData(GL_ARRAY_BUFFER, offset, size, data));
+		GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
+	}
+
+	//-----------------------------------------------------------------------------
+	void destroy()
+	{
+		GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
+		GL_CHECK(glDeleteBuffers(1, &m_id));
+	}
+
+public:
+
+	GLuint m_id;
+	size_t m_size;
+	VertexFormat::Enum m_format;
+};
+
+//-----------------------------------------------------------------------------
+struct IndexBuffer
+{
+	//-----------------------------------------------------------------------------
+	void create(size_t size, const void* data)
+	{
+		GL_CHECK(glGenBuffers(1, &m_id));
+		CE_ASSERT(m_id != 0, "Failed to create buffer");
+		GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_id));
+		GL_CHECK(glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, (data == NULL) ? GL_STREAM_DRAW : GL_STATIC_DRAW));
+		GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
+
+		m_size = size;
+	}
+
+	//-----------------------------------------------------------------------------
+	void update(size_t offset, size_t size, const void* data)
+	{
+		GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_id));
+		GL_CHECK(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, size, data));
+		GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
+	}
+
+	//-----------------------------------------------------------------------------
+	void destroy()
+	{
+		GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
+		GL_CHECK(glDeleteBuffers(1, &m_id));
+	}
+
+public:
+
+	GLuint		m_id;
+	uint32_t	m_size;
+};
+
+//-----------------------------------------------------------------------------
+struct Uniform
+{
+	Uniform()
+	{
+		string::strncpy(m_name, "", CE_MAX_UNIFORM_NAME_LENGTH);
+	}
+
+	void create(const char* name, UniformType::Enum type, uint8_t num)
+	{
+		string::strncpy(m_name, name, CE_MAX_UNIFORM_NAME_LENGTH);
+		m_type = type;
+		m_num = num;
+
+		size_t size = UNIFORM_SIZE_TABLE[type] * num;
+		m_data = default_allocator().allocate(size);
+		memset(m_data, 0, size);
+
+		// Log::d("Uniform created, name = %s, type = %d, num = %d, size = %ld", m_name, type, num, size);
+	}
+
+	void update(size_t size, const void* data)
+	{
+		// Log::d("Uniform updated, new size = %ld, new ptr = %d", size, *((int32_t*)data));
+		memcpy(m_data, data, size);
+	}
+
+	void destroy()
+	{
+		default_allocator().deallocate(m_data);
+	}
+
+public:
+
+	char m_name[CE_MAX_UNIFORM_NAME_LENGTH];
+	UniformType::Enum m_type;
+	uint8_t m_num;
+	void* m_data;
+};
+
+//-----------------------------------------------------------------------------
+struct Shader
+{
+	//-----------------------------------------------------------------------------
+	void create(ShaderType::Enum type, const char* text)
+	{
+		m_id = GL_CHECK(glCreateShader(type == ShaderType::VERTEX ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER));
+
+		GL_CHECK(glShaderSource(m_id, 1, &text, NULL));
+		GL_CHECK(glCompileShader(m_id));
+
+		GLint success;
+		GL_CHECK(glGetShaderiv(m_id, GL_COMPILE_STATUS, &success));
+
+		if (!success)
+		{
+			GLchar info_log[2048];
+			GL_CHECK(glGetShaderInfoLog(m_id, 2048, NULL, info_log));
+			CE_ASSERT(false, "Shader compilation failed\n\n%s", info_log);
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	void destroy()
+	{
+		GL_CHECK(glDeleteShader(m_id));
+	}
+
+public:
+
+	GLuint m_id;
+};
+
+//-----------------------------------------------------------------------------
+struct Texture
+{
+	//-----------------------------------------------------------------------------
+	void create(uint32_t width, uint32_t height, PixelFormat::Enum format, const void* data)
+	{
+		GL_CHECK(glGenTextures(1, &m_id));
+		GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_id));
+
+		#if defined(LINUX) || defined(WINDOWS)
+			GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE));
+		#endif
+
+		GLenum internal_fmt = TEXTURE_FORMAT_TABLE[format].internal_format;
+		GLenum fmt = TEXTURE_FORMAT_TABLE[format].format;
+
+		GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, internal_fmt, width, height, 0,
+					 			fmt, GL_UNSIGNED_BYTE, data));
+		GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
+
+		m_target = GL_TEXTURE_2D;
+		m_format = format;
+	}
+
+	//-----------------------------------------------------------------------------
+	void update(uint32_t x, uint32_t y, uint32_t width, uint32_t height, const void* data)
+	{
+		GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_id));
+		GL_CHECK(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA,
+									GL_UNSIGNED_BYTE, data));
+		GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
+	}
+
+	//-----------------------------------------------------------------------------
+	void set_sampler_state(uint32_t flags)
+	{
+		const GLenum min_filter = TEXTURE_MIN_FILTER_TABLE[(flags & TEXTURE_FILTER_MASK) >> TEXTURE_FILTER_SHIFT];
+		const GLenum mag_filter = TEXTURE_MAG_FILTER_TABLE[(flags & TEXTURE_FILTER_MASK) >> TEXTURE_FILTER_SHIFT];
+		const GLenum wrap_s = TEXTURE_WRAP_TABLE[(flags & TEXTURE_WRAP_U_MASK) >> TEXTURE_WRAP_U_SHIFT];
+		const GLenum wrap_t = TEXTURE_WRAP_TABLE[(flags & TEXTURE_WRAP_V_MASK) >> TEXTURE_WRAP_V_SHIFT];
+
+		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_WRAP_S, wrap_s));
+		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_WRAP_T, wrap_t));
+
+		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, min_filter));
+		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, mag_filter));
+	}
+
+	//-----------------------------------------------------------------------------
+	void destroy()
+	{
+		GL_CHECK(glBindTexture(m_target, 0));
+		GL_CHECK(glDeleteTextures(1, &m_id));
+	}
+
+	//-----------------------------------------------------------------------------
+	void commit(uint8_t unit, uint32_t flags)
+	{
+		GL_CHECK(glActiveTexture(GL_TEXTURE0 + unit));
+		//GL_CHECK(glEnable(m_target));
+		GL_CHECK(glBindTexture(m_target, m_id));
+
+		set_sampler_state(flags);
+	}
+
+public:
+
+	GLuint				m_id;
+	GLenum				m_target;      // Always GL_TEXTURE_2D
+	uint32_t			m_width;
+	uint32_t			m_height;
+	PixelFormat::Enum	m_format;
+};
+
+//-----------------------------------------------------------------------------
+struct GPUProgram
+{
+	//-----------------------------------------------------------------------------
+	void create(const Shader& vertex, const Shader& pixel, uint32_t num_uniforms, Uniform* uniforms)
+	{
+		m_id = GL_CHECK(glCreateProgram());
+
+		GL_CHECK(glAttachShader(m_id, vertex.m_id));
+		GL_CHECK(glAttachShader(m_id, pixel.m_id));
+
+		GL_CHECK(glLinkProgram(m_id));
+		GLint success;
+		GL_CHECK(glGetProgramiv(m_id, GL_LINK_STATUS, &success));
+		if (!success)
+		{
+			GLchar info_log[2048];
+			GL_CHECK(glGetProgramInfoLog(m_id, 2048, NULL, info_log));
+			CE_ASSERT(false, "GPU program compilation failed:\n%s", info_log);
+		}
+
+		GL_CHECK(glValidateProgram(m_id));
+		GLint valid;
+		GL_CHECK(glGetProgramiv(m_id, GL_VALIDATE_STATUS, &valid));
+		if (!valid)
+		{
+			GLchar info_log[2048];
+			GL_CHECK(glGetProgramInfoLog(m_id, 2048, NULL, info_log));
+			CE_ASSERT(false, "GPU program validation failed:\n%s", info_log);
+		}
+
+		// Find active attribs/uniforms
+		GLint num_active_attribs;
+		GLint num_active_uniforms;
+		GL_CHECK(glGetProgramiv(m_id, GL_ACTIVE_ATTRIBUTES, &num_active_attribs));
+		GL_CHECK(glGetProgramiv(m_id, GL_ACTIVE_UNIFORMS, &num_active_uniforms));
+
+		// Log::d("Found %d active attribs", num_active_attribs);
+		// Log::d("Found %d active uniforms", num_active_uniforms);
+
+		// Find active attribs/uniforms max length
+		GLint max_attrib_length;
+		GLint max_uniform_length;
+		GL_CHECK(glGetProgramiv(m_id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attrib_length));
+		GL_CHECK(glGetProgramiv(m_id, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_length));
+
+		for (GLint attrib = 0; attrib < num_active_attribs; attrib++)
+		{
+			GLint attrib_size;
+			GLenum attrib_type;
+			char attrib_name[1024];
+			GL_CHECK(glGetActiveAttrib(m_id, attrib, max_attrib_length, NULL, &attrib_size, &attrib_type, attrib_name));
+
+			/* GLint attrib_location = */GL_CHECK(glGetAttribLocation(m_id, attrib_name));
+			// Log::d("Attrib %d: name = '%s' location = '%d'", attrib, attrib_name, attrib_location);
+		}
+
+		m_num_active_attribs = 0;
+		for (uint32_t attrib = 0; attrib < ShaderAttrib::COUNT; attrib++)
+		{
+			GLint loc = GL_CHECK(glGetAttribLocation(m_id, SHADER_ATTRIB_NAMES[attrib]));
+			if (loc != -1)
+			{
+				m_active_attribs[m_num_active_attribs] = (ShaderAttrib::Enum) attrib;
+				m_num_active_attribs++;
+				m_attrib_locations[attrib] = loc;
+			}
+		}
+
+		m_num_stock_uniforms = 0;
+		m_num_uniforms = 0;
+		for (GLint uniform = 0; uniform < num_active_uniforms; uniform++)
+		{
+			GLint uniform_size;
+			GLenum uniform_type;
+			char uniform_name[1024];
+			GL_CHECK(glGetActiveUniform(m_id, uniform, max_uniform_length, NULL, &uniform_size, &uniform_type, uniform_name));
+			GLint uniform_location = GL_CHECK(glGetUniformLocation(m_id, uniform_name));
+
+			ShaderUniform::Enum stock_uniform = name_to_stock_uniform(uniform_name);
+			if (stock_uniform != ShaderUniform::COUNT)
+			{
+				m_stock_uniforms[m_num_stock_uniforms] = stock_uniform;
+				m_stock_uniform_locations[m_num_stock_uniforms] = uniform_location;
+				m_num_stock_uniforms++;
+			}
+			else
+			{
+				for (uint32_t i = 0; i < num_uniforms; i++)
+				{
+					if (string::strcmp(uniforms[i].m_name, uniform_name) == 0)
+					{
+						m_uniforms[m_num_uniforms] = uniforms[i].m_type;
+						m_uniform_info[m_num_uniforms].loc = uniform_location;
+						m_uniform_info[m_num_uniforms].data = uniforms[i].m_data;
+						m_num_uniforms++;
+					}
+				}
+			}
+
+			// Log::d("Uniform %d: name = '%s' location = '%d' stock = %s", uniform, uniform_name, uniform_location,
+						// (stock_uniform != ShaderUniform::COUNT) ? "yes" : "no");
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	void destroy()
+	{
+		GL_CHECK(glUseProgram(0));
+		GL_CHECK(glDeleteProgram(m_id));
+	}
+
+	//-----------------------------------------------------------------------------
+	void bind_attributes(VertexFormat::Enum format, uint32_t start_vertex) const
+	{
+		// Bind all active attributes
+		for (uint8_t i = 0; i < m_num_active_attribs; i++)
+		{
+			ShaderAttrib::Enum attrib = m_active_attribs[i];
+			GLint loc = m_attrib_locations[attrib];
+
+			const VertexFormatInfo& info = Vertex::info(format);
+
+			if (loc != -1 && info.has_attrib(attrib))
+			{
+				GL_CHECK(glEnableVertexAttribArray(loc));
+				uint32_t base_vertex = start_vertex * info.attrib_stride(attrib) + info.attrib_offset(attrib);
+				GL_CHECK(glVertexAttribPointer(loc, info.num_components(attrib), GL_FLOAT, GL_FALSE, info.attrib_stride(attrib),
+										(GLvoid*)(uintptr_t) base_vertex));
+			}
+		}
+	}
+
+	//-----------------------------------------------------------------------------
+	void commit() const
+	{
+		for (uint8_t i = 0; i < m_num_uniforms; i++)
+		{
+			const UniformType::Enum type = m_uniforms[i];
+			const GLint loc = m_uniform_info[i].loc;
+			const void* data = m_uniform_info[i].data;
+
+			switch (type)
+			{
+				case UniformType::INTEGER_1:   GL_CHECK(glUniform1iv(loc, 1, (const GLint*)data)); break;
+				case UniformType::INTEGER_2:   GL_CHECK(glUniform2iv(loc, 2, (const GLint*)data)); break;
+				case UniformType::INTEGER_3:   GL_CHECK(glUniform3iv(loc, 3, (const GLint*)data)); break;				
+				case UniformType::INTEGER_4:   GL_CHECK(glUniform4iv(loc, 4, (const GLint*)data)); break;
+				case UniformType::FLOAT_1:     GL_CHECK(glUniform1fv(loc, 1, (const GLfloat*)data)); break;
+				case UniformType::FLOAT_2:     GL_CHECK(glUniform2fv(loc, 2, (const GLfloat*)data)); break;
+				case UniformType::FLOAT_3:     GL_CHECK(glUniform3fv(loc, 3, (const GLfloat*)data)); break;
+				case UniformType::FLOAT_4:     GL_CHECK(glUniform4fv(loc, 4, (const GLfloat*)data)); break;
+				case UniformType::FLOAT_3x3:   GL_CHECK(glUniformMatrix3fv(loc, 9, GL_FALSE, (const GLfloat*)data)); break;
+				case UniformType::FLOAT_4x4:   GL_CHECK(glUniformMatrix4fv(loc, 16, GL_FALSE, (const GLfloat*)data)); break;
+				default: CE_FATAL("Oops, unknown uniform type"); break;
+			}
+		}
+	}
+
+public:
+
+	GLuint				m_id;
+
+	uint8_t				m_num_active_attribs;
+	ShaderAttrib::Enum	m_active_attribs[ShaderAttrib::COUNT];
+	GLint				m_attrib_locations[ShaderAttrib::COUNT];
+
+	uint8_t				m_num_stock_uniforms;
+	ShaderUniform::Enum	m_stock_uniforms[ShaderUniform::COUNT];
+	GLint				m_stock_uniform_locations[ShaderUniform::COUNT];
+
+	struct LocAndData
+	{
+		GLint loc;
+		void* data;
+	};
+
+	uint8_t				m_num_uniforms;
+	UniformType::Enum	m_uniforms[16];
+	LocAndData			m_uniform_info[16];
+};
+
+//-----------------------------------------------------------------------------
+struct RenderTarget
+{
+	void create(uint16_t /*width*/, uint16_t /*height*/, RenderTargetFormat /*format*/)
+	{
+		// // Create and bind FBO
+		// GL_CHECK(glGenFramebuffersEXT(1, &m_gl_fbo));
+		// GL_CHECK(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_gl_fbo));
+
+		// GLuint renderedTexture;
+		// glGenTextures(1, &renderedTexture);
+		 
+		// // "Bind" the newly created texture : all future texture functions will modify this texture
+		// glBindTexture(GL_TEXTURE_2D, renderedTexture);
+		 
+		// // Give an empty image to OpenGL ( the last "0" )
+		// glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, 1024, 768, 0,GL_RGB, GL_UNSIGNED_BYTE, 0);
+		 
+		// // Poor filtering. Needed !
+		// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+		// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+
+		// // Create color/depth attachments
+		// switch (format)
+		// {
+		// 	case RTF_RGBA_8:
+		// 	case RTF_D24:
+		// 	{
+		// 		if (format == RTF_RGBA_8)
+		// 		{
+		// 			GL_CHECK(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
+  //                      GL_COLOR_ATTACHMENT0_EXT,
+  //                      GL_TEXTURE_2D,
+  //                      renderedTexture,
+  //                      0));
+		// 			break;
+		// 		}
+		// 		else if (format == RTF_D24)
+		// 		{
+		// 			GL_CHECK(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height));
+		// 			GL_CHECK(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_gl_rbo));
+		// 		}
+
+		// 		break;
+		// 	}
+		// 	default:
+		// 	{
+		// 		CE_ASSERT(false, "Oops, render target format not supported!");
+		// 		break;
+		// 	}
+		// }
+
+		// GLenum status = glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT);
+		// CE_ASSERT(status == GL_FRAMEBUFFER_COMPLETE_EXT, "Oops, framebuffer incomplete!");
+
+		// GL_CHECK(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
+
+		// m_width = width;
+		// m_height = height;
+		// m_format = format;
+	}
+
+	void destroy()
+	{
+		// GL_CHECK(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
+		// GL_CHECK(glDeleteFramebuffersEXT(1, &m_gl_fbo));
+
+		// GL_CHECK(glDeleteRenderbuffersEXT(1, &m_gl_rbo));
+	}
+
+	uint16_t m_width;
+	uint16_t m_height;
+	RenderTargetFormat m_format;
+	GLuint m_gl_fbo;
+	GLuint m_gl_rbo;
+};
+
 /// OpenGL renderer
 class RendererImplementation
 {

+ 0 - 570
engine/renderers/backend/gl/GLRenderer.h

@@ -1,570 +0,0 @@
-/*
-Copyright (c) 2013 Daniele Bartolini, Michele Rossi
-Copyright (c) 2012 Daniele Bartolini, Simone Boscaratto
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-#pragma once
-
-#include "Config.h"
-
-#if defined(LINUX) || defined(WINDOWS)
-	#include <GL/glew.h>
-#elif defined(ANDROID)
-	#include <GLES2/gl2.h>
-#else
-	#error "Oops, wrong platform"
-#endif
-
-#include "Types.h"
-#include "Renderer.h"
-#include "Resource.h"
-#include "GLContext.h"
-#include "VertexFormat.h"
-#include "Allocator.h"
-
-namespace crown
-{
-
-//-----------------------------------------------------------------------------
-struct GLTextureFormatInfo
-{
-	GLenum internal_format;
-	GLenum format;
-};
-
-extern const GLenum TEXTURE_MIN_FILTER_TABLE[];
-extern const GLenum TEXTURE_MAG_FILTER_TABLE[];
-extern const GLenum TEXTURE_WRAP_TABLE[];
-extern const GLTextureFormatInfo TEXTURE_FORMAT_TABLE[PixelFormat::COUNT];
-extern const char* const SHADER_ATTRIB_NAMES[ShaderAttrib::COUNT];
-extern const char* const SHADER_UNIFORM_NAMES[ShaderUniform::COUNT];
-extern const size_t UNIFORM_SIZE_TABLE[UniformType::END];
-extern ShaderUniform::Enum name_to_stock_uniform(const char* uniform);
-
-//-----------------------------------------------------------------------------
-static const char* gl_error_to_string(GLenum error)
-{
-	switch (error)
-	{
-		case GL_INVALID_ENUM: return "GL_INVALID_ENUM";
-		case GL_INVALID_VALUE: return "GL_INVALID_VALUE";
-		case GL_INVALID_OPERATION: return "GL_INVALID_OPERATION";
-		case GL_OUT_OF_MEMORY: return "GL_OUT_OF_MEMORY";
-		default: return "UNKNOWN_GL_ERROR";
-	}
-}
-
-//-----------------------------------------------------------------------------
-#if defined(CROWN_DEBUG) || defined(CROWN_DEVELOPMENT)
-	#define GL_CHECK(function)\
-		function;\
-		do { GLenum error; CE_ASSERT((error = glGetError()) == GL_NO_ERROR,\
-				"OpenGL error: %s", gl_error_to_string(error)); } while (0)
-#else
-	#define GL_CHECK(function)\
-		function;
-#endif
-
-//-----------------------------------------------------------------------------
-struct VertexBuffer
-{
-	//-----------------------------------------------------------------------------
-	void create(size_t size, const void* data, VertexFormat::Enum format)
-	{
-		GL_CHECK(glGenBuffers(1, &m_id));
-		CE_ASSERT(m_id != 0, "Failed to create buffer");
-		GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, m_id));
-		GL_CHECK(glBufferData(GL_ARRAY_BUFFER, size, data, (data == NULL) ? GL_STREAM_DRAW : GL_STATIC_DRAW));
-		GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
-
-		m_size = size;
-		m_format = format;
-	}
-
-	//-----------------------------------------------------------------------------
-	void update(size_t offset, size_t size, const void* data)
-	{
-		GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, m_id));
-		GL_CHECK(glBufferSubData(GL_ARRAY_BUFFER, offset, size, data));
-		GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
-	}
-
-	//-----------------------------------------------------------------------------
-	void destroy()
-	{
-		GL_CHECK(glBindBuffer(GL_ARRAY_BUFFER, 0));
-		GL_CHECK(glDeleteBuffers(1, &m_id));
-	}
-
-public:
-
-	GLuint m_id;
-	size_t m_size;
-	VertexFormat::Enum m_format;
-};
-
-//-----------------------------------------------------------------------------
-struct IndexBuffer
-{
-	//-----------------------------------------------------------------------------
-	void create(size_t size, const void* data)
-	{
-		GL_CHECK(glGenBuffers(1, &m_id));
-		CE_ASSERT(m_id != 0, "Failed to create buffer");
-		GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_id));
-		GL_CHECK(glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, (data == NULL) ? GL_STREAM_DRAW : GL_STATIC_DRAW));
-		GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
-
-		m_size = size;
-	}
-
-	//-----------------------------------------------------------------------------
-	void update(size_t offset, size_t size, const void* data)
-	{
-		GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_id));
-		GL_CHECK(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, offset, size, data));
-		GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
-	}
-
-	//-----------------------------------------------------------------------------
-	void destroy()
-	{
-		GL_CHECK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
-		GL_CHECK(glDeleteBuffers(1, &m_id));
-	}
-
-public:
-
-	GLuint		m_id;
-	uint32_t	m_size;
-};
-
-//-----------------------------------------------------------------------------
-struct Uniform
-{
-	Uniform()
-	{
-		string::strncpy(m_name, "", CE_MAX_UNIFORM_NAME_LENGTH);
-	}
-
-	void create(const char* name, UniformType::Enum type, uint8_t num)
-	{
-		string::strncpy(m_name, name, CE_MAX_UNIFORM_NAME_LENGTH);
-		m_type = type;
-		m_num = num;
-
-		size_t size = UNIFORM_SIZE_TABLE[type] * num;
-		m_data = default_allocator().allocate(size);
-		memset(m_data, 0, size);
-
-		// Log::d("Uniform created, name = %s, type = %d, num = %d, size = %ld", m_name, type, num, size);
-	}
-
-	void update(size_t size, const void* data)
-	{
-		// Log::d("Uniform updated, new size = %ld, new ptr = %d", size, *((int32_t*)data));
-		memcpy(m_data, data, size);
-	}
-
-	void destroy()
-	{
-		default_allocator().deallocate(m_data);
-	}
-
-public:
-
-	char m_name[CE_MAX_UNIFORM_NAME_LENGTH];
-	UniformType::Enum m_type;
-	uint8_t m_num;
-	void* m_data;
-};
-
-//-----------------------------------------------------------------------------
-struct Shader
-{
-	//-----------------------------------------------------------------------------
-	void create(ShaderType::Enum type, const char* text)
-	{
-		m_id = GL_CHECK(glCreateShader(type == ShaderType::VERTEX ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER));
-
-		GL_CHECK(glShaderSource(m_id, 1, &text, NULL));
-		GL_CHECK(glCompileShader(m_id));
-
-		GLint success;
-		GL_CHECK(glGetShaderiv(m_id, GL_COMPILE_STATUS, &success));
-
-		if (!success)
-		{
-			GLchar info_log[2048];
-			GL_CHECK(glGetShaderInfoLog(m_id, 2048, NULL, info_log));
-			CE_ASSERT(false, "Shader compilation failed\n\n%s", info_log);
-		}
-	}
-
-	//-----------------------------------------------------------------------------
-	void destroy()
-	{
-		GL_CHECK(glDeleteShader(m_id));
-	}
-
-public:
-
-	GLuint m_id;
-};
-
-//-----------------------------------------------------------------------------
-struct Texture
-{
-	//-----------------------------------------------------------------------------
-	void create(uint32_t width, uint32_t height, PixelFormat::Enum format, const void* data)
-	{
-		GL_CHECK(glGenTextures(1, &m_id));
-		GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_id));
-
-		#if defined(LINUX) || defined(WINDOWS)
-			GL_CHECK(glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE));
-		#endif
-
-		GLenum internal_fmt = TEXTURE_FORMAT_TABLE[format].internal_format;
-		GLenum fmt = TEXTURE_FORMAT_TABLE[format].format;
-
-		GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, internal_fmt, width, height, 0,
-					 			fmt, GL_UNSIGNED_BYTE, data));
-		GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
-
-		m_target = GL_TEXTURE_2D;
-		m_format = format;
-	}
-
-	//-----------------------------------------------------------------------------
-	void update(uint32_t x, uint32_t y, uint32_t width, uint32_t height, const void* data)
-	{
-		GL_CHECK(glBindTexture(GL_TEXTURE_2D, m_id));
-		GL_CHECK(glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA,
-									GL_UNSIGNED_BYTE, data));
-		GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
-	}
-
-	//-----------------------------------------------------------------------------
-	void set_sampler_state(uint32_t flags)
-	{
-		const GLenum min_filter = TEXTURE_MIN_FILTER_TABLE[(flags & TEXTURE_FILTER_MASK) >> TEXTURE_FILTER_SHIFT];
-		const GLenum mag_filter = TEXTURE_MAG_FILTER_TABLE[(flags & TEXTURE_FILTER_MASK) >> TEXTURE_FILTER_SHIFT];
-		const GLenum wrap_s = TEXTURE_WRAP_TABLE[(flags & TEXTURE_WRAP_U_MASK) >> TEXTURE_WRAP_U_SHIFT];
-		const GLenum wrap_t = TEXTURE_WRAP_TABLE[(flags & TEXTURE_WRAP_V_MASK) >> TEXTURE_WRAP_V_SHIFT];
-
-		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_WRAP_S, wrap_s));
-		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_WRAP_T, wrap_t));
-
-		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_MIN_FILTER, min_filter));
-		GL_CHECK(glTexParameteri(m_target, GL_TEXTURE_MAG_FILTER, mag_filter));
-	}
-
-	//-----------------------------------------------------------------------------
-	void destroy()
-	{
-		GL_CHECK(glBindTexture(m_target, 0));
-		GL_CHECK(glDeleteTextures(1, &m_id));
-	}
-
-	//-----------------------------------------------------------------------------
-	void commit(uint8_t unit, uint32_t flags)
-	{
-		GL_CHECK(glActiveTexture(GL_TEXTURE0 + unit));
-		//GL_CHECK(glEnable(m_target));
-		GL_CHECK(glBindTexture(m_target, m_id));
-
-		set_sampler_state(flags);
-	}
-
-public:
-
-	GLuint				m_id;
-	GLenum				m_target;      // Always GL_TEXTURE_2D
-	uint32_t			m_width;
-	uint32_t			m_height;
-	PixelFormat::Enum	m_format;
-};
-
-//-----------------------------------------------------------------------------
-struct GPUProgram
-{
-	//-----------------------------------------------------------------------------
-	void create(const Shader& vertex, const Shader& pixel, uint32_t num_uniforms, Uniform* uniforms)
-	{
-		m_id = GL_CHECK(glCreateProgram());
-
-		GL_CHECK(glAttachShader(m_id, vertex.m_id));
-		GL_CHECK(glAttachShader(m_id, pixel.m_id));
-
-		GL_CHECK(glLinkProgram(m_id));
-		GLint success;
-		GL_CHECK(glGetProgramiv(m_id, GL_LINK_STATUS, &success));
-		if (!success)
-		{
-			GLchar info_log[2048];
-			GL_CHECK(glGetProgramInfoLog(m_id, 2048, NULL, info_log));
-			CE_ASSERT(false, "GPU program compilation failed:\n%s", info_log);
-		}
-
-		GL_CHECK(glValidateProgram(m_id));
-		GLint valid;
-		GL_CHECK(glGetProgramiv(m_id, GL_VALIDATE_STATUS, &valid));
-		if (!valid)
-		{
-			GLchar info_log[2048];
-			GL_CHECK(glGetProgramInfoLog(m_id, 2048, NULL, info_log));
-			CE_ASSERT(false, "GPU program validation failed:\n%s", info_log);
-		}
-
-		// Find active attribs/uniforms
-		GLint num_active_attribs;
-		GLint num_active_uniforms;
-		GL_CHECK(glGetProgramiv(m_id, GL_ACTIVE_ATTRIBUTES, &num_active_attribs));
-		GL_CHECK(glGetProgramiv(m_id, GL_ACTIVE_UNIFORMS, &num_active_uniforms));
-
-		// Log::d("Found %d active attribs", num_active_attribs);
-		// Log::d("Found %d active uniforms", num_active_uniforms);
-
-		// Find active attribs/uniforms max length
-		GLint max_attrib_length;
-		GLint max_uniform_length;
-		GL_CHECK(glGetProgramiv(m_id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attrib_length));
-		GL_CHECK(glGetProgramiv(m_id, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_length));
-
-		for (GLint attrib = 0; attrib < num_active_attribs; attrib++)
-		{
-			GLint attrib_size;
-			GLenum attrib_type;
-			char attrib_name[1024];
-			GL_CHECK(glGetActiveAttrib(m_id, attrib, max_attrib_length, NULL, &attrib_size, &attrib_type, attrib_name));
-
-			/* GLint attrib_location = */GL_CHECK(glGetAttribLocation(m_id, attrib_name));
-			// Log::d("Attrib %d: name = '%s' location = '%d'", attrib, attrib_name, attrib_location);
-		}
-
-		m_num_active_attribs = 0;
-		for (uint32_t attrib = 0; attrib < ShaderAttrib::COUNT; attrib++)
-		{
-			GLint loc = GL_CHECK(glGetAttribLocation(m_id, SHADER_ATTRIB_NAMES[attrib]));
-			if (loc != -1)
-			{
-				m_active_attribs[m_num_active_attribs] = (ShaderAttrib::Enum) attrib;
-				m_num_active_attribs++;
-				m_attrib_locations[attrib] = loc;
-			}
-		}
-
-		m_num_stock_uniforms = 0;
-		m_num_uniforms = 0;
-		for (GLint uniform = 0; uniform < num_active_uniforms; uniform++)
-		{
-			GLint uniform_size;
-			GLenum uniform_type;
-			char uniform_name[1024];
-			GL_CHECK(glGetActiveUniform(m_id, uniform, max_uniform_length, NULL, &uniform_size, &uniform_type, uniform_name));
-			GLint uniform_location = GL_CHECK(glGetUniformLocation(m_id, uniform_name));
-
-			ShaderUniform::Enum stock_uniform = name_to_stock_uniform(uniform_name);
-			if (stock_uniform != ShaderUniform::COUNT)
-			{
-				m_stock_uniforms[m_num_stock_uniforms] = stock_uniform;
-				m_stock_uniform_locations[m_num_stock_uniforms] = uniform_location;
-				m_num_stock_uniforms++;
-			}
-			else
-			{
-				for (uint32_t i = 0; i < num_uniforms; i++)
-				{
-					if (string::strcmp(uniforms[i].m_name, uniform_name) == 0)
-					{
-						m_uniforms[m_num_uniforms] = uniforms[i].m_type;
-						m_uniform_info[m_num_uniforms].loc = uniform_location;
-						m_uniform_info[m_num_uniforms].data = uniforms[i].m_data;
-						m_num_uniforms++;
-					}
-				}
-			}
-
-			// Log::d("Uniform %d: name = '%s' location = '%d' stock = %s", uniform, uniform_name, uniform_location,
-						// (stock_uniform != ShaderUniform::COUNT) ? "yes" : "no");
-		}
-	}
-
-	//-----------------------------------------------------------------------------
-	void destroy()
-	{
-		GL_CHECK(glUseProgram(0));
-		GL_CHECK(glDeleteProgram(m_id));
-	}
-
-	//-----------------------------------------------------------------------------
-	void bind_attributes(VertexFormat::Enum format, uint32_t start_vertex) const
-	{
-		// Bind all active attributes
-		for (uint8_t i = 0; i < m_num_active_attribs; i++)
-		{
-			ShaderAttrib::Enum attrib = m_active_attribs[i];
-			GLint loc = m_attrib_locations[attrib];
-
-			const VertexFormatInfo& info = Vertex::info(format);
-
-			if (loc != -1 && info.has_attrib(attrib))
-			{
-				GL_CHECK(glEnableVertexAttribArray(loc));
-				uint32_t base_vertex = start_vertex * info.attrib_stride(attrib) + info.attrib_offset(attrib);
-				GL_CHECK(glVertexAttribPointer(loc, info.num_components(attrib), GL_FLOAT, GL_FALSE, info.attrib_stride(attrib),
-										(GLvoid*)(uintptr_t) base_vertex));
-			}
-		}
-	}
-
-	//-----------------------------------------------------------------------------
-	void commit() const
-	{
-		for (uint8_t i = 0; i < m_num_uniforms; i++)
-		{
-			const UniformType::Enum type = m_uniforms[i];
-			const GLint loc = m_uniform_info[i].loc;
-			const void* data = m_uniform_info[i].data;
-
-			switch (type)
-			{
-				case UniformType::INTEGER_1:   GL_CHECK(glUniform1iv(loc, 1, (const GLint*)data)); break;
-				case UniformType::INTEGER_2:   GL_CHECK(glUniform2iv(loc, 2, (const GLint*)data)); break;
-				case UniformType::INTEGER_3:   GL_CHECK(glUniform3iv(loc, 3, (const GLint*)data)); break;				
-				case UniformType::INTEGER_4:   GL_CHECK(glUniform4iv(loc, 4, (const GLint*)data)); break;
-				case UniformType::FLOAT_1:     GL_CHECK(glUniform1fv(loc, 1, (const GLfloat*)data)); break;
-				case UniformType::FLOAT_2:     GL_CHECK(glUniform2fv(loc, 2, (const GLfloat*)data)); break;
-				case UniformType::FLOAT_3:     GL_CHECK(glUniform3fv(loc, 3, (const GLfloat*)data)); break;
-				case UniformType::FLOAT_4:     GL_CHECK(glUniform4fv(loc, 4, (const GLfloat*)data)); break;
-				case UniformType::FLOAT_3x3:   GL_CHECK(glUniformMatrix3fv(loc, 9, GL_FALSE, (const GLfloat*)data)); break;
-				case UniformType::FLOAT_4x4:   GL_CHECK(glUniformMatrix4fv(loc, 16, GL_FALSE, (const GLfloat*)data)); break;
-				default: CE_FATAL("Oops, unknown uniform type"); break;
-			}
-		}
-	}
-
-public:
-
-	GLuint				m_id;
-
-	uint8_t				m_num_active_attribs;
-	ShaderAttrib::Enum	m_active_attribs[ShaderAttrib::COUNT];
-	GLint				m_attrib_locations[ShaderAttrib::COUNT];
-
-	uint8_t				m_num_stock_uniforms;
-	ShaderUniform::Enum	m_stock_uniforms[ShaderUniform::COUNT];
-	GLint				m_stock_uniform_locations[ShaderUniform::COUNT];
-
-	struct LocAndData
-	{
-		GLint loc;
-		void* data;
-	};
-
-	uint8_t				m_num_uniforms;
-	UniformType::Enum	m_uniforms[16];
-	LocAndData			m_uniform_info[16];
-};
-
-//-----------------------------------------------------------------------------
-struct RenderTarget
-{
-	void create(uint16_t /*width*/, uint16_t /*height*/, RenderTargetFormat /*format*/)
-	{
-		// // Create and bind FBO
-		// GL_CHECK(glGenFramebuffersEXT(1, &m_gl_fbo));
-		// GL_CHECK(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_gl_fbo));
-
-		// GLuint renderedTexture;
-		// glGenTextures(1, &renderedTexture);
-		 
-		// // "Bind" the newly created texture : all future texture functions will modify this texture
-		// glBindTexture(GL_TEXTURE_2D, renderedTexture);
-		 
-		// // Give an empty image to OpenGL ( the last "0" )
-		// glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, 1024, 768, 0,GL_RGB, GL_UNSIGNED_BYTE, 0);
-		 
-		// // Poor filtering. Needed !
-		// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-		// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-
-
-		// // Create color/depth attachments
-		// switch (format)
-		// {
-		// 	case RTF_RGBA_8:
-		// 	case RTF_D24:
-		// 	{
-		// 		if (format == RTF_RGBA_8)
-		// 		{
-		// 			GL_CHECK(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
-  //                      GL_COLOR_ATTACHMENT0_EXT,
-  //                      GL_TEXTURE_2D,
-  //                      renderedTexture,
-  //                      0));
-		// 			break;
-		// 		}
-		// 		else if (format == RTF_D24)
-		// 		{
-		// 			GL_CHECK(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height));
-		// 			GL_CHECK(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_gl_rbo));
-		// 		}
-
-		// 		break;
-		// 	}
-		// 	default:
-		// 	{
-		// 		CE_ASSERT(false, "Oops, render target format not supported!");
-		// 		break;
-		// 	}
-		// }
-
-		// GLenum status = glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT);
-		// CE_ASSERT(status == GL_FRAMEBUFFER_COMPLETE_EXT, "Oops, framebuffer incomplete!");
-
-		// GL_CHECK(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
-
-		// m_width = width;
-		// m_height = height;
-		// m_format = format;
-	}
-
-	void destroy()
-	{
-		// GL_CHECK(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
-		// GL_CHECK(glDeleteFramebuffersEXT(1, &m_gl_fbo));
-
-		// GL_CHECK(glDeleteRenderbuffersEXT(1, &m_gl_rbo));
-	}
-
-	uint16_t m_width;
-	uint16_t m_height;
-	RenderTargetFormat m_format;
-	GLuint m_gl_fbo;
-	GLuint m_gl_rbo;
-};
-
-} // namespace crown