Commits

Alex Szpakowski  committed 8468f17

A shader is now always active on systems which support shaders, no matter what; all systems with shader support now always use explicit generic vertex attributes (instead of glEnableClientState etc); GLEW now uses SDL's GetProcAddress function by default, instead of various per-OS functions.

  • Participants
  • Parent commits 153abe5
  • Branches GLES2-compatibility

Comments (0)

Files changed (13)

File src/common/Matrix.cpp

 	return false;
 }
 
-
 //                 | e0 e4 e8  e12 |
 //                 | e1 e5 e9  e13 |
 //                 | e2 e6 e10 e14 |
 	memcpy((void *)this->e, (void *)t.e, sizeof(float)*16);
 }
 
-void Matrix::setElements(float e[16])
-{
-	memcpy(this->e, e, sizeof(float) * 16);
-}
-
 const float *Matrix::getElements() const
 {
 	return e;

File src/common/Matrix.h

 
 	/**
 	 * Determines whether two matrices have equal components.
+	 * Floatiing-point inaccuracies are not accounted for!
 	 * @param m The Matrix to compare to this Matrix.
 	 **/
 	bool operator == (const Matrix &m) const;
 	void operator *= (const Matrix &m);
 
 	/**
-	 * Sets the array elements of this Matrix directly.
-	 * @param e The new array elements to use.
-	 **/
-	void setElements(float e[16]);
-
-	/**
 	 * Gets a pointer to the 16 array elements.
 	 * @return The array elements.
 	 **/
 	 **/
 	void transform(vertex *dst, const vertex *src, int size) const;
 
+	/**
+	 * Creates an orthographic projection Matrix with near and far clipping
+	 * planes at -1.0 and 1.0, respectively.
+	 * Similar to http://www.opengl.org/sdk/docs/man2/xhtml/glOrtho.xml
+	 * @param left, right, bottom, top Clipping planes.
+	 **/
 	static Matrix ortho(float left, float right, float bottom, float top);
 
 private:

File src/libraries/glew/eglew.h

 /* TODO insert license */
 
 /* Includes */
-#include <GL/glew.h>
+#include "glew.h"
 
 /* Macros used in EGL function prototype declarations.
  *

File src/libraries/glew/glew.c

 */
 
 #include "glew.h"
-#if defined(GLEW_USE_LIB_ES)
+#if defined(GLEW_USE_SDL)
+#  include <SDL_video.h>
+#elif defined(GLEW_USE_LIB_ES)
 #  if defined(GLEW_INC_EGL)
 #    include "eglew.h"
 #  endif
 #  define EGLEW_CONTEXT_ARG_DEF_LIST void
 #endif /* GLEW_MX */
 
-#if defined(GLEW_USE_LIB_ES)
+#if defined(GLEW_USE_SDL)
+
+/* using SDL_GL_GetProcAddress */
+
+#elif defined(GLEW_USE_LIB_ES)
 
 #ifdef linux
 
 
 void* NSGLGetProcAddress (const GLubyte *name)
 {
-#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR)
-	// look in ALL the places
-	return dlsym(RTLD_DEFAULT, (const char*)name);
+#if defined(TARGET_OS_IPHONE) && defined(TARGET_IPHONE_SIMULATOR)
+	if (TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR)
+	{
+		// look in ALL the places
+		return dlsym(RTLD_DEFAULT, (const char*)name);
+	}
+	else
+#endif
+	{
+	  static void* image = NULL;
+	  if (NULL == image) 
+	  {
+		image = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_LAZY);
+	  }
+	  if( !image ) return NULL;
+	  void* addr = dlsym(image, (const char*)name);
+	  if( addr ) return addr;
+#ifdef GLEW_APPLE_GLX
+	  return dlGetProcAddress( name ); // try next for glx symbols
 #else
-  static void* image = NULL;
-  if (NULL == image) 
-  {
-    image = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_LAZY);
-  }
-  if( !image ) return NULL;
-  void* addr = dlsym(image, (const char*)name);
-  if( addr ) return addr;
-#ifdef GLEW_APPLE_GLX
-  return dlGetProcAddress( name ); // try next for glx symbols
-#else
-  return NULL;
+	  return NULL;
 #endif // GLEW_APPLE_GLX
-#endif // TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
+	}
 }
 #else
 
 /*
  * Define glewGetProcAddress.
  */
