Fix conflicts with default

--HG--
branch : sounddata-samplecount
This commit is contained in:
darthfodder
2013-04-07 18:22:56 -07:00
39 changed files with 50112 additions and 45013 deletions
+8
View File
@@ -20,6 +20,7 @@ LOVE 0.9.0 []
* Added support for UTF-8 ImageFonts.
* Added SoundData:getDuration.
* Added new Channels api for love.thread.
* Added Thread:getError.
* Added flags to setMode.
* Added support for resizable, borderless, and non-centered windows.
* Added resize event.
@@ -35,6 +36,11 @@ LOVE 0.9.0 []
* Added love.graphics.getDimensions and Image/Canvas/ImageData:getDimensions.
* Added love.filesystem.append.
* Added love.filesystem.getSize.
* Added angle, scale, and shear parameters to love.graphics.printf.
* Added anisotropic filtering support for Images, Canvases, and Fonts.
* Added love.graphics.setCanvases.
* Added ParticleSystem:emit.
* Added love.graphics.setColorMask.
* OPTIONAL: Added support for GME.
* Fixed crashes with font drawing on some ATI cards.
@@ -65,6 +71,7 @@ LOVE 0.9.0 []
* Renamed love's boot script to 'love.boot', which can be required.
* Renamed PixelEffect to Shader (but now with vertex shaders).
* Renamed love.graphics.setDefaultImageFilter to love.graphics.setDefaultFilter.
* Removed love.joystick.open and friends.
* Removed love.graphics.drawTest.
@@ -86,6 +93,7 @@ LOVE 0.9.0 []
* Updated Canvas code to support more systems.
* Updated love.timer.getFPS to be microsecond-accurate.
* Updated love.graphics.newScreenshot to create a fully opaque image by default.
* Updated ImageData:setPixel's alpha parameter to default to 255.
LOVE 0.8.0 [Rubber Piggy]
-------------------------
-2
View File
@@ -56,7 +56,6 @@ enum Type
// Image
IMAGE_IMAGE_DATA_ID,
IMAGE_ENCODED_IMAGE_DATA_ID,
// Audio
AUDIO_SOURCE_ID,
@@ -128,7 +127,6 @@ const bits GRAPHICS_SHADER_T = (bits(1) << GRAPHICS_SHADER_ID) | OBJECT_T;
// Image.
const bits IMAGE_IMAGE_DATA_T = (bits(1) << IMAGE_IMAGE_DATA_ID) | DATA_T;
const bits IMAGE_ENCODED_IMAGE_DATA_T = (bits(1) << IMAGE_ENCODED_IMAGE_DATA_ID) | DATA_T;
// Audio.
const bits AUDIO_SOURCE_T = (bits(1) << AUDIO_SOURCE_ID) | OBJECT_T;
+1 -1
View File
@@ -28,7 +28,7 @@ namespace love
namespace event
{
Message::Message(std::string name, Variant *a, Variant *b, Variant *c, Variant *d)
Message::Message(const std::string &name, Variant *a, Variant *b, Variant *c, Variant *d)
: name(name)
, nargs(0)
{
+1 -1
View File
@@ -45,7 +45,7 @@ private:
int nargs;
public:
Message(std::string name, Variant *a = NULL, Variant *b = NULL, Variant *c = NULL, Variant *d = NULL);
Message(const std::string &name, Variant *a = NULL, Variant *b = NULL, Variant *c = NULL, Variant *d = NULL);
~Message();
int toLua(lua_State *L);
+1 -1
View File
@@ -36,7 +36,7 @@ namespace physfs
extern bool hack_setupWriteDirectory();
File::File(std::string filename)
File::File(const std::string &filename)
: filename(filename)
, file(0)
, mode(filesystem::File::CLOSED)
+1 -1
View File
@@ -61,7 +61,7 @@ public:
* @param source The source from which to load the file. (Archive or directory)
* @param filename The relative filepath of the file to load from the source.
**/
File(std::string filename);
File(const std::string &filename);
virtual ~File();
+3 -14
View File
@@ -343,28 +343,17 @@ void Filesystem::append(const char *filename, const void *data, int64 size) cons
int Filesystem::enumerate(lua_State *L)
{
int n = lua_gettop(L);
const char *dir = luaL_checkstring(L, 1);
if (n != 1)
return luaL_error(L, "Function requires a single parameter.");
int type = lua_type(L, 1);
if (type != LUA_TSTRING)
return luaL_error(L, "Function requires parameter of type string.");
const char *dir = lua_tostring(L, 1);
char **rc = PHYSFS_enumerateFiles(dir);
char **i;
int index = 1;
lua_newtable(L);
for (i = rc; *i != 0; i++)
for (char **i = rc; *i != 0; i++)
{
lua_pushinteger(L, index);
lua_pushstring(L, *i);
lua_settable(L, -3);
lua_rawseti(L, -2, index);
index++;
}
+1
View File
@@ -158,6 +158,7 @@ StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::suppor
{
{ "canvas", Graphics::SUPPORT_CANVAS },
{ "hdrcanvas", Graphics::SUPPORT_HDR_CANVAS },
{ "multicanvas", Graphics::SUPPORT_MULTI_CANVAS },
{ "shader", Graphics::SUPPORT_SHADER },
{ "npot", Graphics::SUPPORT_NPOT },
{ "subtractive", Graphics::SUPPORT_SUBTRACTIVE },
+1
View File
@@ -87,6 +87,7 @@ public:
{
SUPPORT_CANVAS = 1,
SUPPORT_HDR_CANVAS,
SUPPORT_MULTI_CANVAS,
SUPPORT_SHADER,
SUPPORT_NPOT,
SUPPORT_SUBTRACTIVE,
+185 -9
View File
@@ -59,6 +59,15 @@ struct FramebufferStrategy
*/
virtual void deleteFBO(GLuint, GLuint, GLuint) {}
virtual void bindFBO(GLuint) {}
/// attach additional canvases to the active framebuffer for rendering
/**
* @param[in] canvases List of canvases to attach
**/
virtual void setAttachments(const std::vector<Canvas *> &canvases) {}
/// stop using all additional attached canvases
virtual void setAttachments() {}
};
struct FramebufferStrategyGL3 : public FramebufferStrategy
@@ -127,6 +136,40 @@ 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<Canvas *> &canvases)
{
if (canvases.size() == 0)
{
setAttachments();
return;
}
std::vector<GLenum> 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 +239,40 @@ 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<Canvas *> &canvases)
{
if (canvases.size() == 0)
{
setAttachments();
return;
}
std::vector<GLenum> 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 +365,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,18 +418,33 @@ bool Canvas::isSupported()
return (strategy != &strategyNone);
}
bool Canvas::isHdrSupported()
bool Canvas::isHDRSupported()
{
return GLEE_VERSION_3_0 || GLEE_ARB_texture_float;
}
bool Canvas::isMultiCanvasSupported()
{
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 active canvases
return maxFBOColorAttachments >= 4 && maxDrawBuffers >= 4;
}
void Canvas::bindDefaultCanvas()
{
if (current != NULL)
current->stopGrab();
}
void Canvas::startGrab()
void Canvas::setupGrab()
{
// already grabbing
if (current == this)
@@ -379,6 +474,63 @@ void Canvas::startGrab()
current = this;
}
void Canvas::startGrab(const std::vector<Canvas *> &canvases)
{
if (canvases.size() > 0)
{
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 simultaniously render to %d canvases.", 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.");
if (canvases[i]->getTextureType() != texture_type)
throw love::Exception("All canvas arguments must have the same texture type.");
}
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 the active FBO and set up multiple render targets
strategy->setAttachments(canvases);
// retain newly attached canvases
for (size_t i = 0; i < canvases.size(); i++)
canvases[i]->retain();
// release any old canvases
for (size_t i = 0; i < attachedCanvases.size(); i++)
attachedCanvases[i]->release();
attachedCanvases = canvases;
}
void Canvas::startGrab()
{
setupGrab();
if (attachedCanvases.size() == 0)
return;
// make sure the FBO is only using a single canvas
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
@@ -393,20 +545,34 @@ void Canvas::stopGrab()
current = NULL;
}
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
@@ -472,6 +638,11 @@ void Canvas::getPixel(unsigned char* pixel_rgba, int x, int y)
strategy->bindFBO( 0 );
}
const std::vector<Canvas *> &Canvas::getAttachedCanvases() const
{
return attachedCanvases;
}
void Canvas::setFilter(const Image::Filter &f)
{
bindTexture(img);
@@ -515,6 +686,11 @@ void Canvas::unloadVolatile()
settings.filter = getFilter();
settings.wrap = getWrap();
strategy->deleteFBO(fbo, depth_stencil, img);
for (size_t i = 0; i < attachedCanvases.size(); i++)
attachedCanvases[i]->release();
attachedCanvases.clear();
}
int Canvas::getWidth()
+19 -3
View File
@@ -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 <vector>
namespace love
{
namespace graphics
@@ -50,6 +54,11 @@ public:
Canvas(int width, int height, TextureType texture_type = TYPE_NORMAL);
virtual ~Canvas();
/**
* @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<Canvas *> &canvases);
void startGrab();
void stopGrab();
@@ -66,6 +75,8 @@ public:
void getPixel(unsigned char* pixel_rgba, int x, int y);
const std::vector<Canvas *> &getAttachedCanvases() const;
void setFilter(const Image::Filter &f);
Image::Filter getFilter() const;
@@ -89,20 +100,22 @@ public:
void unloadVolatile();
static bool isSupported();
static bool isHdrSupported();
static bool isHDRSupported();
static bool isMultiCanvasSupported();
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 +134,9 @@ private:
Image::Wrap wrap;
} settings;
std::vector<Canvas *> attachedCanvases;
void setupGrab();
void drawv(const Matrix &t, const vertex *v) const;
static StringMap<TextureType, TYPE_MAX_ENUM>::Entry textureTypeEntries[];
+25 -25
View File
@@ -51,20 +51,20 @@ Font::Font(love::font::Rasterizer *r, const Image::Filter &filter)
{
// try to find the best texture size match for the font size
// default to the largest texture size if no rough match is found
texture_size_index = NUM_TEXTURE_SIZES - 1;
textureSizeIndex = NUM_TEXTURE_SIZES - 1;
for (int i = 0; i < NUM_TEXTURE_SIZES; i++)
{
// base our chosen texture width/height on a very rough guess of the total size taken up by the font's used glyphs
// the estimate is likely larger than the actual total size taken up, which is good since texture changes are expensive
if ((height * 0.8) * height * 95 <= TEXTURE_WIDTHS[i] * TEXTURE_HEIGHTS[i])
{
texture_size_index = i;
textureSizeIndex = i;
break;
}
}
texture_width = TEXTURE_WIDTHS[texture_size_index];
texture_height = TEXTURE_HEIGHTS[texture_size_index];
textureWidth = TEXTURE_WIDTHS[textureSizeIndex];
textureHeight = TEXTURE_HEIGHTS[textureSizeIndex];
love::font::GlyphData *gd = 0;
@@ -102,8 +102,8 @@ bool Font::initializeTexture(GLint format)
glTexImage2D(GL_TEXTURE_2D,
0,
internalformat,
(GLsizei)texture_width,
(GLsizei)texture_height,
(GLsizei)textureWidth,
(GLsizei)textureHeight,
0,
format,
GL_UNSIGNED_BYTE,
@@ -114,7 +114,7 @@ bool Font::initializeTexture(GLint format)
void Font::createTexture()
{
texture_x = texture_y = rowHeight = TEXTURE_PADDING;
textureX = textureY = rowHeight = TEXTURE_PADDING;
GLuint t;
glGenTextures(1, &t);
@@ -132,17 +132,17 @@ void Font::createTexture()
// try to initialize the texture, attempting smaller sizes if initialization fails
bool initialized = false;
while (texture_size_index >= 0)
while (textureSizeIndex >= 0)
{
texture_width = TEXTURE_WIDTHS[texture_size_index];
texture_height = TEXTURE_HEIGHTS[texture_size_index];
textureWidth = TEXTURE_WIDTHS[textureSizeIndex];
textureHeight = TEXTURE_HEIGHTS[textureSizeIndex];
initialized = initializeTexture(format);
if (initialized || texture_size_index <= 0)
if (initialized || textureSizeIndex <= 0)
break;
--texture_size_index;
--textureSizeIndex;
}
if (!initialized)
@@ -156,12 +156,12 @@ void Font::createTexture()
}
// Fill the texture with transparent black
std::vector<GLubyte> emptyData(texture_width * texture_height * (type == FONT_TRUETYPE ? 2 : 4), 0);
std::vector<GLubyte> emptyData(textureWidth * textureHeight * (type == FONT_TRUETYPE ? 2 : 4), 0);
glTexSubImage2D(GL_TEXTURE_2D,
0,
0, 0,
(GLsizei)texture_width,
(GLsizei)texture_height,
(GLsizei)textureWidth,
(GLsizei)textureHeight,
format,
GL_UNSIGNED_BYTE,
&emptyData[0]);
@@ -175,14 +175,14 @@ Font::Glyph *Font::addGlyph(unsigned int glyph)
int w = gd->getWidth();
int h = gd->getHeight();
if (texture_x + w + TEXTURE_PADDING > texture_width)
if (textureX + w + TEXTURE_PADDING > textureWidth)
{
// out of space - new row!
texture_x = TEXTURE_PADDING;
texture_y += rowHeight;
textureX = TEXTURE_PADDING;
textureY += rowHeight;
rowHeight = TEXTURE_PADDING;
}
if (texture_y + h + TEXTURE_PADDING > texture_height)
if (textureY + h + TEXTURE_PADDING > textureHeight)
{
// totally out of space - new texture!
createTexture();
@@ -203,8 +203,8 @@ Font::Glyph *Font::addGlyph(unsigned int glyph)
bindTexture(t);
glTexSubImage2D(GL_TEXTURE_2D,
0,
texture_x,
texture_y,
textureX,
textureY,
w, h,
(type == FONT_TRUETYPE ? GL_LUMINANCE_ALPHA : GL_RGBA),
GL_UNSIGNED_BYTE,
@@ -213,12 +213,12 @@ Font::Glyph *Font::addGlyph(unsigned int glyph)
g->texture = t;
Quad::Viewport v;
v.x = (float) texture_x;
v.y = (float) texture_y;
v.x = (float) textureX;
v.y = (float) textureY;
v.w = (float) w;
v.h = (float) h;
Quad q = Quad(v, (const float) texture_width, (const float) texture_height);
Quad q = Quad(v, (const float) textureWidth, (const float) textureHeight);
const vertex *verts = q.getVertices();
// copy vertex data to the glyph and set proper bearing
@@ -231,7 +231,7 @@ Font::Glyph *Font::addGlyph(unsigned int glyph)
}
if (w > 0)
texture_x += (w + TEXTURE_PADDING);
textureX += (w + TEXTURE_PADDING);
if (h > 0)
rowHeight = std::max(rowHeight, h + TEXTURE_PADDING);
+10 -6
View File
@@ -183,12 +183,16 @@ private:
float lineHeight;
float mSpacing; // modifies the spacing by multiplying it with this value
int texture_size_index;
int texture_width;
int texture_height;
int textureSizeIndex;
int textureWidth;
int textureHeight;
// vector of packed textures
std::vector<GLuint> textures;
// maps glyphs to glyph texture information
std::map<unsigned int, Glyph *> glyphs;
std::vector<GLuint> textures; // vector of packed textures
std::map<unsigned int, Glyph *> glyphs; // maps glyphs to quad information
FontType type;
Image::Filter filter;
@@ -198,7 +202,7 @@ private:
static const int TEXTURE_PADDING = 1;
int texture_x, texture_y;
int textureX, textureY;
int rowHeight;
bool initializeTexture(GLint format);
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+32 -14
View File
@@ -87,6 +87,9 @@ DisplayState Graphics::saveState()
if (s.scissor)
glGetIntegerv(GL_SCISSOR_BOX, s.scissorBox);
for (int i = 0; i < 4; i++)
s.colorMask[i] = colorMask[i];
return s;
}
@@ -101,6 +104,7 @@ void Graphics::restoreState(const DisplayState &s)
setScissor(s.scissorBox[0], s.scissorBox[1], s.scissorBox[2], s.scissorBox[3]);
else
setScissor();
setColorMask(s.colorMask[0], s.colorMask[1], s.colorMask[2], s.colorMask[3]);
}
bool Graphics::setMode(int width, int height, WindowFlags *flags)
@@ -135,6 +139,9 @@ bool Graphics::setMode(int width, int height, WindowFlags *flags)
// "Normal" blending
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Enable all color component writes.
setColorMask(true, true, true, true);
// Enable line/point smoothing.
setLineStyle(LINE_SMOOTH);
glEnable(GL_POINT_SMOOTH);
@@ -265,33 +272,29 @@ bool Graphics::isCreated() const
int Graphics::getModes(lua_State *L) const
{
int n;
love::window::Window::WindowSize **modes = currentWindow->getFullscreenSizes(n);
love::window::Window::WindowSize *modes = currentWindow->getFullscreenSizes(n);
if (modes == 0)
return 0;
lua_newtable(L);
lua_createtable(L, n, 0);
for (int i = 0; i < n ; i++)
{
lua_pushinteger(L, i+1);
lua_newtable(L);
lua_createtable(L, 0, 2);
// Inner table attribs.
lua_pushstring(L, "width");
lua_pushinteger(L, modes[i]->width);
lua_settable(L, -3);
lua_pushinteger(L, modes[i].width);
lua_setfield(L, -2, "width");
lua_pushstring(L, "height");
lua_pushinteger(L, modes[i]->height);
lua_settable(L, -3);
lua_pushinteger(L, modes[i].height);
lua_setfield(L, -2, "height");
// Inner table attribs end.
lua_settable(L, -3);
delete modes[i];
}
delete[] modes;
@@ -338,12 +341,12 @@ void Graphics::useStencil(bool invert)
{
glStencilFunc(GL_EQUAL, (int)(!invert), 1); // invert ? 0 : 1
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
setColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
}
void Graphics::discardStencil()
{
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
setColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
glDisable(GL_STENCIL_TEST);
}
@@ -397,7 +400,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())
@@ -507,6 +510,21 @@ Font *Graphics::getFont() const
return currentFont;
}
void Graphics::setColorMask(bool r, bool g, bool b, bool a)
{
colorMask[0] = r;
colorMask[1] = g;
colorMask[2] = b;
colorMask[3] = a;
glColorMask((GLboolean) r, (GLboolean) g, (GLboolean) b, (GLboolean) a);
}
const bool *Graphics::getColorMask() const
{
return colorMask;
}
void Graphics::setBlendMode(Graphics::BlendMode mode)
{
const int gl_1_4 = GLEE_VERSION_1_4;
+16
View File
@@ -77,6 +77,9 @@ struct DisplayState
bool scissor;
GLint scissorBox[4];
// Color mask.
bool colorMask[4];
// Window info.
std::string caption;
bool mouseVisible;
@@ -94,6 +97,7 @@ struct DisplayState
pointSize = 1.0f;
pointStyle = Graphics::POINT_SMOOTH;
scissor = false;
colorMask[0] = colorMask[1] = colorMask[2] = colorMask[3] = true;
caption = "";
mouseVisible = true;
}
@@ -299,6 +303,17 @@ public:
**/
Font *getFont() const;
/**
* Sets the enabled color components when rendering.
**/
void setColorMask(bool r, bool g, bool b, bool a);
/**
* Gets the current color mask.
* Returns an array of 4 booleans representing the mask.
**/
const bool *getColorMask() const;
/**
* Sets the current blend mode.
**/
@@ -495,6 +510,7 @@ private:
float lineWidth;
GLint matrixLimit;
GLint userMatrices;
bool colorMask[4];
int getRenderWidth() const;
int getRenderHeight() const;
@@ -478,6 +478,20 @@ void ParticleSystem::reset()
emitCounter = 0;
}
void ParticleSystem::emit(int num)
{
if (!active)
return;
for (int i = 0; i < num; i++)
{
if (isFull())
return;
add();
}
}
bool ParticleSystem::isActive() const
{
return active;
@@ -377,6 +377,12 @@ public:
**/
void reset();
/**
* Instantly emits a number of particles.
* @param num The number of particles to emit.
**/
void emit(int num);
/**
* Returns whether the particle emitter is active.
**/
+59 -22
View File
@@ -71,9 +71,12 @@ Shader::Shader(const ShaderSources &sources)
if (shaderSources.empty())
throw love::Exception("Cannot create shader: no source code!");
GLint maxtexunits;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtexunits);
maxTextureUnits = std::max(maxtexunits - 1, 0);
if (maxTextureUnits <= 0)
{
GLint maxtexunits;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxtexunits);
maxTextureUnits = std::max(maxtexunits - 1, 0);
}
// initialize global texture id counters if needed
if (textureCounters.size() < (size_t) maxTextureUnits)
@@ -94,17 +97,18 @@ Shader::~Shader()
GLuint Shader::compileCode(ShaderType type, const std::string &code)
{
GLenum glshadertype;
const char *shadertypename = NULL;
const char *typestr;
if (!typeNames.find(type, typestr))
typestr = "";
switch (type)
{
case TYPE_VERTEX:
glshadertype = GL_VERTEX_SHADER;
shadertypename = "vertex";
break;
case TYPE_PIXEL:
glshadertype = GL_FRAGMENT_SHADER;
shadertypename = "pixel";
break;
default:
throw love::Exception("Cannot create shader object: unknown shader type.");
@@ -121,9 +125,9 @@ GLuint Shader::compileCode(ShaderType type, const std::string &code)
GLenum err = glGetError();
if (err == GL_INVALID_ENUM) // invalid or unsupported shader type
throw love::Exception("Cannot create %s shader object: %s shaders not supported.", shadertypename, shadertypename);
throw love::Exception("Cannot create %s shader object: %s shaders not supported.", typestr, typestr);
else // other errors should only happen between glBegin() and glEnd()
throw love::Exception("Cannot create %s shader object.", shadertypename);
throw love::Exception("Cannot create %s shader object.", typestr);
}
const char *src = code.c_str();
@@ -132,23 +136,26 @@ GLuint Shader::compileCode(ShaderType type, const std::string &code)
glCompileShader(shaderid);
// Get any warnings the shader compiler may have produced
GLint infologlen;
glGetShaderiv(shaderid, GL_INFO_LOG_LENGTH, &infologlen);
GLchar *infolog = new GLchar[infologlen + 1];
glGetShaderInfoLog(shaderid, infologlen, NULL, infolog);
// Save any warnings for later querying
if (infologlen > 0)
shaderWarnings[type] = infolog;
delete[] infolog;
GLint status;
glGetShaderiv(shaderid, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
GLint infologlen;
glGetShaderiv(shaderid, GL_INFO_LOG_LENGTH, &infologlen);
GLchar *errorlog = new GLchar[infologlen + 1];
glGetShaderInfoLog(shaderid, infologlen, NULL, errorlog);
std::string tmp(errorlog);
delete[] errorlog;
glDeleteShader(shaderid);
throw love::Exception("Cannot compile %s shader code:\n%s", shadertypename, tmp.c_str());
throw love::Exception("Cannot compile %s shader code:\n%s",
typestr, shaderWarnings[type].c_str());
}
return shaderid;
@@ -174,7 +181,7 @@ void Shader::createProgram(const std::vector<GLuint> &shaderids)
if (status == GL_FALSE)
{
const std::string warnings = getWarnings();
std::string warnings = getProgramWarnings();
glDeleteProgram(program);
throw love::Exception("Cannot link shader program object:\n%s", warnings.c_str());
@@ -233,12 +240,15 @@ void Shader::unloadVolatile()
// same with uniform location list
uniforms.clear();
shaderWarnings.clear();
}
std::string Shader::getWarnings() const
std::string Shader::getProgramWarnings() const
{
GLint strlen, nullpos;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &strlen);
char *tempstr = new char[strlen+1];
// be extra sure that the error string will be 0-terminated
memset(tempstr, '\0', strlen+1);
@@ -247,6 +257,25 @@ std::string Shader::getWarnings() const
std::string warnings(tempstr);
delete[] tempstr;
return warnings;
}
std::string Shader::getWarnings() const
{
std::string warnings;
const char *typestr;
// Get the individual shader stage warnings
std::map<ShaderType, std::string>::const_iterator it;
for (it = shaderWarnings.begin(); it != shaderWarnings.end(); ++it)
{
if (typeNames.find(it->first, typestr))
warnings += std::string(typestr) + std::string(" shader:\n") + it->second;
}
warnings += getProgramWarnings();
return warnings;
}
@@ -452,6 +481,14 @@ bool Shader::isSupported()
return GLEE_VERSION_2_0 && getGLSLVersion() >= "1.2";
}
StringMap<Shader::ShaderType, Shader::TYPE_MAX_ENUM>::Entry Shader::typeNameEntries[] =
{
{"vertex", Shader::TYPE_VERTEX},
{"pixel", Shader::TYPE_PIXEL},
};
StringMap<Shader::ShaderType, Shader::TYPE_MAX_ENUM> Shader::typeNames(Shader::typeNameEntries, sizeof(Shader::typeNameEntries));
} // opengl
} // graphics
} // love
+16 -3
View File
@@ -21,14 +21,18 @@
#ifndef LOVE_GRAPHICS_SHADER_H
#define LOVE_GRAPHICS_SHADER_H
// LOVE
#include "common/Object.h"
#include <string>
#include <map>
#include <vector>
#include "common/StringMap.h"
#include "OpenGL.h"
#include "Image.h"
#include "Canvas.h"
// STL
#include <string>
#include <map>
#include <vector>
namespace love
{
namespace graphics
@@ -133,9 +137,15 @@ private:
void sendTexture(const std::string &name, GLuint texture);
// Get any warnings or errors generated only by the shader program object.
std::string getProgramWarnings() const;
// List of all shader code attached to this Shader
ShaderSources shaderSources;
// Shader compiler warning strings for individual shader stages.
std::map<ShaderType, std::string> shaderWarnings;
GLuint program; // volatile
// Uniform location buffer map
@@ -150,6 +160,9 @@ private:
// Counts total number of textures bound to each texture unit in all shaders
static std::vector<int> textureCounters;
static StringMap<ShaderType, TYPE_MAX_ENUM>::Entry typeNameEntries[];
static StringMap<ShaderType, TYPE_MAX_ENUM> typeNames;
};
} // opengl
+16 -13
View File
@@ -47,7 +47,14 @@ 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();
try
{
canvas->startGrab();
}
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();
@@ -172,18 +179,14 @@ int w_Canvas_clear(lua_State *L)
}
else if (lua_istable(L, 2))
{
lua_pushinteger(L, 1);
lua_gettable(L, 2);
c.r = (unsigned char)luaL_checkint(L, -1);
lua_pushinteger(L, 2);
lua_gettable(L, 2);
c.g = (unsigned char)luaL_checkint(L, -1);
lua_pushinteger(L, 3);
lua_gettable(L, 2);
c.b = (unsigned char)luaL_checkint(L, -1);
lua_pushinteger(L, 4);
lua_gettable(L, 2);
c.g = (unsigned char)luaL_optint(L, -1, 255);
for (int i = 1; i <= 4; i++)
lua_rawgeti(L, 2, i);
c.r = (unsigned char)luaL_checkint(L, -4);
c.g = (unsigned char)luaL_checkint(L, -3);
c.b = (unsigned char)luaL_checkint(L, -2);
c.a = (unsigned char)luaL_optint(L, -1, 255);
lua_pop(L, 4);
}
else
+124 -40
View File
@@ -601,22 +601,15 @@ int w_setColor(lua_State *L)
Color c;
if (lua_istable(L, 1))
{
lua_pushinteger(L, 1);
lua_gettable(L, -2);
c.r = (unsigned char)luaL_checkint(L, -1);
lua_pop(L, 1);
lua_pushinteger(L, 2);
lua_gettable(L, -2);
c.g = (unsigned char)luaL_checkint(L, -1);
lua_pop(L, 1);
lua_pushinteger(L, 3);
lua_gettable(L, -2);
c.b = (unsigned char)luaL_checkint(L, -1);
lua_pop(L, 1);
lua_pushinteger(L, 4);
lua_gettable(L, -2);
for (int i = 1; i <= 4; i++)
lua_rawgeti(L, 1, i);
c.r = (unsigned char)luaL_checkint(L, -4);
c.g = (unsigned char)luaL_checkint(L, -3);
c.b = (unsigned char)luaL_checkint(L, -2);
c.a = (unsigned char)luaL_optint(L, -1, 255);
lua_pop(L, 1);
lua_pop(L, 4);
}
else
{
@@ -644,22 +637,15 @@ int w_setBackgroundColor(lua_State *L)
Color c;
if (lua_istable(L, 1))
{
lua_pushinteger(L, 1);
lua_gettable(L, -2);
c.r = (unsigned char)luaL_checkint(L, -1);
lua_pop(L, 1);
lua_pushinteger(L, 2);
lua_gettable(L, -2);
c.g = (unsigned char)luaL_checkint(L, -1);
lua_pop(L, 1);
lua_pushinteger(L, 3);
lua_gettable(L, -2);
c.b = (unsigned char)luaL_checkint(L, -1);
lua_pop(L, 1);
lua_pushinteger(L, 4);
lua_gettable(L, -2);
for (int i = 1; i <= 4; i++)
lua_rawgeti(L, 1, i);
c.r = (unsigned char)luaL_checkint(L, -4);
c.g = (unsigned char)luaL_checkint(L, -3);
c.b = (unsigned char)luaL_checkint(L, -2);
c.a = (unsigned char)luaL_optint(L, -1, 255);
lua_pop(L, 1);
lua_pop(L, 4);
}
else
{
@@ -701,6 +687,28 @@ int w_getFont(lua_State *L)
return 1;
}
int w_setColorMask(lua_State *L)
{
bool mask[4];
for (int i = 0; i < 4; i++)
mask[i] = luax_toboolean(L, i + 1);
// r, g, b, a
instance->setColorMask(mask[0], mask[1], mask[2], mask[3]);
return 0;
}
int w_getColorMask(lua_State *L)
{
const bool *mask = instance->getColorMask();
for (int i = 0; i < 4; i++)
luax_pushboolean(L, mask[i]);
return 4;
}
int w_setBlendMode(lua_State *L)
{
Graphics::BlendMode mode;
@@ -943,8 +951,67 @@ int w_setCanvas(lua_State *L)
}
Canvas *canvas = luax_checkcanvas(L, 1);
// this unbinds the previous fbo
canvas->startGrab();
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<Canvas *> attachments;
Canvas *canvas = 0;
if (is_table)
{
// grab the first canvas in the array and attach the rest
lua_rawgeti(L, 1, 1);
canvas = luax_checkcanvas(L, -1);
lua_pop(L, 1);
for (int i = 2; i <= lua_objlen(L, 1); i++)
{
lua_rawgeti(L, 1, i);
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 +1019,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<Canvas *> &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 +1087,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_MULTI_CANVAS:
if (!Canvas::isMultiCanvasSupported())
supported = false;
break;
case Graphics::SUPPORT_SHADER:
@@ -1086,8 +1168,8 @@ int w_drawq(lua_State *L)
{
DrawQable *dq = luax_checktype<DrawQable>(L, 1, "DrawQable", GRAPHICS_DRAWQABLE_T);
Quad *q = luax_checkquad(L, 2);
float x = (float)luaL_checknumber(L, 3);
float y = (float)luaL_checknumber(L, 4);
float x = (float)luaL_optnumber(L, 3, 0.0f);
float y = (float)luaL_optnumber(L, 4, 0.0f);
float angle = (float)luaL_optnumber(L, 5, 0);
float sx = (float)luaL_optnumber(L, 6, 1);
float sy = (float)luaL_optnumber(L, 7, sx);
@@ -1192,8 +1274,7 @@ int w_line(lua_State *L)
{
for (int i = 0; i < args; ++i)
{
lua_pushnumber(L, i + 1);
lua_rawget(L, 1);
lua_rawgeti(L, 1, i + 1);
coords[i] = luax_tofloat(L, -1);
lua_pop(L, 1);
}
@@ -1295,8 +1376,7 @@ int w_polygon(lua_State *L)
{
for (int i = 0; i < args; ++i)
{
lua_pushnumber(L, i + 1);
lua_rawget(L, 2);
lua_rawgeti(L, 2, i + 1);
coords[i] = luax_tofloat(L, -1);
lua_pop(L, 1);
}
@@ -1408,6 +1488,8 @@ static const luaL_Reg functions[] =
{ "setFont", w_setFont },
{ "getFont", w_getFont },
{ "setColorMask", w_setColorMask },
{ "getColorMask", w_getColorMask },
{ "setBlendMode", w_setBlendMode },
{ "getBlendMode", w_getBlendMode },
{ "setDefaultFilter", w_setDefaultFilter },
@@ -1427,7 +1509,9 @@ static const luaL_Reg functions[] =
{ "getMaxPointSize", w_getMaxPointSize },
{ "newScreenshot", w_newScreenshot },
{ "setCanvas", w_setCanvas },
{ "setCanvases", w_setCanvases },
{ "getCanvas", w_getCanvas },
{ "getCanvases", w_getCanvas },
{ "setShader", w_setShader },
{ "getShader", w_getShader },
@@ -71,6 +71,8 @@ int w_setBackgroundColor(lua_State *L);
int w_getBackgroundColor(lua_State *L);
int w_setFont(lua_State *L);
int w_getFont(lua_State *L);
int w_setColorMask(lua_State *L);
int w_getColorMask(lua_State *L);
int w_setBlendMode(lua_State *L);
int w_getBlendMode(lua_State *L);
int w_setDefaultFilter(lua_State *L);
@@ -90,6 +92,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);
@@ -248,11 +248,8 @@ int w_ParticleSystem_setColors(lua_State *L)
return luaL_argerror(L, i + 2, "expected 4 color components");
for (int j = 0; j < 4; j++)
{
// push args[i+2][j+1] onto the stack
lua_pushnumber(L, j + 1);
lua_gettable(L, i + 2);
}
lua_rawgeti(L, i + 2, j + 1);
int r = luaL_checkint(L, -4);
int g = luaL_checkint(L, -3);
@@ -325,8 +322,7 @@ int w_ParticleSystem_setQuads(lua_State *L)
{
for (int i = 0; i < nQuads; i++)
{
lua_pushnumber(L, i + 1); // array index
lua_gettable(L, 2);
lua_rawgeti(L, 2, i + 1); // array index
quads[i] = luax_checkquad(L, -1);
lua_pop(L, 1);
}
@@ -452,6 +448,14 @@ int w_ParticleSystem_reset(lua_State *L)
return 0;
}
int w_ParticleSystem_emit(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
int num = luaL_checkint(L, 2);
t->emit(num);
return 0;
}
int w_ParticleSystem_isActive(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
@@ -518,6 +522,7 @@ static const luaL_Reg functions[] =
{ "stop", w_ParticleSystem_stop },
{ "pause", w_ParticleSystem_pause },
{ "reset", w_ParticleSystem_reset },
{ "emit", w_ParticleSystem_emit },
{ "isActive", w_ParticleSystem_isActive },
{ "isEmpty", w_ParticleSystem_isEmpty },
{ "isFull", w_ParticleSystem_isFull },
@@ -67,6 +67,7 @@ int w_ParticleSystem_start(lua_State *L);
int w_ParticleSystem_stop(lua_State *L);
int w_ParticleSystem_pause(lua_State *L);
int w_ParticleSystem_reset(lua_State *L);
int w_ParticleSystem_emit(lua_State *L);
int w_ParticleSystem_isActive(lua_State *L);
int w_ParticleSystem_isEmpty(lua_State *L);
int w_ParticleSystem_isFull(lua_State *L);
@@ -158,18 +158,15 @@ int w_SpriteBatch_setColor(lua_State *L)
}
else if (lua_istable(L, 2))
{
lua_rawgeti(L, 2, 1);
c.r = (unsigned char) luaL_checkint(L, -1);
lua_pop(L, 1);
lua_rawgeti(L, 2, 2);
c.g = (unsigned char) luaL_checkint(L, -1);
lua_pop(L, 1);
lua_rawgeti(L, 2, 3);
c.b = (unsigned char) luaL_checkint(L, -1);
lua_pop(L, 1);
lua_rawgeti(L, 2, 4);
for (int i = 1; i <= 4; i++)
lua_rawgeti(L, 2, i);
c.r = (unsigned char) luaL_checkint(L, -4);
c.g = (unsigned char) luaL_checkint(L, -3);
c.b = (unsigned char) luaL_checkint(L, -2);
c.a = (unsigned char) luaL_optint(L, -1, 255);
lua_pop(L, 1);
lua_pop(L, 4);
}
else
{
+11 -11
View File
@@ -108,8 +108,7 @@ void ImageData::load(Data *data)
devilMutex = thread::newMutex();
Lock lock(devilMutex);
ILuint image;
ilGenImages(1, &image);
ILuint image = ilGenImage();
ilBindImage(image);
try
@@ -132,13 +131,14 @@ void ImageData::load(Data *data)
create(width, height, ilGetData());
}
catch(std::exception &e)
catch (std::exception &e)
{
ilDeleteImages(1, &image);
// catches love and std exceptions
ilDeleteImage(image);
throw love::Exception("%s", e.what());
}
ilDeleteImages(1, &image);
ilDeleteImage(image);
}
void ImageData::encode(love::filesystem::File *f, ImageData::Format format)
@@ -149,8 +149,7 @@ void ImageData::encode(love::filesystem::File *f, ImageData::Format format)
Lock lock1(devilMutex);
Lock lock2(mutex);
ILuint tempimage;
ilGenImages(1, &tempimage);
ILuint tempimage = ilGenImage();
ilBindImage(tempimage);
ilxClearErrors();
@@ -222,14 +221,15 @@ void ImageData::encode(love::filesystem::File *f, ImageData::Format format)
f->write(encoded_data, size);
f->close();
}
catch(std::exception &)
catch (std::exception &e)
{
ilDeleteImages(1, &tempimage);
// catches love and std exceptions
ilDeleteImage(tempimage);
delete[] encoded_data;
throw;
throw love::Exception("%s", e.what());
}
ilDeleteImages(1, &tempimage);
ilDeleteImage(tempimage);
delete[] encoded_data;
}
+3 -3
View File
@@ -167,13 +167,14 @@ int w_ImageData_encode(lua_State *L)
{
ext = file->getExtension();
fmt = ext.c_str();
ImageData::getConstant(fmt, format);
if (!ImageData::getConstant(fmt, format))
return luaL_error(L, "Invalid image format '%s'.", fmt);
}
else
{
fmt = luaL_checkstring(L, 3);
if (!ImageData::getConstant(fmt, format))
luaL_error(L, "Invalid image format.");
return luaL_error(L, "Invalid image format '%s'.", fmt);
}
try
@@ -189,7 +190,6 @@ int w_ImageData_encode(lua_State *L)
static const luaL_Reg functions[] =
{
// Data
{ "getPointer", w_Data_getPointer },
{ "getSize", w_Data_getSize },
+2 -2
View File
@@ -152,9 +152,9 @@ int SoundData::getSampleCount() const
return (size/channels)/(bits/8);
}
int SoundData::getDuration() const
float SoundData::getDuration() const
{
return size/(channels*sampleRate*bits/8);
return float(size) /(channels*sampleRate*bits/8);
}
void SoundData::setSample(int i, float sample)
+1 -1
View File
@@ -50,7 +50,7 @@ public:
virtual int getSampleRate() const;
virtual int getSampleCount() const;
virtual int getDuration() const;
virtual float getDuration() const;
void setSample(int i, float sample);
float getSample(int i) const;
+1 -1
View File
@@ -63,7 +63,7 @@ int w_SoundData_getSampleCount(lua_State *L)
int w_SoundData_getDuration(lua_State *L)
{
SoundData *t = luax_checksounddata(L, 1);
lua_pushinteger(L, t->getDuration());
lua_pushnumber(L, t->getDuration());
return 1;
}
+4
View File
@@ -47,6 +47,8 @@ int w_Channel_push(lua_State *L)
{
Channel *c = luax_checkchannel(L, 1);
Variant *var = Variant::fromLua(L, 2);
if (!var)
return luaL_argerror(L, 2, "boolean, number, string, or love userdata expected");
c->push(var);
releaseVariant(c, var);
return 0;
@@ -56,6 +58,8 @@ int w_Channel_supply(lua_State *L)
{
Channel *c = luax_checkchannel(L, 1);
Variant *var = Variant::fromLua(L, 2);
if (!var)
return luaL_argerror(L, 2, "boolean, number, string, or love userdata expected");
c->supply(var);
releaseVariant(c, var);
return 0;
+2
View File
@@ -49,6 +49,8 @@ Timer::Timer()
// Init the SDL timer system.
if (SDL_InitSubSystem(SDL_INIT_TIMER) < 0)
throw Exception(SDL_GetError());
prevFpsUpdate = currTime = getMicroTime();
}
Timer::~Timer()
+2 -2
View File
@@ -59,14 +59,14 @@ public:
virtual void getWindow(int &width, int &height, WindowFlags &flags) const = 0;
virtual bool checkWindowSize(int width, int height, bool fullscreen) const = 0;
virtual WindowSize **getFullscreenSizes(int &n) const = 0;
virtual WindowSize *getFullscreenSizes(int &n) const = 0;
virtual int getWidth() const = 0;
virtual int getHeight() const = 0;
virtual bool isCreated() const = 0;
virtual void setWindowTitle(std::string &title) = 0;
virtual void setWindowTitle(const std::string &title) = 0;
virtual std::string getWindowTitle() const = 0;
virtual bool setIcon(love::image::ImageData *imgd) = 0;
+5 -6
View File
@@ -211,7 +211,7 @@ bool Window::checkWindowSize(int width, int height, bool fullscreen) const
typedef Window::WindowSize WindowSize;
WindowSize **Window::getFullscreenSizes(int &n) const
WindowSize *Window::getFullscreenSizes(int &n) const
{
SDL_Rect **modes = SDL_ListModes(0, SDL_OPENGL | SDL_FULLSCREEN);
@@ -225,13 +225,12 @@ WindowSize **Window::getFullscreenSizes(int &n) const
for (int i = 0; modes[i]; i++)
n++;
WindowSize **sizes = new WindowSize*[n];
WindowSize *sizes = new WindowSize[n];
for (int i = 0; i < n; i++)
{
sizes[i] = new WindowSize;
sizes[i]->width = modes[i]->w;
sizes[i]->height = modes[i]->h;
WindowSize w = {modes[i]->w, modes[i]->h};
sizes[i] = w;
}
return sizes;
}
@@ -251,7 +250,7 @@ bool Window::isCreated() const
return created;
}
void Window::setWindowTitle(std::string &title)
void Window::setWindowTitle(const std::string &title)
{
windowTitle = title;
SDL_WM_SetCaption(windowTitle.c_str(), 0);
+2 -2
View File
@@ -41,14 +41,14 @@ public:
void getWindow(int &width, int &height, WindowFlags &flags) const;
bool checkWindowSize(int width, int height, bool fullscreen) const;
WindowSize **getFullscreenSizes(int &n) const;
WindowSize *getFullscreenSizes(int &n) const;
int getWidth() const;
int getHeight() const;
bool isCreated() const;
void setWindowTitle(std::string &title);
void setWindowTitle(const std::string &title);
std::string getWindowTitle() const;
bool setIcon(love::image::ImageData *imgd);
+63 -25
View File
@@ -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_MULTI_CANVAS = [[
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_multicanvas)
local pixelcodes = {
GLSL_VERSION,
GLSL_SYNTAX, GLSL_PIXEL.HEADER, GLSL_UNIFORMS,
"#line 0",
pixelcode,
GLSL_PIXEL.FOOTER
is_multicanvas and GLSL_PIXEL.FOOTER_MULTI_CANVAS 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 -- render to multiple canvases simultaniously
return true, true
else
return false
end
end
function love.graphics._shaderCodeToGLSL(arg1, arg2)
local vertexcode, pixelcode
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
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, isMultiCanvas = isPixelCode(s)
if ispixel then
pixelcode = arg1 -- first arg contains pixel shader code
is_multicanvas = isMultiCanvas
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, isMultiCanvas = isPixelCode(s)
if ispixel then
pixelcode = arg2 -- second arg contains pixel shader code
is_multicanvas = isMultiCanvas
end
end
@@ -1386,7 +1420,7 @@ void main() {
vertexcode = createVertexCode(vertexcode)
end
if pixelcode then
pixelcode = createPixelCode(pixelcode)
pixelcode = createPixelCode(pixelcode, is_multicanvas)
end
return vertexcode, pixelcode
@@ -1466,10 +1500,14 @@ void main() {
function love.graphics.newShader(vertexcode, pixelcode)
love.graphics.newShader = newShader
local shader = newShader(vertexcode, pixelcode)
local meta = getmetatable(shader)
meta.send = shader_dispatch_send
meta.sendBoolean = meta.sendFloat
return shader
local success, shader = pcall(love.graphics.newShader, vertexcode, pixelcode)
if success then
local meta = getmetatable(shader)
meta.send = shader_dispatch_send
meta.sendBoolean = meta.sendFloat
return shader
else
return error(shader, 2)
end
end
end
+132 -64
View File
@@ -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,21 @@ 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, 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,
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 +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, 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,
@@ -6377,65 +6394,108 @@ 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, 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,
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, 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,
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, 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,
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, 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, 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, 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, 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, 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,
@@ -6448,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, 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,
@@ -6628,16 +6689,23 @@ const unsigned char graphics_lua[] =
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65,
0x77, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x6e, 0x65, 0x77, 0x53, 0x68, 0x61, 0x64, 0x65,
0x72, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x6e,
0x65, 0x77, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 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, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x3d, 0x20, 0x67, 0x65, 0x74,
0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x29, 0x0a,
0x09, 0x09, 0x6d, 0x65, 0x74, 0x61, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x73, 0x68, 0x61, 0x64,
0x65, 0x72, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x6d, 0x65, 0x74, 0x61, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e,
0x20, 0x3d, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x0a,
0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x2c, 0x20, 0x73,
0x68, 0x61, 0x64, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65,
0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x53, 0x68, 0x61, 0x64, 0x65,
0x72, 0x2c, 0x20, 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, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x3d, 0x20, 0x67, 0x65,
0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x6d, 0x65, 0x74, 0x61, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x73, 0x68, 0x61,
0x64, 0x65, 0x72, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x73, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x09, 0x6d, 0x65, 0x74, 0x61, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x42, 0x6f, 0x6f, 0x6c, 0x65, 0x61,
0x6e, 0x20, 0x3d, 0x20, 0x6d, 0x65, 0x74, 0x61, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x0a,
0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x0a,
0x09, 0x09, 0x65, 0x6c, 0x73, 0x65, 0x0a,
0x09, 0x09, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x2c, 0x20, 0x32,
0x29, 0x0a,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x65, 0x6e, 0x64, 0x0a,
0x65, 0x6e, 0x64, 0x0a,
}; // [graphics.lua]