Browse Source

Added GLSL ES 1.00 (OpenGL ES 2) shader support.

--HG--
branch : minor
Alex Szpakowski 10 years ago
parent
commit
5df56d041a

+ 7 - 0
src/modules/graphics/Graphics.h

@@ -87,6 +87,13 @@ public:
 		SUPPORT_MAX_ENUM
 	};
 
+	enum Renderer
+	{
+		RENDERER_OPENGL = 0,
+		RENDERER_OPENGLES,
+		RENDERER_MAX_ENUM
+	};
+
 	enum SystemLimit
 	{
 		LIMIT_POINT_SIZE,

+ 5 - 2
src/modules/graphics/opengl/Graphics.cpp

@@ -295,7 +295,10 @@ bool Graphics::setMode(int width, int height, bool &sRGB)
 
 	// We always need a default shader.
 	if (!Shader::defaultShader)
-		Shader::defaultShader = newShader(Shader::defaultCode[0]);
+	{
+		Renderer renderer = GLAD_ES_VERSION_2_0 ? RENDERER_OPENGLES : RENDERER_OPENGL;
+		Shader::defaultShader = newShader(Shader::defaultCode[renderer]);
+	}
 
 	if (!getShader())
 		setShader(Shader::defaultShader);
@@ -944,7 +947,7 @@ Graphics::LineJoin Graphics::getLineJoin() const
 
 void Graphics::setPointSize(float size)
 {
-	glPointSize(size);
+	gl.setPointSize(size);
 	states.back().pointSize = size;
 }
 

+ 47 - 15
src/modules/graphics/opengl/OpenGL.cpp

@@ -97,6 +97,11 @@ void OpenGL::setupContext()
 	glGetIntegerv(GL_SCISSOR_BOX, (GLint *) &state.scissor.x);
 	state.scissor.y = state.viewport.h - (state.scissor.y + state.scissor.h);
 
+	if (GLAD_VERSION_1_0)
+		glGetFloatv(GL_POINT_SIZE, &state.pointSize);
+	else
+		state.pointSize = 1.0f;
+
 	// Initialize multiple texture unit support for shaders.
 	state.textureUnits.clear();
 
@@ -290,27 +295,41 @@ void OpenGL::prepareDraw()
 		}
 	}
 
-	const float *curproj = matrices.projection.back().getElements();
-	const float *lastproj = state.lastProjectionMatrix.getElements();
+	const Matrix &curproj = matrices.projection.back();
+	const Matrix &curxform = matrices.transform.back();
 
-	// We only need to re-upload the projection matrix if it's changed.
-	if (memcmp(curproj, lastproj, sizeof(float) * 16) != 0)
+	if (GLAD_ES_VERSION_2_0 && shader)
 	{
-		glMatrixMode(GL_PROJECTION);
-		glLoadMatrixf(curproj);
-		glMatrixMode(GL_MODELVIEW);
+		// Send built-in uniforms to the current shader.
+		shader->sendBuiltinMatrix(Shader::BUILTIN_TRANSFORM_MATRIX, 4, curxform.getElements(), 1);
+		shader->sendBuiltinMatrix(Shader::BUILTIN_PROJECTION_MATRIX, 4, curproj.getElements(), 1);
+
+		Matrix tp_matrix(curproj * curxform);
+		shader->sendBuiltinMatrix(Shader::BUILTIN_TRANSFORM_PROJECTION_MATRIX, 4, tp_matrix.getElements(), 1);
 
-		state.lastProjectionMatrix = matrices.projection.back();
+		shader->sendBuiltinFloat(Shader::BUILTIN_POINT_SIZE, 1, &state.pointSize, 1);
 	}
+	else if (GLAD_VERSION_1_0)
+	{
+		const Matrix &lastproj = state.lastProjectionMatrix;
+		const Matrix &lastxform = state.lastTransformMatrix;
 
-	const float *curxform = matrices.transform.back().getElements();
-	const float *lastxform = state.lastTransformMatrix.getElements();
+		// We only need to re-upload the projection matrix if it's changed.
+		if (memcmp(curproj.getElements(), lastproj.getElements(), sizeof(float) * 16) != 0)
+		{
+			glMatrixMode(GL_PROJECTION);
+			glLoadMatrixf(curproj.getElements());
+			glMatrixMode(GL_MODELVIEW);
 
-	// Same with the transform matrix.
-	if (memcmp(curxform, lastxform, sizeof(float) * 16) != 0)
-	{
-		glLoadMatrixf(curxform);
-		state.lastTransformMatrix = matrices.transform.back();
+			state.lastProjectionMatrix = matrices.projection.back();
+		}
+
+		// Same with the transform matrix.
+		if (memcmp(curxform.getElements(), lastxform.getElements(), sizeof(float) * 16) != 0)
+		{
+			glLoadMatrixf(curxform.getElements());
+			state.lastTransformMatrix = matrices.transform.back();
+		}
 	}
 }
 