-#if defined(GLEW_USE_LIB_ES)
+#if defined(GLEW_USE_SDL)
+#  define glewGetProcAddress(name) SDL_GL_GetProcAddress(name)
+#elif defined(GLEW_USE_LIB_ES)
 #  define glewGetProcAddress(name) esGetProcAddress(name)
 #elif defined(_WIN32)
 #  define glewGetProcAddress(name) wglGetProcAddress((LPCSTR)name)

File src/libraries/glew/glew.h

 
 #define GLEW_NO_GLU
 #define GLEW_STATIC
+#define GLEW_USE_SDL
 
 
 #if defined(GLEW_USE_LIB_ES11) || defined(GLEW_USE_LIB_ES20)

File src/libraries/glew/glxew.h

 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/Xmd.h>
-#include <GL/glew.h>
+#include "glew.h"
 
 #ifdef __cplusplus
 extern "C" {

File src/modules/graphics/opengl/Context.cpp

 		glUnmapBuffer = glUnmapBufferARB;
 	}
 
-	// Similar deal with glActiveTexture
-	if (!(GLEW_ES_VERSION_2_0 || GLEW_VERSION_1_3) && GLEW_ARB_multitexture)
-		glActiveTexture = glActiveTextureARB;
-
 	extensionsInitialized = true;
 }
 
 {
 	state.textureUnits.clear();
 
-	// initialize multiple texture unit support, if available
-	if (GLEW_ES_VERSION_2_0 || GLEW_VERSION_1_3 || GLEW_ARB_multitexture)
+	// Initialize multiple texture unit support, if available
+	if (shadersSupported)
 	{
 		GLint maxtextureunits;
-		glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxtextureunits);
-
-		// shaders/GL2.0 added "Texture Image Units." Total max texture units is the greater of the two
-		if (GLEW_ES_VERSION_2_0 || GLEW_VERSION_2_0 || GLEW_ARB_vertex_shader)
-		{
-			GLint maxtextureimageunits;
-			glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtextureimageunits);
-			maxtextureunits = std::max(maxtextureunits, maxtextureimageunits);
-		}
+		glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtextureunits);
 
 		state.textureUnits.resize(maxtextureunits, 0);
 
 		GLenum curgltextureunit;
-		glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint *)&curgltextureunit);
+		glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint *) &curgltextureunit);
 
 		state.curTextureUnit = curgltextureunit - GL_TEXTURE0;
 
-		// retrieve currently bound textures for each texture unit
+		// Retrieve currently bound textures for each texture unit
 		for (size_t i = 0; i < state.textureUnits.size(); ++i)
 		{
 			glActiveTexture(GL_TEXTURE0 + i);
 	}
 	else
 	{
-		// multitexturing not supported, so we only have 1 texture unit
+		// Multitexturing not supported, so we only have 1 texture unit
 		state.textureUnits.resize(1, 0);
 		state.curTextureUnit = 0;
 
 	}
 }
 
+void Context::createDefaultTexture()
+{
+	// Set the 'default' texture (id 0) as a repeating white pixel.
+	// Otherwise, texture2D inside a shader would return black when drawing graphics primitives,
+	// which would require the creation of different default shaders for untextured primitives vs images.
+
+	GLuint curtexture = state.textureUnits[state.curTextureUnit];
+	bindTexture(0);
+
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+	GLubyte pixel = 255;
+	glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &pixel);
+
+	bindTexture(curtexture);
+}
+
 void Context::initMatrixState()
 {
-	// Set up matrix stacks with a sane amount of preallocated space
+	// Set up transformation matrix stacks with plenty of pre-allocated space
 	modelViewStack.clear();
 	modelViewStack.reserve(64);
 	modelViewStack.push_back(Matrix());
 
 	if (!GLEW_ES_VERSION_2_0)
 	{
-		GLfloat e[16];
-
-		glGetFloatv(GL_MODELVIEW_MATRIX, e);
-		state.modelViewMatrix.setElements(e);
-
-		glGetFloatv(GL_PROJECTION_MATRIX, e);
-		state.projectionMatrix.setElements(e);
+		glMatrixMode(GL_PROJECTION);
+		glLoadIdentity();
 
 		glMatrixMode(GL_MODELVIEW);
+		glLoadIdentity();
 	}
 }
 
 	// set vertex attribute index map
 	state.vertexAttribMap.clear();
 
