From 2ea065c68b70f648754f2f62eb666b2b1dba113e Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 24 Mar 2013 02:20:15 -0300 Subject: [PATCH 1/3] Added MRT support to canvases via love.graphics.setCanvases(c1, c2, ...), and an 'effects' callback function in shaders. - Simultanious rendering to multiple canvases requires all canvases to be the same size (limitation of pre-GL3.0 framebuffers) - love.graphics.isSupported("mrtcanvas") was added - love_Canvases[n] (0-based array of active canvases) can be written to in pixel shaders in the 'effects' callback function - everything drawn to multiple canvases at once will be duplicated to all canvases if no shader is active or the standard 'effect' shader function is used --HG-- branch : MRTs --- src/modules/graphics/Graphics.cpp | 1 + src/modules/graphics/Graphics.h | 1 + src/modules/graphics/opengl/Canvas.cpp | 132 +++++++++++++- src/modules/graphics/opengl/Canvas.h | 23 ++- src/modules/graphics/opengl/Graphics.cpp | 2 +- src/modules/graphics/opengl/wrap_Canvas.cpp | 10 +- src/modules/graphics/opengl/wrap_Graphics.cpp | 59 ++++++- src/scripts/graphics.lua | 74 +++++--- src/scripts/graphics.lua.h | 162 ++++++++++++------ 9 files changed, 377 insertions(+), 87 deletions(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 71428919b..dc79f7299 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -158,6 +158,7 @@ StringMap::Entry Graphics::suppor { { "canvas", Graphics::SUPPORT_CANVAS }, { "hdrcanvas", Graphics::SUPPORT_HDR_CANVAS }, + { "mrtcanvas", Graphics::SUPPORT_MRT_CANVAS }, { "shader", Graphics::SUPPORT_SHADER }, { "npot", Graphics::SUPPORT_NPOT }, { "subtractive", Graphics::SUPPORT_SUBTRACTIVE }, diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index bd645c1e7..29212e2d8 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -87,6 +87,7 @@ public: { SUPPORT_CANVAS = 1, SUPPORT_HDR_CANVAS, + SUPPORT_MRT_CANVAS, SUPPORT_SHADER, SUPPORT_NPOT, SUPPORT_SUBTRACTIVE, diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 1e5c20670..b19947b4b 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -59,6 +59,12 @@ struct FramebufferStrategy */ virtual void deleteFBO(GLuint, GLuint, GLuint) {} virtual void bindFBO(GLuint) {} + + /// attach additional canvases to this framebuffer for rendering + /** + * @param[in] canvases List of canvases to attach + **/ + virtual void setAttachments(const std::vector &canvases) {} }; struct FramebufferStrategyGL3 : public FramebufferStrategy @@ -127,6 +133,35 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy { glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); } + + virtual void setAttachments(const std::vector &canvases) + { + if (canvases.size() == 0) + { + // set a single render target + glDrawBuffer(GL_COLOR_ATTACHMENT0); + return; + } + + std::vector drawbuffers; + drawbuffers.push_back(GL_COLOR_ATTACHMENT0); + + // attach the canvas framebuffer textures to the currently bound framebuffer + for (int i = 0; i < canvases.size(); i++) + { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1 + i, + GL_TEXTURE_2D, canvases[i]->getTextureName(), 0); + drawbuffers.push_back(GL_COLOR_ATTACHMENT1 + i); + } + + // set up multiple render targets + if (GLEE_VERSION_2_0) + glDrawBuffers(drawbuffers.size(), &drawbuffers[0]); + else if (GLEE_ARB_draw_buffers) + glDrawBuffersARB(drawbuffers.size(), &drawbuffers[0]); + else if (GLEE_ATI_draw_buffers) + glDrawBuffersATI(drawbuffers.size(), &drawbuffers[0]); + } }; struct FramebufferStrategyPackedEXT : public FramebufferStrategy @@ -196,6 +231,35 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer); } + + virtual void setAttachments(const std::vector &canvases) + { + if (canvases.size() == 0) + { + // set a single render target + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + return; + } + + std::vector drawbuffers; + drawbuffers.push_back(GL_COLOR_ATTACHMENT0_EXT); + + // attach the canvas framebuffer textures to the currently bound framebuffer + for (int i = 0; i < canvases.size(); i++) + { + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1_EXT + i, + GL_TEXTURE_2D, canvases[i]->getTextureName(), 0); + drawbuffers.push_back(GL_COLOR_ATTACHMENT1_EXT + i); + } + + // set up multiple render targets + if (GLEE_VERSION_2_0) + glDrawBuffers(drawbuffers.size(), &drawbuffers[0]); + else if (GLEE_ARB_draw_buffers) + glDrawBuffersARB(drawbuffers.size(), &drawbuffers[0]); + else if (GLEE_ATI_draw_buffers) + glDrawBuffersATI(drawbuffers.size(), &drawbuffers[0]); + } }; struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT @@ -288,6 +352,9 @@ static void getStrategy() } } +static int maxFBOColorAttachments = 0; +static int maxDrawBuffers = 0; + Canvas::Canvas(int width, int height, TextureType texture_type) : width(width) , height(height) @@ -338,11 +405,26 @@ bool Canvas::isSupported() return (strategy != &strategyNone); } -bool Canvas::isHdrSupported() +bool Canvas::isHDRSupported() { return GLEE_VERSION_3_0 || GLEE_ARB_texture_float; } +bool Canvas::isMRTSupported() +{ + if (!(isSupported() && (GLEE_VERSION_2_0 || GLEE_ARB_draw_buffers || GLEE_ATI_draw_buffers))) + return false; + + if (maxFBOColorAttachments == 0 || maxDrawBuffers == 0) + { + glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxFBOColorAttachments); + glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); + } + + // system must support at least 4 simultanious render targets + return maxFBOColorAttachments >= 4 && maxDrawBuffers >= 4; +} + void Canvas::bindDefaultCanvas() { if (current != NULL) @@ -379,6 +461,42 @@ void Canvas::startGrab() current = this; } +void Canvas::startGrab(const std::vector &canvases) +{ + if (canvases.size() > 0) + { + if (!isMRTSupported()) + throw love::Exception("Multiple render targets are not supported on this system."); + + if (canvases.size() + 1 > maxDrawBuffers || canvases.size() + 1 > maxFBOColorAttachments) + throw love::Exception("This system can't support %d simultanious render targets.", canvases.size() + 1); + } + + for (size_t i = 0; i < canvases.size(); i++) + { + if (canvases[i]->getWidth() != width || canvases[i]->getHeight() != height) + throw love::Exception("All canvas arguments must have the same dimensions."); + } + + startGrab(); + + // don't attach anything if there's nothing to attach/detach + if (canvases.size() == 0 && attachedCanvases.size() == 0) + return; + + strategy->setAttachments(canvases); + + // retain newly attached canvases + for (size_t i = 0; i < canvases.size(); i++) + canvases[i]->retain(); + + // release previously attached canvases + for (size_t i = 0; i < attachedCanvases.size(); i++) + attachedCanvases[i]->release(); + + attachedCanvases = canvases; +} + void Canvas::stopGrab() { // i am not grabbing. leave me alone @@ -393,7 +511,6 @@ void Canvas::stopGrab() current = NULL; } - void Canvas::clear(const Color &c) { GLuint previous = 0; @@ -472,6 +589,11 @@ void Canvas::getPixel(unsigned char* pixel_rgba, int x, int y) strategy->bindFBO( 0 ); } +const std::vector &Canvas::getAttachedCanvases() const +{ + return attachedCanvases; +} + void Canvas::setFilter(const Image::Filter &f) { bindTexture(img); @@ -515,6 +637,12 @@ void Canvas::unloadVolatile() settings.filter = getFilter(); settings.wrap = getWrap(); strategy->deleteFBO(fbo, depth_stencil, img); + + // release attached canvases + for (size_t i = 0; i < attachedCanvases.size(); i++) + attachedCanvases[i]->release(); + + attachedCanvases.clear(); } int Canvas::getWidth() diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index 81162e68e..832df4185 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -21,6 +21,7 @@ #ifndef LOVE_GRAPHICS_OPENGL_CANVAS_H #define LOVE_GRAPHICS_OPENGL_CANVAS_H +// LOVE #include "graphics/DrawQable.h" #include "graphics/Volatile.h" #include "graphics/Image.h" @@ -31,6 +32,9 @@ #include "common/Matrix.h" #include "OpenGL.h" +// STL +#include + namespace love { namespace graphics @@ -50,7 +54,11 @@ public: Canvas(int width, int height, TextureType texture_type = TYPE_NORMAL); virtual ~Canvas(); - void startGrab(); + /** + * @param canvases A list of other canvases to temporarily attach to this one, + * to allow drawing to multiple canvases at once. + **/ + void startGrab(const std::vector &canvases); void stopGrab(); void clear(const Color &c); @@ -66,6 +74,8 @@ public: void getPixel(unsigned char* pixel_rgba, int x, int y); + const std::vector &getAttachedCanvases() const; + void setFilter(const Image::Filter &f); Image::Filter getFilter() const; @@ -89,20 +99,22 @@ public: void unloadVolatile(); static bool isSupported(); - static bool isHdrSupported(); + static bool isHDRSupported(); + static bool isMRTSupported(); static bool getConstant(const char *in, TextureType &out); static bool getConstant(TextureType in, const char *&out); static Canvas *current; static void bindDefaultCanvas(); -private: - friend class Shader; GLuint getTextureName() const { return img; } +private: + friend class Shader; + GLsizei width; GLsizei height; GLuint fbo; @@ -121,6 +133,9 @@ private: Image::Wrap wrap; } settings; + std::vector attachedCanvases; + + void startGrab(); void drawv(const Matrix &t, const vertex *v) const; static StringMap::Entry textureTypeEntries[]; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 1a9802001..3c2fbc6a4 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -397,7 +397,7 @@ ParticleSystem *Graphics::newParticleSystem(Image *image, int size) Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_type) { - if (texture_type == Canvas::TYPE_HDR && !Canvas::isHdrSupported()) + if (texture_type == Canvas::TYPE_HDR && !Canvas::isHDRSupported()) throw Exception("HDR Canvases are not supported by your OpenGL implementation"); while (GL_NO_ERROR != glGetError()) diff --git a/src/modules/graphics/opengl/wrap_Canvas.cpp b/src/modules/graphics/opengl/wrap_Canvas.cpp index 5fe5c5099..aef511e52 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.cpp +++ b/src/modules/graphics/opengl/wrap_Canvas.cpp @@ -47,7 +47,15 @@ int w_Canvas_renderTo(lua_State *L) if (!lua_isfunction(L, 2)) return luaL_error(L, "Need a function to render to canvas."); - canvas->startGrab(); + static std::vector attachments; + try + { + canvas->startGrab(attachments); + } + catch (love::Exception &e) + { + return luaL_error(L, "%s", e.what()); + } lua_settop(L, 2); // make sure the function is on top of the stack lua_call(L, 0, 0); canvas->stopGrab(); diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index f3bb54c54..e8edcee47 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -942,9 +942,41 @@ int w_setCanvas(lua_State *L) return 0; } - Canvas *canvas = luax_checkcanvas(L, 1); - // this unbinds the previous fbo - canvas->startGrab(); + bool is_table = lua_istable(L, 1); + std::vector attachments; + + Canvas *canvas = 0; + + if (is_table) + { + lua_pushinteger(L, 1); + lua_gettable(L, 1); + canvas = luax_checkcanvas(L, -1); + lua_pop(L, 1); + + for (int i = 2; i <= lua_objlen(L, 1); i++) + { + lua_pushinteger(L, i); + lua_gettable(L, 1); + attachments.push_back(luax_checkcanvas(L, -1)); + lua_pop(L, 1); + } + } + else + { + canvas = luax_checkcanvas(L, 1); + for (int i = 2; i <= lua_gettop(L); i++) + attachments.push_back(luax_checkcanvas(L, i)); + } + + try + { + canvas->startGrab(attachments); + } + catch (love::Exception &e) + { + return luaL_error(L, "%s", e.what()); + } return 0; } @@ -952,14 +984,25 @@ int w_setCanvas(lua_State *L) int w_getCanvas(lua_State *L) { Canvas *canvas = Canvas::current; + int n = 1; + if (canvas) { canvas->retain(); luax_newtype(L, "Canvas", GRAPHICS_CANVAS_T, (void *) canvas); + + const std::vector &attachments = canvas->getAttachedCanvases(); + for (size_t i = 0; i < attachments.size(); i++) + { + attachments[i]->retain(); + luax_newtype(L, "Canvas", GRAPHICS_CANVAS_T, (void *) attachments[i]); + n++; + } } else lua_pushnil(L); - return 1; + + return n; } int w_setShader(lua_State *L) @@ -1009,7 +1052,11 @@ int w_isSupported(lua_State *L) supported = false; break; case Graphics::SUPPORT_HDR_CANVAS: - if (!Canvas::isHdrSupported()) + if (!Canvas::isHDRSupported()) + supported = false; + break; + case Graphics::SUPPORT_MRT_CANVAS: + if (!Canvas::isMRTSupported()) supported = false; break; case Graphics::SUPPORT_SHADER: @@ -1427,7 +1474,9 @@ static const luaL_Reg functions[] = { "getMaxPointSize", w_getMaxPointSize }, { "newScreenshot", w_newScreenshot }, { "setCanvas", w_setCanvas }, + { "setCanvases", w_setCanvas }, { "getCanvas", w_getCanvas }, + { "getCanvases", w_getCanvas }, { "setShader", w_setShader }, { "getShader", w_getShader }, diff --git a/src/scripts/graphics.lua b/src/scripts/graphics.lua index e4755cbea..c423b0246 100644 --- a/src/scripts/graphics.lua +++ b/src/scripts/graphics.lua @@ -1295,7 +1295,8 @@ do #define number float #define Image sampler2D #define extern uniform -#define Texel texture2D]] +#define Texel texture2D +#define love_Canvases gl_FragData]] local GLSL_UNIFORMS = [[ #define ModelViewMatrix gl_ModelViewMatrix @@ -1332,10 +1333,17 @@ void main() { FOOTER = [[ void main() { - // fix weird crashing issue in OSX when _tex0_ is unused within effect() + // fix 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); }]], + + FOOTER_MRT = [[ +void main() { + // fix crashing issue in OSX when _tex0_ is unused within effect() + float dummy = texture2D(_tex0_, vec2(.5)).r; + effects(VaryingColor, _tex0_, VaryingTexCoord.st, gl_FragCoord.xy); +}]], } local function createVertexCode(vertexcode) @@ -1349,36 +1357,62 @@ void main() { return table_concat(vertexcodes, "\n") end - local function createPixelCode(pixelcode) + local function createPixelCode(pixelcode, is_mrt) local pixelcodes = { GLSL_VERSION, GLSL_SYNTAX, GLSL_PIXEL.HEADER, GLSL_UNIFORMS, "#line 0", pixelcode, - GLSL_PIXEL.FOOTER + is_mrt and GLSL_PIXEL.FOOTER_MRT or GLSL_PIXEL.FOOTER, } return table_concat(pixelcodes, "\n") end - function love.graphics._shaderCodeToGLSL(vertexcode, pixelcode) - if vertexcode then - local s = vertexcode:gsub("\r\n\t", " ") - s = s:gsub("(%w+)(%s+)%(", "%1(") - if s:match("vec4%s*effect%(") then - pixelcode = vertexcode -- first argument contains pixel shader code + local function isVertexCode(code) + return code:match("vec4%s*position%(") ~= nil + end + + local function isPixelCode(code) + if code:match("vec4%s*effect%(") then + return true + elseif code:match("void%s*effects%(") then -- multiple render targets (MRT) + return true, true + else + return false + end + end + + function love.graphics._shaderCodeToGLSL(arg1, arg2) + local vertexcode, pixelcode + local is_mrt = false -- whether pixel code has "effects" function instead of "effect" + + if arg1 then + local s = arg1:gsub("\r\n\t", " ") -- convert whitespace to spaces for parsing + s = s:gsub("(%w+)(%s+)%(", "%1(") -- convert "func ()" to "func()" + + if isVertexCode(s) then + vertexcode = arg1 -- first arg contains vertex shader code end - if not s:match("vec4%s*position%(") then - vertexcode = nil -- first argument doesn't contain vertex shader code + + local ispixel, isMRT = isPixelCode(s) + if ispixel then + pixelcode = arg1 -- first arg contains pixel shader code + is_mrt = isMRT end end - if pixelcode then - local s = pixelcode:gsub("\r\n\t", " ") - s = s:gsub("(%w+)(%s+)%(", "%1(") - if s:match("vec4%s*position%(") then - vertexcode = pixelcode -- second argument contains vertex shader code + + if arg2 then + local s = arg2:gsub("\r\n\t", " ") -- convert whitespace to spaces for parsing + s = s:gsub("(%w+)(%s+)%(", "%1(") -- convert "func ()" to "func()" + + if isVertexCode(s) then + vertexcode = arg2 -- second arg contains vertex shader code end - if not s:match("vec4%s*effect%(") then - pixelcode = nil -- second argument doesn't contain pixel shader code + + local ispixel, isMRT = isPixelCode(s) + if ispixel then + pixelcode = arg2 -- second arg contains pixel shader code + is_mrt = isMRT end end @@ -1386,7 +1420,7 @@ void main() { vertexcode = createVertexCode(vertexcode) end if pixelcode then - pixelcode = createPixelCode(pixelcode) + pixelcode = createPixelCode(pixelcode, is_mrt) end return vertexcode, pixelcode diff --git a/src/scripts/graphics.lua.h b/src/scripts/graphics.lua.h index 5b41b2c7b..73c5001b7 100644 --- a/src/scripts/graphics.lua.h +++ b/src/scripts/graphics.lua.h @@ -6276,7 +6276,9 @@ const unsigned char graphics_lua[] = 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, 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, 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, @@ -6333,11 +6335,10 @@ const unsigned char graphics_lua[] = 0x6f, 0x72, 0x20, 0x67, 0x6c, 0x5f, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 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, - 0x68, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x4f, 0x53, 0x58, 0x20, - 0x77, 0x68, 0x65, 0x6e, 0x20, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x20, 0x69, 0x73, 0x20, 0x75, 0x6e, 0x75, - 0x73, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x28, - 0x29, 0x0a, + 0x09, 0x2f, 0x2f, 0x20, 0x66, 0x69, 0x78, 0x20, 0x63, 0x72, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x4f, 0x53, 0x58, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x5f, + 0x74, 0x65, 0x78, 0x30, 0x5f, 0x20, 0x69, 0x73, 0x20, 0x75, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x69, 0x6e, 0x20, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x28, 0x29, 0x0a, 0x09, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x32, 0x44, 0x28, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x2c, 0x20, 0x76, 0x65, 0x63, 0x32, 0x28, 0x2e, 0x35, 0x29, 0x29, 0x2e, 0x72, 0x3b, 0x0a, @@ -6347,6 +6348,20 @@ const unsigned char graphics_lua[] = 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, 0x7d, 0x5d, 0x5d, 0x2c, 0x0a, + 0x09, 0x09, 0x46, 0x4f, 0x4f, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x52, 0x54, 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, 0x63, 0x72, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x4f, 0x53, 0x58, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x5f, + 0x74, 0x65, 0x78, 0x30, 0x5f, 0x20, 0x69, 0x73, 0x20, 0x75, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x20, 0x77, 0x69, + 0x74, 0x68, 0x69, 0x6e, 0x20, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x28, 0x29, 0x0a, + 0x09, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x64, 0x75, 0x6d, 0x6d, 0x79, 0x20, 0x3d, 0x20, 0x74, 0x65, 0x78, + 0x74, 0x75, 0x72, 0x65, 0x32, 0x44, 0x28, 0x5f, 0x74, 0x65, 0x78, 0x30, 0x5f, 0x2c, 0x20, 0x76, 0x65, 0x63, + 0x32, 0x28, 0x2e, 0x35, 0x29, 0x29, 0x2e, 0x72, 0x3b, 0x0a, + 0x09, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 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, + 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, 0x65, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x76, 0x65, 0x72, @@ -6368,7 +6383,7 @@ const unsigned char graphics_lua[] = 0x09, 0x65, 0x6e, 0x64, 0x0a, 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, 0x29, 0x0a, + 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x73, 0x5f, 0x6d, 0x72, 0x74, 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, @@ -6377,65 +6392,104 @@ const unsigned char graphics_lua[] = 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, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x2e, 0x46, 0x4f, 0x4f, 0x54, - 0x45, 0x52, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x73, 0x5f, 0x6d, 0x72, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x4c, 0x53, 0x4c, + 0x5f, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x2e, 0x46, 0x4f, 0x4f, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x52, 0x54, 0x20, + 0x6f, 0x72, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 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, 0x63, 0x61, 0x74, 0x28, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x2c, 0x20, 0x22, 0x5c, 0x6e, 0x22, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, + 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, + 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3a, 0x6d, 0x61, 0x74, 0x63, + 0x68, 0x28, 0x22, 0x76, 0x65, 0x63, 0x34, 0x25, 0x73, 0x2a, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x25, 0x28, 0x22, 0x29, 0x20, 0x7e, 0x3d, 0x20, 0x6e, 0x69, 0x6c, 0x0a, + 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x73, + 0x50, 0x69, 0x78, 0x65, 0x6c, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, + 0x09, 0x09, 0x69, 0x66, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28, 0x22, 0x76, + 0x65, 0x63, 0x34, 0x25, 0x73, 0x2a, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x25, 0x28, 0x22, 0x29, 0x20, 0x74, + 0x68, 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, + 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3a, 0x6d, 0x61, 0x74, 0x63, + 0x68, 0x28, 0x22, 0x76, 0x6f, 0x69, 0x64, 0x25, 0x73, 0x2a, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x25, + 0x28, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x2d, 0x2d, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, + 0x6c, 0x65, 0x20, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x20, + 0x28, 0x4d, 0x52, 0x54, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x20, 0x74, 0x72, + 0x75, 0x65, 0x0a, + 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a, + 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a, + 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x54, - 0x6f, 0x47, 0x4c, 0x53, 0x4c, 0x28, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, - 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x29, 0x0a, - 0x09, 0x09, 0x69, 0x66, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, - 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, - 0x78, 0x63, 0x6f, 0x64, 0x65, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x5c, 0x72, 0x5c, 0x6e, 0x5c, 0x74, - 0x22, 0x2c, 0x20, 0x22, 0x20, 0x22, 0x29, 0x0a, + 0x6f, 0x47, 0x4c, 0x53, 0x4c, 0x28, 0x61, 0x72, 0x67, 0x31, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x32, 0x29, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, + 0x2c, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x0a, + 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x73, 0x5f, 0x6d, 0x72, 0x74, 0x20, 0x3d, 0x20, 0x66, + 0x61, 0x6c, 0x73, 0x65, 0x20, 0x2d, 0x2d, 0x20, 0x77, 0x68, 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x70, 0x69, + 0x78, 0x65, 0x6c, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x68, 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, 0x69, 0x66, 0x20, 0x61, 0x72, 0x67, 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x61, 0x72, 0x67, 0x31, 0x3a, + 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x5c, 0x72, 0x5c, 0x6e, 0x5c, 0x74, 0x22, 0x2c, 0x20, 0x22, 0x20, 0x22, + 0x29, 0x20, 0x2d, 0x2d, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x70, 0x61, 0x72, 0x73, 0x69, 0x6e, 0x67, 0x0a, 0x09, 0x09, 0x09, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x28, 0x25, 0x77, - 0x2b, 0x29, 0x28, 0x25, 0x73, 0x2b, 0x29, 0x25, 0x28, 0x22, 0x2c, 0x20, 0x22, 0x25, 0x31, 0x28, 0x22, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x73, 0x3a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28, 0x22, 0x76, 0x65, 0x63, - 0x34, 0x25, 0x73, 0x2a, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x25, 0x28, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, - 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x76, 0x65, - 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x2d, 0x2d, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, - 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, - 0x70, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, + 0x2b, 0x29, 0x28, 0x25, 0x73, 0x2b, 0x29, 0x25, 0x28, 0x22, 0x2c, 0x20, 0x22, 0x25, 0x31, 0x28, 0x22, 0x29, + 0x20, 0x2d, 0x2d, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x20, 0x22, 0x66, 0x75, 0x6e, 0x63, 0x20, + 0x28, 0x29, 0x22, 0x20, 0x74, 0x6f, 0x20, 0x22, 0x66, 0x75, 0x6e, 0x63, 0x28, 0x29, 0x22, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x69, 0x73, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x64, 0x65, + 0x28, 0x73, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x61, + 0x72, 0x67, 0x31, 0x20, 0x2d, 0x2d, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x61, 0x72, 0x67, 0x20, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x20, 0x73, 0x68, 0x61, + 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x3a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28, - 0x22, 0x76, 0x65, 0x63, 0x34, 0x25, 0x73, 0x2a, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x25, 0x28, - 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x6e, - 0x69, 0x6c, 0x20, 0x2d, 0x2d, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, - 0x6e, 0x74, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, - 0x65, 0x0a, + 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x73, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x2c, 0x20, + 0x69, 0x73, 0x4d, 0x52, 0x54, 0x20, 0x3d, 0x20, 0x69, 0x73, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x43, 0x6f, 0x64, + 0x65, 0x28, 0x73, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x69, 0x73, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x61, 0x72, + 0x67, 0x31, 0x20, 0x2d, 0x2d, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x61, 0x72, 0x67, 0x20, 0x63, 0x6f, + 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, + 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x69, 0x73, 0x5f, 0x6d, 0x72, 0x74, 0x20, 0x3d, 0x20, 0x69, 0x73, 0x4d, 0x52, 0x54, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 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, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, - 0x63, 0x6f, 0x64, 0x65, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x5c, 0x72, 0x5c, 0x6e, 0x5c, 0x74, 0x22, - 0x2c, 0x20, 0x22, 0x20, 0x22, 0x29, 0x0a, + 0x09, 0x09, 0x0a, + 0x09, 0x09, 0x69, 0x66, 0x20, 0x61, 0x72, 0x67, 0x32, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x61, 0x72, 0x67, 0x32, 0x3a, + 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x5c, 0x72, 0x5c, 0x6e, 0x5c, 0x74, 0x22, 0x2c, 0x20, 0x22, 0x20, 0x22, + 0x29, 0x20, 0x2d, 0x2d, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x70, 0x61, 0x72, 0x73, 0x69, 0x6e, 0x67, 0x0a, 0x09, 0x09, 0x09, 0x73, 0x20, 0x3d, 0x20, 0x73, 0x3a, 0x67, 0x73, 0x75, 0x62, 0x28, 0x22, 0x28, 0x25, 0x77, - 0x2b, 0x29, 0x28, 0x25, 0x73, 0x2b, 0x29, 0x25, 0x28, 0x22, 0x2c, 0x20, 0x22, 0x25, 0x31, 0x28, 0x22, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x73, 0x3a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28, 0x22, 0x76, 0x65, 0x63, - 0x34, 0x25, 0x73, 0x2a, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x25, 0x28, 0x22, 0x29, 0x20, 0x74, - 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x70, - 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, - 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, - 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, - 0x65, 0x0a, + 0x2b, 0x29, 0x28, 0x25, 0x73, 0x2b, 0x29, 0x25, 0x28, 0x22, 0x2c, 0x20, 0x22, 0x25, 0x31, 0x28, 0x22, 0x29, + 0x20, 0x2d, 0x2d, 0x20, 0x63, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x20, 0x22, 0x66, 0x75, 0x6e, 0x63, 0x20, + 0x28, 0x29, 0x22, 0x20, 0x74, 0x6f, 0x20, 0x22, 0x66, 0x75, 0x6e, 0x63, 0x28, 0x29, 0x22, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x69, 0x73, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x64, 0x65, + 0x28, 0x73, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x61, + 0x72, 0x67, 0x32, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x61, 0x72, 0x67, 0x20, + 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x20, 0x73, 0x68, + 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x3a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28, - 0x22, 0x76, 0x65, 0x63, 0x34, 0x25, 0x73, 0x2a, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x25, 0x28, 0x22, 0x29, - 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x6e, 0x69, - 0x6c, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, - 0x6e, 0x74, 0x20, 0x64, 0x6f, 0x65, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, - 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, + 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x73, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x2c, 0x20, + 0x69, 0x73, 0x4d, 0x52, 0x54, 0x20, 0x3d, 0x20, 0x69, 0x73, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x43, 0x6f, 0x64, + 0x65, 0x28, 0x73, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x69, 0x73, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x61, 0x72, + 0x67, 0x32, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x61, 0x72, 0x67, 0x20, 0x63, + 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x73, 0x68, 0x61, 0x64, + 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x69, 0x73, 0x5f, 0x6d, 0x72, 0x74, 0x20, 0x3d, 0x20, 0x69, 0x73, 0x4d, 0x52, 0x54, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, @@ -6448,7 +6502,7 @@ const unsigned char graphics_lua[] = 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, 0x29, 0x0a, + 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x73, 0x5f, 0x6d, 0x72, 0x74, 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, From 6c5daab312d7724e3584cf1b8c1776edc2394a93 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 25 Mar 2013 21:23:09 -0300 Subject: [PATCH 2/3] Fixed up the API: setCanvas (singular) now only takes one canvas, setCanvases must be used for multi-canvas rendering --HG-- branch : MRTs --- src/modules/graphics/opengl/Canvas.cpp | 48 ++++++++++++++++--- src/modules/graphics/opengl/Canvas.h | 3 +- src/modules/graphics/opengl/wrap_Canvas.cpp | 3 +- src/modules/graphics/opengl/wrap_Graphics.cpp | 30 +++++++++++- src/modules/graphics/opengl/wrap_Graphics.h | 1 + 5 files changed, 74 insertions(+), 11 deletions(-) diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index b19947b4b..a8e283635 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -60,11 +60,14 @@ struct FramebufferStrategy virtual void deleteFBO(GLuint, GLuint, GLuint) {} virtual void bindFBO(GLuint) {} - /// attach additional canvases to this framebuffer for rendering + /// attach additional canvases to the active framebuffer for rendering /** * @param[in] canvases List of canvases to attach **/ virtual void setAttachments(const std::vector &canvases) {} + + /// stop using all additional attached canvases + virtual void setAttachments() {} }; struct FramebufferStrategyGL3 : public FramebufferStrategy @@ -134,12 +137,17 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); } + virtual void setAttachments() + { + // set a single render target + glDrawBuffer(GL_COLOR_ATTACHMENT0); + } + virtual void setAttachments(const std::vector &canvases) { if (canvases.size() == 0) { - // set a single render target - glDrawBuffer(GL_COLOR_ATTACHMENT0); + setAttachments(); return; } @@ -232,12 +240,17 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer); } + virtual void setAttachments() + { + // set a single render target + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + } + virtual void setAttachments(const std::vector &canvases) { if (canvases.size() == 0) { - // set a single render target - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + setAttachments(); return; } @@ -431,7 +444,7 @@ void Canvas::bindDefaultCanvas() current->stopGrab(); } -void Canvas::startGrab() +void Canvas::setupGrab() { // already grabbing if (current == this) @@ -476,14 +489,18 @@ void Canvas::startGrab(const std::vector &canvases) { if (canvases[i]->getWidth() != width || canvases[i]->getHeight() != height) throw love::Exception("All canvas arguments must have the same dimensions."); + + if (canvases[i]->getTextureType() != texture_type) + throw love::Exception("All canvas arguments must have the same texture type."); } - startGrab(); + setupGrab(); // don't attach anything if there's nothing to attach/detach if (canvases.size() == 0 && attachedCanvases.size() == 0) return; + // attach the canvas textures to this FBO and set up multiple render targets strategy->setAttachments(canvases); // retain newly attached canvases @@ -497,6 +514,23 @@ void Canvas::startGrab(const std::vector &canvases) attachedCanvases = canvases; } +void Canvas::startGrab() +{ + setupGrab(); + + if (attachedCanvases.size() == 0) + return; + + // make sure the FBO is only using a single render target + strategy->setAttachments(); + + // release any previously attached canvases + for (size_t i = 0; i < attachedCanvases.size(); i++) + attachedCanvases[i]->release(); + + attachedCanvases.clear(); +} + void Canvas::stopGrab() { // i am not grabbing. leave me alone diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index 832df4185..44a63a962 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -59,6 +59,7 @@ public: * to allow drawing to multiple canvases at once. **/ void startGrab(const std::vector &canvases); + void startGrab(); void stopGrab(); void clear(const Color &c); @@ -135,7 +136,7 @@ private: std::vector attachedCanvases; - void startGrab(); + void setupGrab(); void drawv(const Matrix &t, const vertex *v) const; static StringMap::Entry textureTypeEntries[]; diff --git a/src/modules/graphics/opengl/wrap_Canvas.cpp b/src/modules/graphics/opengl/wrap_Canvas.cpp index aef511e52..991dc8b66 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.cpp +++ b/src/modules/graphics/opengl/wrap_Canvas.cpp @@ -47,10 +47,9 @@ int w_Canvas_renderTo(lua_State *L) if (!lua_isfunction(L, 2)) return luaL_error(L, "Need a function to render to canvas."); - static std::vector attachments; try { - canvas->startGrab(attachments); + canvas->startGrab(); } catch (love::Exception &e) { diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index e8edcee47..a69407354 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -942,6 +942,34 @@ int w_setCanvas(lua_State *L) return 0; } + Canvas *canvas = luax_checkcanvas(L, 1); + + try + { + // this unbinds the previous fbo + canvas->startGrab(); + } + catch (love::Exception &e) + { + return luaL_error(L, "%s", e.what()); + } + + return 0; +} + +int w_setCanvases(lua_State *L) +{ + // discard stencil testing + instance->discardStencil(); + + // called with none -> reset to default buffer + // nil is an error, to help people with typoes + if (lua_isnone(L,1)) + { + Canvas::bindDefaultCanvas(); + return 0; + } + bool is_table = lua_istable(L, 1); std::vector attachments; @@ -1474,7 +1502,7 @@ static const luaL_Reg functions[] = { "getMaxPointSize", w_getMaxPointSize }, { "newScreenshot", w_newScreenshot }, { "setCanvas", w_setCanvas }, - { "setCanvases", w_setCanvas }, + { "setCanvases", w_setCanvases }, { "getCanvas", w_getCanvas }, { "getCanvases", w_getCanvas }, diff --git a/src/modules/graphics/opengl/wrap_Graphics.h b/src/modules/graphics/opengl/wrap_Graphics.h index 1d4dea8a3..89f7c68bb 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.h +++ b/src/modules/graphics/opengl/wrap_Graphics.h @@ -90,6 +90,7 @@ int w_getPointStyle(lua_State *L); int w_getMaxPointSize(lua_State *L); int w_newScreenshot(lua_State *L); int w_setCanvas(lua_State *L); +int w_setCanvases(lua_State *L); int w_getCanvas(lua_State *L); int w_setShader(lua_State *L); int w_getShader(lua_State *L); From a55c7e871e1968bddfc3c97e7b2eda62cc3602b1 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 26 Mar 2013 04:58:43 -0300 Subject: [PATCH 3/3] fixed canvas:clear() when multi-canvas rendering is active, changed some names and wording --HG-- branch : MRTs --- src/modules/graphics/Graphics.cpp | 2 +- src/modules/graphics/Graphics.h | 2 +- src/modules/graphics/opengl/Canvas.cpp | 43 ++++++++++------ src/modules/graphics/opengl/Canvas.h | 2 +- src/modules/graphics/opengl/wrap_Graphics.cpp | 4 +- src/scripts/graphics.lua | 20 ++++---- src/scripts/graphics.lua.h | 49 +++++++++++-------- 7 files changed, 72 insertions(+), 50 deletions(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index dc79f7299..682650568 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -158,7 +158,7 @@ StringMap::Entry Graphics::suppor { { "canvas", Graphics::SUPPORT_CANVAS }, { "hdrcanvas", Graphics::SUPPORT_HDR_CANVAS }, - { "mrtcanvas", Graphics::SUPPORT_MRT_CANVAS }, + { "multicanvas", Graphics::SUPPORT_MULTI_CANVAS }, { "shader", Graphics::SUPPORT_SHADER }, { "npot", Graphics::SUPPORT_NPOT }, { "subtractive", Graphics::SUPPORT_SUBTRACTIVE }, diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 29212e2d8..e2c73ae62 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -87,7 +87,7 @@ public: { SUPPORT_CANVAS = 1, SUPPORT_HDR_CANVAS, - SUPPORT_MRT_CANVAS, + SUPPORT_MULTI_CANVAS, SUPPORT_SHADER, SUPPORT_NPOT, SUPPORT_SUBTRACTIVE, diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index a8e283635..04361ff74 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -423,7 +423,7 @@ bool Canvas::isHDRSupported() return GLEE_VERSION_3_0 || GLEE_ARB_texture_float; } -bool Canvas::isMRTSupported() +bool Canvas::isMultiCanvasSupported() { if (!(isSupported() && (GLEE_VERSION_2_0 || GLEE_ARB_draw_buffers || GLEE_ATI_draw_buffers))) return false; @@ -434,7 +434,7 @@ bool Canvas::isMRTSupported() glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); } - // system must support at least 4 simultanious render targets + // system must support at least 4 simultanious active canvases return maxFBOColorAttachments >= 4 && maxDrawBuffers >= 4; } @@ -478,11 +478,11 @@ void Canvas::startGrab(const std::vector &canvases) { if (canvases.size() > 0) { - if (!isMRTSupported()) - throw love::Exception("Multiple render targets are not supported on this system."); + if (!isMultiCanvasSupported()) + throw love::Exception("Multi-canvas rendering is not supported on this system."); - if (canvases.size() + 1 > maxDrawBuffers || canvases.size() + 1 > maxFBOColorAttachments) - throw love::Exception("This system can't support %d simultanious render targets.", canvases.size() + 1); + if (canvases.size()+1 > maxDrawBuffers || canvases.size()+1 > maxFBOColorAttachments) + throw love::Exception("This system can't simultaniously render to %d canvases.", canvases.size()+1); } for (size_t i = 0; i < canvases.size(); i++) @@ -500,7 +500,7 @@ void Canvas::startGrab(const std::vector &canvases) if (canvases.size() == 0 && attachedCanvases.size() == 0) return; - // attach the canvas textures to this FBO and set up multiple render targets + // attach the canvas textures to the active FBO and set up multiple render targets strategy->setAttachments(canvases); // retain newly attached canvases @@ -521,7 +521,7 @@ void Canvas::startGrab() if (attachedCanvases.size() == 0) return; - // make sure the FBO is only using a single render target + // make sure the FBO is only using a single canvas strategy->setAttachments(); // release any previously attached canvases @@ -548,16 +548,31 @@ void Canvas::stopGrab() void Canvas::clear(const Color &c) { GLuint previous = 0; - if (current != NULL) - previous = current->fbo; - strategy->bindFBO(fbo); - glPushAttrib(GL_COLOR_BUFFER_BIT); + if (current != this) + { + if (current != NULL) + previous = current->fbo; + + strategy->bindFBO(fbo); + glPushAttrib(GL_COLOR_BUFFER_BIT); + } + + // Make sure only this canvas is cleared when multi-canvas rendering is set + if (attachedCanvases.size() > 0) + strategy->setAttachments(); + glClearColor((float)c.r/255.0f, (float)c.g/255.0f, (float)c.b/255.0f, (float)c.a/255.0f); glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - glPopAttrib(); - strategy->bindFBO(previous); + if (attachedCanvases.size() > 0) + strategy->setAttachments(attachedCanvases); + + if (current != this) + { + glPopAttrib(); + strategy->bindFBO(previous); + } } void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index 44a63a962..b7b071bbe 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -101,7 +101,7 @@ public: static bool isSupported(); static bool isHDRSupported(); - static bool isMRTSupported(); + static bool isMultiCanvasSupported(); static bool getConstant(const char *in, TextureType &out); static bool getConstant(TextureType in, const char *&out); diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index a69407354..90cfc7649 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -1083,8 +1083,8 @@ int w_isSupported(lua_State *L) if (!Canvas::isHDRSupported()) supported = false; break; - case Graphics::SUPPORT_MRT_CANVAS: - if (!Canvas::isMRTSupported()) + case Graphics::SUPPORT_MULTI_CANVAS: + if (!Canvas::isMultiCanvasSupported()) supported = false; break; case Graphics::SUPPORT_SHADER: diff --git a/src/scripts/graphics.lua b/src/scripts/graphics.lua index c423b0246..1a318b9a6 100644 --- a/src/scripts/graphics.lua +++ b/src/scripts/graphics.lua @@ -1338,7 +1338,7 @@ void main() { gl_FragColor = effect(VaryingColor, _tex0_, VaryingTexCoord.st, gl_FragCoord.xy); }]], - FOOTER_MRT = [[ + FOOTER_MULTI_CANVAS = [[ void main() { // fix crashing issue in OSX when _tex0_ is unused within effect() float dummy = texture2D(_tex0_, vec2(.5)).r; @@ -1357,13 +1357,13 @@ void main() { return table_concat(vertexcodes, "\n") end - local function createPixelCode(pixelcode, is_mrt) + local function createPixelCode(pixelcode, is_multicanvas) local pixelcodes = { GLSL_VERSION, GLSL_SYNTAX, GLSL_PIXEL.HEADER, GLSL_UNIFORMS, "#line 0", pixelcode, - is_mrt and GLSL_PIXEL.FOOTER_MRT or GLSL_PIXEL.FOOTER, + is_multicanvas and GLSL_PIXEL.FOOTER_MULTI_CANVAS or GLSL_PIXEL.FOOTER, } return table_concat(pixelcodes, "\n") end @@ -1375,7 +1375,7 @@ void main() { local function isPixelCode(code) if code:match("vec4%s*effect%(") then return true - elseif code:match("void%s*effects%(") then -- multiple render targets (MRT) + elseif code:match("void%s*effects%(") then -- render to multiple canvases simultaniously return true, true else return false @@ -1384,7 +1384,7 @@ void main() { function love.graphics._shaderCodeToGLSL(arg1, arg2) local vertexcode, pixelcode - local is_mrt = false -- whether pixel code has "effects" function instead of "effect" + local is_multicanvas = false -- whether pixel code has "effects" function instead of "effect" if arg1 then local s = arg1:gsub("\r\n\t", " ") -- convert whitespace to spaces for parsing @@ -1394,10 +1394,10 @@ void main() { vertexcode = arg1 -- first arg contains vertex shader code end - local ispixel, isMRT = isPixelCode(s) + local ispixel, isMultiCanvas = isPixelCode(s) if ispixel then pixelcode = arg1 -- first arg contains pixel shader code - is_mrt = isMRT + is_multicanvas = isMultiCanvas end end @@ -1409,10 +1409,10 @@ void main() { vertexcode = arg2 -- second arg contains vertex shader code end - local ispixel, isMRT = isPixelCode(s) + local ispixel, isMultiCanvas = isPixelCode(s) if ispixel then pixelcode = arg2 -- second arg contains pixel shader code - is_mrt = isMRT + is_multicanvas = isMultiCanvas end end @@ -1420,7 +1420,7 @@ void main() { vertexcode = createVertexCode(vertexcode) end if pixelcode then - pixelcode = createPixelCode(pixelcode, is_mrt) + pixelcode = createPixelCode(pixelcode, is_multicanvas) end return vertexcode, pixelcode diff --git a/src/scripts/graphics.lua.h b/src/scripts/graphics.lua.h index 73c5001b7..e2f2752fb 100644 --- a/src/scripts/graphics.lua.h +++ b/src/scripts/graphics.lua.h @@ -6348,7 +6348,8 @@ const unsigned char graphics_lua[] = 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, 0x7d, 0x5d, 0x5d, 0x2c, 0x0a, - 0x09, 0x09, 0x46, 0x4f, 0x4f, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x52, 0x54, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, + 0x09, 0x09, 0x46, 0x4f, 0x4f, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x5f, 0x43, 0x41, 0x4e, + 0x56, 0x41, 0x53, 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, 0x63, 0x72, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x73, 0x73, 0x75, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x4f, 0x53, 0x58, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x5f, @@ -6383,7 +6384,8 @@ const unsigned char graphics_lua[] = 0x09, 0x65, 0x6e, 0x64, 0x0a, 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, 0x72, 0x74, 0x29, 0x0a, + 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x73, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x63, 0x61, 0x6e, + 0x76, 0x61, 0x73, 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, @@ -6392,10 +6394,11 @@ const unsigned char graphics_lua[] = 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, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x0a, - 0x09, 0x09, 0x09, 0x69, 0x73, 0x5f, 0x6d, 0x72, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x4c, 0x53, 0x4c, - 0x5f, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x2e, 0x46, 0x4f, 0x4f, 0x54, 0x45, 0x52, 0x5f, 0x4d, 0x52, 0x54, 0x20, - 0x6f, 0x72, 0x20, 0x47, 0x4c, 0x53, 0x4c, 0x5f, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x2e, 0x46, 0x4f, 0x4f, 0x54, - 0x45, 0x52, 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, + 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, + 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, 0x63, 0x61, 0x74, 0x28, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x2c, 0x20, 0x22, 0x5c, @@ -6415,9 +6418,9 @@ const unsigned char graphics_lua[] = 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x69, 0x66, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x3a, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x28, 0x22, 0x76, 0x6f, 0x69, 0x64, 0x25, 0x73, 0x2a, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x25, - 0x28, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x2d, 0x2d, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, - 0x6c, 0x65, 0x20, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x20, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x20, - 0x28, 0x4d, 0x52, 0x54, 0x29, 0x0a, + 0x28, 0x22, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x2d, 0x2d, 0x20, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, + 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x63, 0x61, 0x6e, 0x76, 0x61, + 0x73, 0x65, 0x73, 0x20, 0x73, 0x69, 0x6d, 0x75, 0x6c, 0x74, 0x61, 0x6e, 0x69, 0x6f, 0x75, 0x73, 0x6c, 0x79, 0x0a, 0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x20, 0x74, 0x72, 0x75, 0x65, 0x0a, 0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a, @@ -6429,11 +6432,12 @@ const unsigned char graphics_lua[] = 0x6f, 0x47, 0x4c, 0x53, 0x4c, 0x28, 0x61, 0x72, 0x67, 0x31, 0x2c, 0x20, 0x61, 0x72, 0x67, 0x32, 0x29, 0x0a, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x0a, - 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x73, 0x5f, 0x6d, 0x72, 0x74, 0x20, 0x3d, 0x20, 0x66, - 0x61, 0x6c, 0x73, 0x65, 0x20, 0x2d, 0x2d, 0x20, 0x77, 0x68, 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x70, 0x69, - 0x78, 0x65, 0x6c, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x68, 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, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x73, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x63, 0x61, + 0x6e, 0x76, 0x61, 0x73, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x20, 0x2d, 0x2d, 0x20, 0x77, 0x68, + 0x65, 0x74, 0x68, 0x65, 0x72, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x68, + 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, 0x69, 0x66, 0x20, 0x61, 0x72, 0x67, 0x31, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x20, 0x3d, 0x20, 0x61, 0x72, 0x67, 0x31, 0x3a, @@ -6453,14 +6457,15 @@ const unsigned char graphics_lua[] = 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x73, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x2c, 0x20, - 0x69, 0x73, 0x4d, 0x52, 0x54, 0x20, 0x3d, 0x20, 0x69, 0x73, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x43, 0x6f, 0x64, - 0x65, 0x28, 0x73, 0x29, 0x0a, + 0x69, 0x73, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x20, 0x3d, 0x20, 0x69, 0x73, + 0x50, 0x69, 0x78, 0x65, 0x6c, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x73, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x69, 0x73, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x61, 0x72, 0x67, 0x31, 0x20, 0x2d, 0x2d, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x61, 0x72, 0x67, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x69, 0x73, 0x5f, 0x6d, 0x72, 0x74, 0x20, 0x3d, 0x20, 0x69, 0x73, 0x4d, 0x52, 0x54, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x69, 0x73, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x63, 0x61, 0x6e, 0x76, 0x61, 0x73, + 0x20, 0x3d, 0x20, 0x69, 0x73, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x0a, @@ -6482,14 +6487,15 @@ const unsigned char graphics_lua[] = 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x73, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x2c, 0x20, - 0x69, 0x73, 0x4d, 0x52, 0x54, 0x20, 0x3d, 0x20, 0x69, 0x73, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x43, 0x6f, 0x64, - 0x65, 0x28, 0x73, 0x29, 0x0a, + 0x69, 0x73, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x20, 0x3d, 0x20, 0x69, 0x73, + 0x50, 0x69, 0x78, 0x65, 0x6c, 0x43, 0x6f, 0x64, 0x65, 0x28, 0x73, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x69, 0x73, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x3d, 0x20, 0x61, 0x72, 0x67, 0x32, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x61, 0x72, 0x67, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x73, 0x20, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x0a, - 0x09, 0x09, 0x09, 0x09, 0x69, 0x73, 0x5f, 0x6d, 0x72, 0x74, 0x20, 0x3d, 0x20, 0x69, 0x73, 0x4d, 0x52, 0x54, 0x0a, + 0x09, 0x09, 0x09, 0x09, 0x69, 0x73, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x63, 0x61, 0x6e, 0x76, 0x61, 0x73, + 0x20, 0x3d, 0x20, 0x69, 0x73, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x43, 0x61, 0x6e, 0x76, 0x61, 0x73, 0x0a, 0x09, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x74, 0x68, @@ -6502,7 +6508,8 @@ const unsigned char graphics_lua[] = 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, 0x72, 0x74, 0x29, 0x0a, + 0x63, 0x6f, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x73, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x63, 0x61, 0x6e, 0x76, + 0x61, 0x73, 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,