@@ -450,6 +469,19 @@ OpenGL::BlendState OpenGL::getBlendState() const
 	return state.blend;
 }
 
+void OpenGL::setPointSize(float size)
+{
+	if (GLAD_VERSION_1_0)
+		glPointSize(size);
+
+	state.pointSize = size;
+}
+
+float OpenGL::getPointSize() const
+{
+	return state.pointSize;
+}
+
 GLuint OpenGL::getDefaultFBO() const
 {
 	return state.defaultFBO;

+ 12 - 0
src/modules/graphics/opengl/OpenGL.h

@@ -247,6 +247,16 @@ public:
 	 **/
 	BlendState getBlendState() const;
 
+	/**
+	 * Sets the global point size.
+	 **/
+	void setPointSize(float size);
+
+	/**
+	 * Gets the global point size.
+	 **/
+	float getPointSize() const;
+
 	/**
 	 * This will usually be 0 (system drawable), but some platforms require a
 	 * non-zero FBO for rendering.
@@ -352,6 +362,8 @@ private:
 		Viewport viewport;
 		Viewport scissor;
 
+		float pointSize;
+
 		GLuint defaultFBO;
 		GLuint defaultTexture;
 

+ 38 - 5
src/modules/graphics/opengl/Shader.cpp

@@ -64,7 +64,7 @@ namespace
 Shader *Shader::current = nullptr;
 Shader *Shader::defaultShader = nullptr;
 
-Shader::ShaderSource Shader::defaultCode[1]; // TODO: RENDERER_MAX_ENUM
+Shader::ShaderSource Shader::defaultCode[Graphics::RENDERER_MAX_ENUM];
 
 GLint Shader::maxTexUnits = 0;
 std::vector<int> Shader::textureCounters;
@@ -224,11 +224,13 @@ bool Shader::loadVolatile()
 
 	std::vector<GLuint> shaderids;
 
-	// The shader program must have both vertex and pixel shader stages.
-	const ShaderSource &defaults = defaultCode[0];
+	const ShaderSource *defaults = &defaultCode[Graphics::RENDERER_OPENGL];
+	if (GLAD_ES_VERSION_2_0)
+		defaults = &defaultCode[Graphics::RENDERER_OPENGLES];
 
-	const std::string &vertexcode = shaderSource.vertex.empty() ? defaults.vertex : shaderSource.vertex;
-	const std::string &pixelcode = shaderSource.pixel.empty() ? defaults.pixel : shaderSource.pixel;
+	// The shader program must have both vertex and pixel shader stages.
+	const std::string &vertexcode = shaderSource.vertex.empty() ? defaults->vertex : shaderSource.vertex;
+	const std::string &pixelcode = shaderSource.pixel.empty() ? defaults->pixel : shaderSource.pixel;
 
 	try
 	{
@@ -627,6 +629,33 @@ bool Shader::hasBuiltinUniform(BuiltinUniform builtin) const
 	return builtinUniforms[int(builtin)] != -1;
 }
 
+bool Shader::sendBuiltinMatrix(BuiltinUniform builtin, int size, const GLfloat *m, int count)
+{
+	if (!hasBuiltinUniform(builtin))
+		return false;
+
+	GLint location = builtinUniforms[GLint(builtin)];
+
+	TemporaryAttacher attacher(this);
+
+	switch (size)
+	{
+	case 2:
+		glUniformMatrix2fv(location, count, GL_FALSE, m);
+		break;
+	case 3:
+		glUniformMatrix3fv(location, count, GL_FALSE, m);
+		break;
+	case 4:
+		glUniformMatrix4fv(location, count, GL_FALSE, m);
+		break;
+	default:
+		return false;
+	}
+	
+	return true;
+}
+
 bool Shader::sendBuiltinFloat(BuiltinUniform builtin, int size, const GLfloat *vec, int count)
 {
 	if (!hasBuiltinUniform(builtin))
@@ -822,6 +851,10 @@ StringMap<VertexAttribID, ATTRIB_MAX_ENUM> Shader::attribNames(Shader::attribNam
 
 StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM>::Entry Shader::builtinNameEntries[] =
 {
+	{"TransformMatrix", Shader::BUILTIN_TRANSFORM_MATRIX},
+	{"ProjectionMatrix", Shader::BUILTIN_PROJECTION_MATRIX},
+	{"TransformProjectionMatrix", Shader::BUILTIN_TRANSFORM_PROJECTION_MATRIX},
+	{"love_PointSize", Shader::BUILTIN_POINT_SIZE},
 	{"love_ScreenSize", Shader::BUILTIN_SCREEN_SIZE},
 };
 

+ 7 - 1
src/modules/graphics/opengl/Shader.h

@@ -24,6 +24,7 @@
 // LOVE
 #include "common/Object.h"
 #include "common/StringMap.h"
+#include "graphics/Graphics.h"
 #include "OpenGL.h"
 #include "Texture.h"
 
@@ -56,6 +57,10 @@ public:
 	// Built-in uniform (extern) variables.
 	enum BuiltinUniform
 	{
+		BUILTIN_TRANSFORM_MATRIX = 0,
+		BUILTIN_PROJECTION_MATRIX,
+		BUILTIN_TRANSFORM_PROJECTION_MATRIX,
+		BUILTIN_POINT_SIZE,
 		BUILTIN_SCREEN_SIZE,
 		BUILTIN_MAX_ENUM
 	};
@@ -84,7 +89,7 @@ public:
 	static Shader *defaultShader;
 
 	// Default shader code (a shader is always required internally.)
-	static ShaderSource defaultCode[1]; // TODO: RENDERER_MAX_ENUM
+	static ShaderSource defaultCode[Graphics::RENDERER_MAX_ENUM];
 
 	/**
 	 * Creates a new Shader using a list of source codes.
@@ -173,6 +178,7 @@ public:
 	 **/
 	bool hasVertexAttrib(VertexAttribID attrib) const;
 	bool hasBuiltinUniform(BuiltinUniform builtin) const;
+	bool sendBuiltinMatrix(BuiltinUniform builtin, int size, const GLfloat *m, int count);
 	bool sendBuiltinFloat(BuiltinUniform builtin, int size, const GLfloat *m, int count);
 	void checkSetScreenParams();
 

+ 12 - 1
src/modules/graphics/opengl/wrap_Graphics.cpp

@@ -971,7 +971,18 @@ int w_setDefaultShaderCode(lua_State *L)
 
 	lua_pop(L, 3);
 
-	Shader::defaultCode[0] = openglcode;
+	lua_getfield(L, 1, "opengles");
+	lua_rawgeti(L, -1, 1);
+	lua_rawgeti(L, -2, 2);
+
+	Shader::ShaderSource openglescode;
+	openglescode.vertex = luax_checkstring(L, -2);
+	openglescode.pixel = luax_checkstring(L, -1);
+
+	lua_pop(L, 3);
+
+	Shader::defaultCode[Graphics::RENDERER_OPENGL]   = openglcode;
+	Shader::defaultCode[Graphics::RENDERER_OPENGLES] = openglescode;
 
 	return 0;
 }