-	if (GLEW_ES_VERSION_2_0)
+	if (shadersSupported)
 	{
-		// use explicit generic attribute locations in OpenGL ES 2
+		// use explicit generic attribute index locations with shaders
 		state.vertexAttribMap[ATTRIB_VERTEX] = 0;
 		state.vertexAttribMap[ATTRIB_COLOR] = 1;
 		state.vertexAttribMap[ATTRIB_TEXCOORD] = 2;
 	}
 	else
 	{
-		// and use the old glEnableClientState etc. in regular GL
+		// and use the old glEnableClientState etc. otherwise
 		state.vertexAttribMap[ATTRIB_VERTEX] = GL_VERTEX_ARRAY;
 		state.vertexAttribMap[ATTRIB_COLOR] = GL_COLOR_ARRAY;
 		state.vertexAttribMap[ATTRIB_TEXCOORD] = GL_TEXTURE_COORD_ARRAY;
 	// making sure all vertex attributes are disabled is much easier than querying them...
 	state.enabledVertexAttribArrays.clear();
 	useVertexAttribArrays(ATTRIB_NONE);
-
 }
 
 void Context::initState()
 {
+	shadersSupported = Shader::isSupported();
+
 	initCapabilityState();
 	initTextureState();
 	initMatrixState();
 		glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint *) &state.blend.function);
 	else
 		state.blend.function = GL_FUNC_ADD;
-	
+
 
 	// get the current color
 	GLfloat color[4];
 
 	// get the maximum point size
 	GLfloat pointsizerange[2];
+
 	if (GLEW_ES_VERSION_2_0 || GLEW_VERSION_1_2)
 		glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointsizerange);
 	else
 		glGetFloatv(GL_POINT_SIZE_RANGE, pointsizerange);
+
 	state.maxPointSize = pointsizerange[1];
 }
 