+ 55 - 36
src/scripts/graphics.lua

@@ -1289,27 +1289,39 @@ do
 
 	-- SHADERS
 
-	local GLSL_VERSION = "#version 120"
-	
-	local GLSL_SYNTAX = [[
+	local GLSL = {}
+
+	GLSL.VERSION = "#version 120"
+	GLSL.VERSION_ES = "#version 100"
+
+	GLSL.SYNTAX = [[
+#ifndef GL_ES
 #define lowp
 #define mediump
 #define highp
+#endif
 #define number float
 #define Image sampler2D
 #define extern uniform
 #define Texel texture2D
 #pragma optionNV(strict on)]]
 
-	local GLSL_UNIFORMS = [[
+	GLSL.UNIFORMS = [[
+#ifdef GL_ES
+uniform mat4 TransformMatrix;
+uniform mat4 ProjectionMatrix;
+uniform mat4 TransformProjectionMatrix;
+// uniform mat4 NormalMatrix;
+uniform mediump float love_PointSize;
+#else
 #define TransformMatrix gl_ModelViewMatrix
 #define ProjectionMatrix gl_ProjectionMatrix
 #define TransformProjectionMatrix gl_ModelViewProjectionMatrix
-#define NormalMatrix gl_NormalMatrix
+#endif
 uniform sampler2D _tex0_;
-uniform vec4 love_ScreenSize;]]
+uniform mediump vec4 love_ScreenSize;]]
 
-	local GLSL_VERTEX = {
+	GLSL.VERTEX = {
 		HEADER = [[
 #define VERTEX
 
@@ -1318,31 +1330,29 @@ attribute vec4 VertexTexCoord;
 attribute vec4 VertexColor;
 
 varying vec4 VaryingTexCoord;
-varying vec4 VaryingColor;
-
-// #if defined(GL_ARB_draw_instanced)
-//	#extension GL_ARB_draw_instanced : enable
-//	#define love_InstanceID gl_InstanceIDARB
-// #else
-//	attribute float love_PseudoInstanceID;
-//	int love_InstanceID = int(love_PseudoInstanceID);
-// #endif
-]],
+varying vec4 VaryingColor;]],
 
 		FOOTER = [[
 void main() {
 	VaryingTexCoord = VertexTexCoord;
 	VaryingColor = VertexColor;
+#ifdef GL_ES
+	gl_PointSize = love_PointSize;
+#endif
 	gl_Position = position(TransformProjectionMatrix, VertexPosition);
 }]],
 	}
 
-	local GLSL_PIXEL = {
+	GLSL.PIXEL = {
 		HEADER = [[
 #define PIXEL
 
-varying vec4 VaryingTexCoord;
-varying vec4 VaryingColor;
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+varying mediump vec4 VaryingTexCoord;
+varying lowp vec4 VaryingColor;
 
 #define love_Canvases gl_FragData]],
 
@@ -1369,24 +1379,24 @@ void main() {
 }]],
 	}
 
-	local function createVertexCode(vertexcode)
+	local function createVertexCode(vertexcode, lang)
 		local vertexcodes = {
-			GLSL_VERSION,
-			GLSL_SYNTAX, GLSL_VERTEX.HEADER, GLSL_UNIFORMS,
-			"#line 0",
+			lang == "glsles" and GLSL.VERSION_ES or GLSL.VERSION,
+			GLSL.SYNTAX, GLSL.VERTEX.HEADER, GLSL.UNIFORMS,
+			lang == "glsles" and "#line 1" or "#line 0",
 			vertexcode,
-			GLSL_VERTEX.FOOTER,
+			GLSL.VERTEX.FOOTER,
 		}
 		return table_concat(vertexcodes, "\n")
 	end
 
-	local function createPixelCode(pixelcode, is_multicanvas)
+	local function createPixelCode(pixelcode, is_multicanvas, lang)
 		local pixelcodes = {
-			GLSL_VERSION,
-			GLSL_SYNTAX, GLSL_PIXEL.HEADER, GLSL_UNIFORMS,
-			"#line 0",
+			lang == "glsles" and GLSL.VERSION_ES or GLSL.VERSION,
+			GLSL.SYNTAX, GLSL.PIXEL.HEADER, GLSL.UNIFORMS,
+			lang == "glsles" and "#line 1" or "#line 0",
 			pixelcode,
-			is_multicanvas and GLSL_PIXEL.FOOTER_MULTI_CANVAS or GLSL_PIXEL.FOOTER,
+			is_multicanvas and GLSL.PIXEL.FOOTER_MULTI_CANVAS or GLSL.PIXEL.FOOTER,
 		}
 		return table_concat(pixelcodes, "\n")
 	end
@@ -1409,7 +1419,12 @@ void main() {
 	function love.graphics._shaderCodeToGLSL(arg1, arg2)
 		local vertexcode, pixelcode
 		local is_multicanvas = false -- whether pixel code has "effects" function instead of "effect"
-		
+
+		local lang = "glsl"
+		if (love.graphics.getRendererInfo()) == "OpenGL ES" then
+			lang = "glsles"
+		end
+
 		if arg1 then
 			if isVertexCode(arg1) then
 				vertexcode = arg1 -- first arg contains vertex shader code
@@ -1435,10 +1450,10 @@ void main() {
 		end
 
 		if vertexcode then
-			vertexcode = createVertexCode(vertexcode)
+			vertexcode = createVertexCode(vertexcode, lang)
 		end
 		if pixelcode then
-			pixelcode = createPixelCode(pixelcode, is_multicanvas)
+			pixelcode = createPixelCode(pixelcode, is_multicanvas, lang)
 		end
 
 		return vertexcode, pixelcode
@@ -1477,15 +1492,19 @@ vec4 position(mat4 transform_proj, vec4 vertpos) {
 	return transform_proj * vertpos;
 }]],
 		pixel = [[
-vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord) {
+vec4 effect(lowp vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord) {
 	return Texel(tex, texcoord) * vcolor;
 }]]
 	}
 
 	local defaults = {
 		opengl = {
-			createVertexCode(defaultcode.vertex),
-			createPixelCode(defaultcode.pixel, false),
+			createVertexCode(defaultcode.vertex, "glsl"),
+			createPixelCode(defaultcode.pixel, false, "glsl"),
+		},
+		opengles = {
+			createVertexCode(defaultcode.vertex, "glsles"),
+			createPixelCode(defaultcode.pixel, false, "glsles"),
 		},
 	}
 

+ 95 - 63
src/scripts/graphics.lua.h

@@ -27,7 +27,7 @@ const unsigned char graphics_lua[] =
 
 	0x2d, 0x2d, 0x5b, 0x5b, 0x0a,
 	0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, 
-	0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 
+	0x2d, 0x32, 0x30, 0x31, 0x35, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 
 	0x6d, 0x65, 0x6e, 0x74, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x0a,
 	0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, 
 	0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x27, 0x61, 0x73, 0x2d, 0x69, 0x73, 0x27, 0x2c, 0x20, 0x77, 
@@ -6264,14 +6264,17 @@ const unsigned char graphics_lua[] =
 	0x69, 0x6e, 0x74, 0x66, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x0a,
 	0x09, 0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x2d, 0x2d, 0x20, 0x53, 0x48, 0x41, 0x44, 0x45, 0x52, 0x53, 0x0a,
-	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 
-	0x4e, 0x20, 0x3d, 0x20, 0x22, 0x23, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x32, 0x30, 0x22, 0x0a,
-	0x09, 0x0a,
-	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x53, 0x59, 0x4e, 0x54, 0x41, 0x58, 
-	0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a,
+	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a,
+	0x09, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x20, 0x3d, 0x20, 0x22, 0x23, 
+	0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x32, 0x30, 0x22, 0x0a,
+	0x09, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x5f, 0x45, 0x53, 0x20, 0x3d, 
+	0x20, 0x22, 0x23, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x30, 0x30, 0x22, 0x0a,
+	0x09, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x53, 0x59, 0x4e, 0x54, 0x41, 0x58, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a,
+	0x23, 0x69, 0x66, 0x6e, 0x64, 0x65, 0x66, 0x20, 0x47, 0x4c, 0x5f, 0x45, 0x53, 0x0a,
 	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x6c, 0x6f, 0x77, 0x70, 0x0a,
 	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x70, 0x0a,
 	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x68, 0x69, 0x67, 0x68, 0x70, 0x0a,
+	0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a,
 	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x66, 0x6c, 0x6f, 
 	0x61, 0x74, 0x0a,
 	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x70, 
@@ -6282,8 +6285,22 @@ const unsigned char graphics_lua[] =
 	0x75, 0x72, 0x65, 0x32, 0x44, 0x0a,
 	0x23, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x20, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x56, 0x28, 0x73, 
 	0x74, 0x72, 0x69, 0x63, 0x74, 0x20, 0x6f, 0x6e, 0x29, 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,
+	0x09, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x55, 0x4e, 0x49, 0x46, 0x4f, 0x52, 0x4d, 0x53, 0x20, 0x3d, 0x20, 0x5b, 
+	0x5b, 0x0a,
+	0x23, 0x69, 0x66, 0x64, 0x65, 0x66, 0x20, 0x47, 0x4c, 0x5f, 0x45, 0x53, 0x0a,
+	0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73, 
+	0x66, 0x6f, 0x72, 0x6d, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x3b, 0x0a,
+	0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x20, 0x50, 0x72, 0x6f, 0x6a, 0x65, 
+	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x3b, 0x0a,
+	0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73, 
+	0x66, 0x6f, 0x72, 0x6d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x72, 
+	0x69, 0x78, 0x3b, 0x0a,
+	0x2f, 0x2f, 0x20, 0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x6d, 0x61, 0x74, 0x34, 0x20, 0x4e, 0x6f, 
+	0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x3b, 0x0a,
+	0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 0x66, 0x6c, 
+	0x6f, 0x61, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 
+	0x3b, 0x0a,
+	0x23, 0x65, 0x6c, 0x73, 0x65, 0x0a,
 	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x4d, 
 	0x61, 0x74, 0x72, 0x69, 0x78, 0x20, 0x67, 0x6c, 0x5f, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 
 	0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x0a,
@@ -6294,14 +6311,13 @@ const unsigned char graphics_lua[] =
 	0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x20, 0x67, 0x6c, 
 	0x5f, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x56, 0x69, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 
 	0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x0a,
-	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 
-	0x69, 0x78, 0x20, 0x67, 0x6c, 0x5f, 0x4e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x0a,
+	0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a,
 	0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x32, 0x44, 0x20, 
 	0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x3b, 0x0a,
-	0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 
-	0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x53, 0x69, 0x7a, 0x65, 0x3b, 0x5d, 0x5d, 0x0a,
-	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 
-	0x20, 0x3d, 0x20, 0x7b, 0x0a,
+	0x75, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 0x76, 0x65, 
+	0x63, 0x34, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x53, 0x69, 0x7a, 0x65, 
+	0x3b, 0x5d, 0x5d, 0x0a,
+	0x09, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x20, 0x3d, 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,
 	0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x65, 0x72, 
@@ -6313,45 +6329,35 @@ const unsigned char graphics_lua[] =
 	0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 
 	0x6e, 0x67, 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,
-	0x2f, 0x2f, 0x20, 0x23, 0x69, 0x66, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x28, 0x47, 0x4c, 0x5f, 
-	0x41, 0x52, 0x42, 0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 
-	0x29, 0x0a,
-	0x2f, 0x2f, 0x09, 0x23, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x47, 0x4c, 0x5f, 0x41, 
-	0x52, 0x42, 0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x20, 
-	0x3a, 0x20, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x0a,
-	0x2f, 0x2f, 0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 
-	0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x20, 0x67, 0x6c, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 
-	0x63, 0x65, 0x49, 0x44, 0x41, 0x52, 0x42, 0x0a,
-	0x2f, 0x2f, 0x20, 0x23, 0x65, 0x6c, 0x73, 0x65, 0x0a,
-	0x2f, 0x2f, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 
-	0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 
-	0x63, 0x65, 0x49, 0x44, 0x3b, 0x0a,
-	0x2f, 0x2f, 0x09, 0x69, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 
-	0x63, 0x65, 0x49, 0x44, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 
-	0x65, 0x75, 0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x29, 0x3b, 0x0a,
-	0x2f, 0x2f, 0x20, 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a,
-	0x5d, 0x5d, 0x2c, 0x0a,
+	0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 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,
 	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,
+	0x23, 0x69, 0x66, 0x64, 0x65, 0x66, 0x20, 0x47, 0x4c, 0x5f, 0x45, 0x53, 0x0a,
+	0x09, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 
+	0x76, 0x65, 0x5f, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x3b, 0x0a,
+	0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a,
 	0x09, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x70, 0x6f, 0x73, 
 	0x69, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x50, 0x72, 0x6f, 
 	0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x2c, 0x20, 0x56, 0x65, 0x72, 
 	0x74, 0x65, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x3b, 0x0a,
 	0x7d, 0x5d, 0x5d, 0x2c, 0x0a,
 	0x09, 0x7d, 0x0a,
-	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x20, 
-	0x3d, 0x20, 0x7b, 0x0a,
+	0x09, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x20, 0x3d, 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,
-	0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 
-	0x6e, 0x67, 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,
+	0x23, 0x69, 0x66, 0x64, 0x65, 0x66, 0x20, 0x47, 0x4c, 0x5f, 0x45, 0x53, 0x0a,
+	0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 
+	0x66, 0x6c, 0x6f, 0x61, 0x74, 0x3b, 0x0a,
+	0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a,
+	0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x70, 0x20, 0x76, 0x65, 
+	0x63, 0x34, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 
+	0x3b, 0x0a,
+	0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x6f, 0x77, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 
+	0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a,
 	0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x43, 0x61, 0x6e, 0x76, 0x61, 
 	0x73, 0x65, 0x73, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x44, 0x61, 0x74, 0x61, 0x5d, 0x5d, 0x2c, 0x0a,
 	0x09, 0x09, 0x46, 0x4f, 0x4f, 0x54, 0x45, 0x52, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a,
@@ -6405,16 +6411,21 @@ const unsigned char graphics_lua[] =
 	0x09, 0x7d, 0x0a,
 	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x72, 
 	0x65, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x76, 0x65, 0x72, 
-	0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a,
+	0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x6c, 0x61, 0x6e, 0x67, 0x29, 0x0a,
 	0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 
 	0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a,
-	0x09, 0x09, 0x09, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x2c, 0x0a,
-	0x09, 0x09, 0x09, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x53, 0x59, 0x4e, 0x54, 0x41, 0x58, 0x2c, 0x20, 0x47, 0x4c, 
-	0x53, 0x4c, 0x5f, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x2e, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x2c, 0x20, 
-	0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x55, 0x4e, 0x49, 0x46, 0x4f, 0x52, 0x4d, 0x53, 0x2c, 0x0a,
-	0x09, 0x09, 0x09, 0x22, 0x23, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x30, 0x22, 0x2c, 0x0a,
+	0x09, 0x09, 0x09, 0x6c, 0x61, 0x6e, 0x67, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x67, 0x6c, 0x73, 0x6c, 0x65, 0x73, 
+	0x22, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 
+	0x5f, 0x45, 0x53, 0x20, 0x6f, 0x72, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 
+	0x4e, 0x2c, 0x0a,
+	0x09, 0x09, 0x09, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x53, 0x59, 0x4e, 0x54, 0x41, 0x58, 0x2c, 0x20, 0x47, 0x4c, 
+	0x53, 0x4c, 0x2e, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x2e, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x2c, 0x20, 
+	0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x55, 0x4e, 0x49, 0x46, 0x4f, 0x52, 0x4d, 0x53, 0x2c, 0x0a,
+	0x09, 0x09, 0x09, 0x6c, 0x61, 0x6e, 0x67, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x67, 0x6c, 0x73, 0x6c, 0x65, 0x73, 
+	0x22, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x22, 0x23, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x31, 0x22, 0x20, 0x6f, 0x72, 
+	0x20, 0x22, 0x23, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x30, 0x22, 0x2c, 0x0a,
 	0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x0a,
-	0x09, 0x09, 0x09, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x2e, 0x46, 0x4f, 0x4f, 
+	0x09, 0x09, 0x09, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x2e, 0x46, 0x4f, 0x4f, 
 	0x54, 0x45, 0x52, 0x2c, 0x0a,
 	0x09, 0x09, 0x7d, 0x0a,
 	0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 
@@ -6424,19 +6435,24 @@ const unsigned char graphics_lua[] =
 	0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x63, 0x72, 
 	0x65, 0x61, 0x74, 0x65, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x70, 0x69, 0x78, 0x65, 
 	0x6c, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x73, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x63, 0x61, 0x6e, 
-	0x76, 0x61, 0x73, 0x29, 0x0a,
+	0x76, 0x61, 0x73, 0x2c, 0x20, 0x6c, 0x61, 0x6e, 0x67, 0x29, 0x0a,
 	0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x73, 
 	0x20, 0x3d, 0x20, 0x7b, 0x0a,
-	0x09, 0x09, 0x09, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x2c, 0x0a,
-	0x09, 0x09, 0x09, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x53, 0x59, 0x4e, 0x54, 0x41, 0x58, 0x2c, 0x20, 0x47, 0x4c, 
-	0x53, 0x4c, 0x5f, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x2e, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x2c, 0x20, 0x47, 
-	0x4c, 0x53, 0x4c, 0x5f, 0x55, 0x4e, 0x49, 0x46, 0x4f, 0x52, 0x4d, 0x53, 0x2c, 0x0a,
-	0x09, 0x09, 0x09, 0x22, 0x23, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x30, 0x22, 0x2c, 0x0a,
+	0x09, 0x09, 0x09, 0x6c, 0x61, 0x6e, 0x67, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x67, 0x6c, 0x73, 0x6c, 0x65, 0x73, 
+	0x22, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 
+	0x5f, 0x45, 0x53, 0x20, 0x6f, 0x72, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 
+	0x4e, 0x2c, 0x0a,
+	0x09, 0x09, 0x09, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x53, 0x59, 0x4e, 0x54, 0x41, 0x58, 0x2c, 0x20, 0x47, 0x4c, 
+	0x53, 0x4c, 0x2e, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x2e, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x2c, 0x20, 0x47, 
+	0x4c, 0x53, 0x4c, 0x2e, 0x55, 0x4e, 0x49, 0x46, 0x4f, 0x52, 0x4d, 0x53, 0x2c, 0x0a,
+	0x09, 0x09, 0x09, 0x6c, 0x61, 0x6e, 0x67, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x67, 0x6c, 0x73, 0x6c, 0x65, 0x73, 
+	0x22, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x22, 0x23, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x31, 0x22, 0x20, 0x6f, 0x72, 
+	0x20, 0x22, 0x23, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x30, 0x22, 0x2c, 0x0a,
 	0x09, 0x09, 0x09, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x0a,
 	0x09, 0x09, 0x09, 0x69, 0x73, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x63, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x20, 
-	0x61, 0x6e, 0x64, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x2e, 0x46, 0x4f, 0x4f, 
+	0x61, 0x6e, 0x64, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x2e, 0x46, 0x4f, 0x4f, 
 	0x54, 0x45, 0x52, 0x5f, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x5f, 0x43, 0x41, 0x4e, 0x56, 0x41, 0x53, 0x20, 0x6f, 
-	0x72, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x2e, 0x46, 0x4f, 0x4f, 0x54, 0x45, 
+	0x72, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x2e, 0x46, 0x4f, 0x4f, 0x54, 0x45, 
 	0x52, 0x2c, 0x0a,
 	0x09, 0x09, 0x7d, 0x0a,
 	0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 
@@ -6479,7 +6495,14 @@ const unsigned char graphics_lua[] =
 	0x61, 0x73, 0x20, 0x22, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x22, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 
 	0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x73, 0x74, 0x65, 0x61, 0x64, 0x20, 0x6f, 0x66, 0x20, 0x22, 0x65, 0x66, 
 	0x66, 0x65, 0x63, 0x74, 0x22, 0x0a,
-	0x09, 0x09, 0x0a,
+	0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x61, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x22, 0x67, 0x6c, 
+	0x73, 0x6c, 0x22, 0x0a,
+	0x09, 0x09, 0x69, 0x66, 0x20, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 
+	0x73, 0x2e, 0x67, 0x65, 0x74, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x28, 
+	0x29, 0x29, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x4f, 0x70, 0x65, 0x6e, 0x47, 0x4c, 0x20, 0x45, 0x53, 0x22, 0x20, 
+	0x74, 0x68, 0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x09, 0x6c, 0x61, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x22, 0x67, 0x6c, 0x73, 0x6c, 0x65, 0x73, 0x22, 0x0a,
+	0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x09, 0x69, 0x66, 0x20, 0x61, 0x72, 0x67, 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
 	0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x69, 0x73, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x64, 0x65, 
 	0x28, 0x61, 0x72, 0x67, 0x31, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
@@ -6525,14 +6548,14 @@ const unsigned char graphics_lua[] =
 	0x65, 0x6e, 0x0a,
 	0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x72, 
 	0x65, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x76, 0x65, 0x72, 
-	0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a,
+	0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x6c, 0x61, 0x6e, 0x67, 0x29, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x09, 0x69, 0x66, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 
 	0x6e, 0x0a,
 	0x09, 0x09, 0x09, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x63, 0x72, 0x65, 
 	0x61, 0x74, 0x65, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x70, 0x69, 0x78, 0x65, 0x6c, 
 	0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x73, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x63, 0x61, 0x6e, 0x76, 
-	0x61, 0x73, 0x29, 0x0a,
+	0x61, 0x73, 0x2c, 0x20, 0x6c, 0x61, 0x6e, 0x67, 0x29, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 
 	0x65, 0x2c, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x0a,
@@ -6622,10 +6645,10 @@ const unsigned char graphics_lua[] =
 	0x70, 0x72, 0x6f, 0x6a, 0x20, 0x2a, 0x20, 0x76, 0x65, 0x72, 0x74, 0x70, 0x6f, 0x73, 0x3b, 0x0a,
 	0x7d, 0x5d, 0x5d, 0x2c, 0x0a,
 	0x09, 0x09, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a,
-	0x76, 0x65, 0x63, 0x34, 0x20, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x28, 0x76, 0x65, 0x63, 0x34, 0x20, 0x76, 
-	0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x20, 0x74, 0x65, 0x78, 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, 0x20, 0x7b, 0x0a,
+	0x76, 0x65, 0x63, 0x34, 0x20, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x28, 0x6c, 0x6f, 0x77, 0x70, 0x20, 0x76, 
+	0x65, 0x63, 0x34, 0x20, 0x76, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x20, 
+	0x74, 0x65, 0x78, 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, 0x20, 0x7b, 0x0a,
 	0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x28, 0x74, 0x65, 0x78, 0x2c, 
 	0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x29, 0x20, 0x2a, 0x20, 0x76, 0x63, 0x6f, 0x6c, 0x6f, 
 	0x72, 0x3b, 0x0a,
@@ -6636,10 +6659,19 @@ const unsigned char graphics_lua[] =
 	0x09, 0x09, 0x6f, 0x70, 0x65, 0x6e, 0x67, 0x6c, 0x20, 0x3d, 0x20, 0x7b, 0x0a,
 	0x09, 0x09, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x64, 
 	0x65, 0x28, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x65, 0x72, 0x74, 
-	0x65, 0x78, 0x29, 0x2c, 0x0a,
+	0x65, 0x78, 0x2c, 0x20, 0x22, 0x67, 0x6c, 0x73, 0x6c, 0x22, 0x29, 0x2c, 0x0a,
+	0x09, 0x09, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x43, 0x6f, 0x64, 0x65, 
+	0x28, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x69, 0x78, 0x65, 0x6c, 
+	0x2c, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x20, 0x22, 0x67, 0x6c, 0x73, 0x6c, 0x22, 0x29, 0x2c, 0x0a,
+	0x09, 0x09, 0x7d, 0x2c, 0x0a,
+	0x09, 0x09, 0x6f, 0x70, 0x65, 0x6e, 0x67, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a,
+	0x09, 0x09, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x64, 
+	0x65, 0x28, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x65, 0x72, 0x74, 
+	0x65, 0x78, 0x2c, 0x20, 0x22, 0x67, 0x6c, 0x73, 0x6c, 0x65, 0x73, 0x22, 0x29, 0x2c, 0x0a,
 	0x09, 0x09, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x43, 0x6f, 0x64, 0x65, 
 	0x28, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x69, 0x78, 0x65, 0x6c, 
-	0x2c, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x29, 0x2c, 0x0a,
+	0x2c, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x20, 0x22, 0x67, 0x6c, 0x73, 0x6c, 0x65, 0x73, 0x22, 0x29, 
+	0x2c, 0x0a,
 	0x09, 0x09, 0x7d, 0x2c, 0x0a,
 	0x09, 0x7d, 0x0a,
 	0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x5f, 0x73, 0x65,