-void Context::createDefaultTexture()
-{
-	// Set the 'default' texture (id 0) as a repeating white pixel.
-	// Otherwise, texture2D inside a shader would return black when drawing graphics primitives,
-	// which would create the need to use different "passthrough" shaders for untextured primitives vs images.
-
-	GLuint curtexture = state.textureUnits[state.curTextureUnit];
-	bindTexture(0);
-
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-
-	GLubyte pixel = 255;
-	glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &pixel);
-
-	bindTexture(curtexture);
-}
-
 void Context::setupRender()
 {
 	const Matrix &projectionMatrix = projectionStack.back();
 
 void Context::setColor(const Color &color)
 {
-	if (isGenericVertexAttrib(ATTRIB_COLOR))
+	// The current color is a generic vertex attribute when using shaders
+	if (shadersSupported)
 		glVertexAttrib4Nub(state.vertexAttribMap[ATTRIB_COLOR], color.r, color.g, color.b, color.a);
 	else
 		glColor4ub(color.r, color.g, color.b, color.a);
 {
 	// GLES2 can only set the point size with gl_PointSize in shaders
 	if (!GLEW_ES_VERSION_2_0)
-		glPointSize((GLfloat) size);
+		glPointSize(size);
 
 	state.pointSize = size;
 }
 	return state.blend;
 }
 
-bool Context::isGenericVertexAttrib(unsigned int attrib) const
-{
-	return GLEW_ES_VERSION_2_0 || attrib > ATTRIB_TEXCOORD;
-}
-
 GLint Context::getVertexAttribID(unsigned int attrib) const
 {
 	std::map<unsigned int, GLenum>::const_iterator glattrib = state.vertexAttribMap.find(attrib);
 	if (glattrib < 0)
 		return;
 
-	if (isGenericVertexAttrib(attrib))
+	if (shadersSupported)
 	{
 		if (use)
 			glEnableVertexAttribArray(glattrib);
 
 void Context::vertexAttribPointer(Context::VertexAttribType attrib, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) const
 {
-	if (isGenericVertexAttrib(attrib))
+	if (shadersSupported)
 	{
 		// get the internal OpenGL representation for this attribute, if it exists
 		GLint glattrib = getVertexAttribID(attrib);
 
 	if (textureunit != state.curTextureUnit)
 	{
-		if (GLEW_ES_VERSION_2_0 || GLEW_VERSION_1_3 || GLEW_ARB_multitexture)
+		if (shadersSupported)
 			glActiveTexture(GL_TEXTURE0 + textureunit);
 		else
 			throw love::Exception("Multitexturing not supported.");

File src/modules/graphics/opengl/Context.h

 		GLenum destination;
 	};
 
-	// Matrix stacks used when rendering.
+	// Transformation matrix stacks used when rendering.
 	std::vector<Matrix> modelViewStack;
 	std::vector<Matrix> projectionStack;
 
 	const Viewport &getViewport() const;
 
 	/**
-	 * Returns true if the specified vertex attribute doesn't go through the
-	 * fixed-function pipeline.
-	 *
-	 * @param attrib See VertexAttribType.
-	 **/
-	bool isGenericVertexAttrib(unsigned int attrib) const;
-
-	/**
 	 * Gets the OpenGL representation of the specified vertex attribute.
 	 * Will be the attribute index for generic vertex attributes, or a
 	 * GL_*_ARRAY for fixed-function ones.
 		// The current blending state.
 		BlendState blend;
 
-		// The currently active matrices used when rendering.
+		// The currently active transformation matrices used when rendering.
 		Matrix modelViewMatrix;
 		Matrix projectionMatrix;
 
 
 	} state;
 
+	bool shadersSupported;
+
 	static bool extensionsInitialized;
 
 	// Pointer to the currently active context.

File src/modules/graphics/opengl/Shader.cpp

 Shader *Shader::currentShader = NULL;
 Shader *Shader::defaultShader = NULL;
 
-GLint Shader::maxTextureUnits = 0;
+size_t Shader::maxTextureUnits = 0;
 std::vector<int> Shader::textureCounters;
 
 Shader::Shader(const ShaderSources &sources)
 
 	GLint maxtexunits;
 	glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtexunits);
-	maxTextureUnits = std::max(maxtexunits - 1, 0);
+	maxTextureUnits = std::max(getContext()->getNumTextureUnits() - 1, 0);
 
 	// initialize global texture id counters if needed
-	if (textureCounters.size() < (size_t) maxTextureUnits)
+	if (textureCounters.size() < maxTextureUnits)
 		textureCounters.resize(maxTextureUnits, 0);
 
 	// set names of generic vertex attributes in the shader code
-	// only relevant when the deprecated built-in ones aren't used
 	vertexAttribNames[Context::ATTRIB_VERTEX] = "VertexPosition";
+	vertexAttribNames[Context::ATTRIB_COLOR] = "VertexColor";
 	vertexAttribNames[Context::ATTRIB_TEXCOORD] = "VertexTexCoord";
-	vertexAttribNames[Context::ATTRIB_COLOR] = "VertexColor";
 
 	// Make sure we have both vertex and fragment source codes
 	checkCodeCompleteness();
 	for (it = vertexAttribNames.begin(); it != vertexAttribNames.end(); ++it)
 	{
 		GLint glattrib = ctx->getVertexAttribID(it->first);
-		if (glattrib >= 0 && ctx->isGenericVertexAttrib(it->first))
+		if (glattrib >= 0)
 			glBindAttribLocation(program, glattrib, it->second.c_str());
 	}
 }
 	if (defaultShader != NULL)
 		defaultShader->attach();
 	else
+	{
 		glUseProgram(0);
-
-	currentShader = defaultShader;
+		currentShader = NULL;
+	}
 }
 
 void Shader::sendFloat(const std::string &name, int size, const GLfloat *vec, int count)

File src/modules/graphics/opengl/Shader.h

 	std::vector<GLuint> activeTextureUnits; // activeTextureUnits[textureunit-1] = textureid
 
 	// Max GPU texture units available for sent images
-	static GLint maxTextureUnits;
+	static size_t maxTextureUnits;
 
 	// Counts total number of textures bound to each texture unit in all shaders
 	static std::vector<int> textureCounters;

File src/modules/graphics/opengl/VertexBuffer.h

  * that can use the pattern below) can request a size and use it for the
  * drawElements call.
  *
- *  0----3
- *  | \  |
- *  |  \ |
- *  1----2
- *
  *  indices[i*6 + 0] = i*4 + 0;
  *  indices[i*6 + 1] = i*4 + 1;
  *  indices[i*6 + 2] = i*4 + 2;
  *  indices[i*6 + 4] = i*4 + 2;
  *  indices[i*6 + 5] = i*4 + 3;
  *
+ *  0----3
+ *  | \  |
+ *  |  \ |
+ *  1----2
+ *
  * There will always be a large enough VertexBuffer around until all
  * VertexIndex instances have been deleted.
  *

File src/scripts/graphics.lua

 #define number float
 #define Image sampler2D
 #define extern uniform
-#define Texel texture2D]]
+#define Texel texture2D
+#extension all: disable]]
 
 	local GLSL_UNIFORMS = [[
 #define ModelViewMatrix gl_ModelViewMatrix
 		HEADER = [[
 #define VERTEX
 
-#define VertexPosition gl_Vertex
-#define VertexTexCoord gl_MultiTexCoord0
-#define VertexColor gl_Color
+attribute vec4 VertexPosition;
+attribute vec4 VertexColor;
+attribute vec4 VertexTexCoord;
 
-#define VaryingTexCoord gl_TexCoord[0]
-#define VaryingColor gl_FrontColor]],
+varying vec4 VaryingColor;
+varying vec2 VaryingTexCoord;]],
 
 		FOOTER = [[
 void main() {
-	VaryingTexCoord = VertexTexCoord;
+	VaryingTexCoord = VertexTexCoord.st;
 	VaryingColor = VertexColor;
 	gl_Position = position(ModelViewProjectionMatrix, VertexPosition);
 }]],
 		HEADER = [[
 #define PIXEL
 
-#define VaryingTexCoord gl_TexCoord[0]
-#define VaryingColor gl_Color]],
+varying vec4 VaryingColor;
+varying vec2 VaryingTexCoord;]],
 
 		FOOTER = [[
 void main() {
 	// fix weird crashing issue in OSX when _tex0_ is unused within effect()
 	float dummy = texture2D(_tex0_, vec2(.5)).r;
-	gl_FragColor = effect(VaryingColor, _tex0_, VaryingTexCoord.st, gl_FragCoord.xy);
+	gl_FragColor = effect(VaryingColor, _tex0_, VaryingTexCoord, gl_FragCoord.xy);
 }]],
 	}
 
 		frag = [[
 vec4 effect(vec4 vcolor, Image texture, vec2 texcoord, vec2 pixcoord)
 {
-	vec4 texcolor = Texel(texture, texcoord);
-	return texcolor * vcolor;
+	return vcolor * Texel(texture, texcoord);
 }]],
 	}
 
 	function love.graphics.setMode(...)
 		local success = _setMode(...)
 
-		-- make sure we have a default shader
+		-- make sure we always have a default shader, if they're supported
 		if success then
 			if love.graphics.isSupported("shader") and not love.graphics.getDefaultShader() then
 				local defaultshader = love.graphics.newShader(defaultcode.vert, defaultcode.frag)

File src/scripts/graphics.lua.h

 	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x75, 0x6e, 0x69, 
 	0x66, 0x6f, 0x72, 0x6d, 0x0a,
 	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x20, 0x74, 0x65, 0x78, 0x74, 
-	0x75, 0x72, 0x65, 0x32, 0x44, 0x5d, 0x5d, 0x0a,
+	0x75, 0x72, 0x65, 0x32, 0x44, 0x0a,
+	0x23, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x61, 0x6c, 0x6c, 0x3a, 0x20, 0x64, 0x69, 
+	0x73, 0x61, 0x62, 0x6c, 0x65, 0x5d, 0x5d, 0x0a,
 	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x55, 0x4e, 0x49, 0x46, 0x4f, 0x52, 
 	0x4d, 0x53, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a,
 	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x4d, 
 	0x20, 0x7b, 0x0a,
 	0x09, 0x09, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a,
 	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x0a,
-	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x50, 0x6f, 0x73, 0x69, 
-	0x74, 0x69, 0x6f, 0x6e, 0x20, 0x67, 0x6c, 0x5f, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0a,
-	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x54, 0x65, 0x78, 0x43, 
-	0x6f, 0x6f, 0x72, 0x64, 0x20, 0x67, 0x6c, 0x5f, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x54, 0x65, 0x78, 0x43, 0x6f, 
-	0x6f, 0x72, 0x64, 0x30, 0x0a,
-	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 
-	0x72, 0x20, 0x67, 0x6c, 0x5f, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x0a,
-	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x78, 
-	0x43, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x67, 0x6c, 0x5f, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x5b, 
-	0x30, 0x5d, 0x0a,
-	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 
-	0x6f, 0x72, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x5d, 0x5d, 
-	0x2c, 0x0a,
+	0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x65, 0x72, 
+	0x74, 0x65, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x0a,
+	0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x65, 0x72, 
+	0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a,
+	0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x65, 0x72, 
+	0x74, 0x65, 0x78, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a,
+	0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 
+	0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a,
+	0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 
+	0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x5d, 0x5d, 0x2c, 0x0a,
 	0x09, 0x09, 0x46, 0x4f, 0x4f, 0x54, 0x45, 0x52, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a,
 	0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a,
 	0x09, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x3d, 
-	0x20, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a,
+	0x20, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x73, 0x74, 
+	0x3b, 0x0a,
 	0x09, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x56, 0x65, 
 	0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a,
 	0x09, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x70, 0x6f, 0x73, 
 	0x20, 0x7b, 0x0a,
 	0x09, 0x09, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a,
 	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x0a,
-	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x78, 
-	0x43, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x67, 0x6c, 0x5f, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x5b, 
-	0x30, 0x5d, 0x0a,
-	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 
-	0x6f, 0x72, 0x20, 0x67, 0x6c, 0x5f, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x5d, 0x5d, 0x2c, 0x0a,
+	0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 
+	0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a,
+	0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 
+	0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x5d, 0x5d, 0x2c, 0x0a,
 	0x09, 0x09, 0x46, 0x4f, 0x4f, 0x54, 0x45, 0x52, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a,
 	0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a,
 	0x09, 0x2f, 0x2f, 0x20, 0x66, 0x69, 0x78, 0x20, 0x77, 0x65, 0x69, 0x72, 0x64, 0x20, 0x63, 0x72, 0x61, 0x73, 
 	0x09, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x65, 0x66, 
 	0x66, 0x65, 0x63, 0x74, 0x28, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x2c, 
 	0x20, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x2c, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65, 
-	0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x73, 0x74, 0x2c, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 
-	0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x78, 0x79, 0x29, 0x3b, 0x0a,
+	0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2c, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 
+	0x72, 0x64, 0x2e, 0x78, 0x79, 0x29, 0x3b, 0x0a,
 	0x7d, 0x5d, 0x5d, 0x2c, 0x0a,
 	0x09, 0x7d, 0x0a,
 	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x72, 
 	0x72, 0x65, 0x2c, 0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2c, 
 	0x20, 0x76, 0x65, 0x63, 0x32, 0x20, 0x70, 0x69, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x29, 0x0a,
 	0x7b, 0x0a,
-	0x09, 0x76, 0x65, 0x63, 0x34, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x3d, 0x20, 0x54, 
+	0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x2a, 0x20, 0x54, 
 	0x65, 0x78, 0x65, 0x6c, 0x28, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x2c, 0x20, 0x74, 0x65, 0x78, 0x63, 
 	0x6f, 0x6f, 0x72, 0x64, 0x29, 0x3b, 0x0a,
-	0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x20, 0x2a, 
-	0x20, 0x76, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a,
 	0x7d, 0x5d, 0x5d, 0x2c, 0x0a,
 	0x09, 0x7d, 0x0a,
 	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x5f, 0x73, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 
 	0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x3d, 0x20, 
 	0x5f, 0x73, 0x65, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x0a,
 	0x09, 0x09, 0x2d, 0x2d, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x20, 0x73, 0x75, 0x72, 0x65, 0x20, 0x77, 0x65, 0x20, 
-	0x68, 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x20, 0x73, 0x68, 0x61, 
-	0x64, 0x65, 0x72, 0x0a,
+	0x61, 0x6c, 0x77, 0x61, 0x79, 0x73, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x64, 0x65, 0x66, 0x61, 
+	0x75, 0x6c, 0x74, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x2c, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 
+	0x79, 0x27, 0x72, 0x65, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x0a,
 	0x09, 0x09, 0x69, 0x66, 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
 	0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 
 	0x73, 0x2e, 0x69, 0x73, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x28, 0x22, 0x73, 0x68, 0x61,