From 3a51f0ad083285102cdfb31a289574877808a0c0 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 26 Aug 2014 03:24:42 -0300 Subject: [PATCH] Changed the love.graphics internal code to always use a default shader when none is set externally, and replaced the deprecated OpenGL vertex attribute code with the equivalent generic vertex attribute functions. This will simplify the code and make it more maintainable when OpenGL ES 2+ support is added, compared to using the deprecated VA functions on desktop GL and the generic VA functions on GLES. --HG-- branch : minor --- src/modules/graphics/opengl/Canvas.cpp | 12 +- src/modules/graphics/opengl/Font.cpp | 12 +- src/modules/graphics/opengl/Graphics.cpp | 25 ++- src/modules/graphics/opengl/Image.cpp | 12 +- src/modules/graphics/opengl/Mesh.cpp | 18 +- src/modules/graphics/opengl/OpenGL.cpp | 16 +- src/modules/graphics/opengl/OpenGL.h | 22 +- .../graphics/opengl/ParticleSystem.cpp | 18 +- src/modules/graphics/opengl/Polyline.cpp | 14 +- src/modules/graphics/opengl/Shader.cpp | 206 ++++++++++-------- src/modules/graphics/opengl/Shader.h | 20 +- src/modules/graphics/opengl/SpriteBatch.cpp | 18 +- src/modules/graphics/opengl/wrap_Graphics.cpp | 21 ++ src/modules/graphics/opengl/wrap_Graphics.h | 1 + src/scripts/graphics.lua | 34 ++- src/scripts/graphics.lua.h | 64 ++++-- 16 files changed, 316 insertions(+), 197 deletions(-) diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index d857f7e82..1e80b07c6 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -618,17 +618,17 @@ void Canvas::drawv(const Matrix &t, const Vertex *v) predraw(); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableVertexAttribArray(ATTRIB_POS); + glEnableVertexAttribArray(ATTRIB_TEXCOORD); - glVertexPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *)&v[0].x); - glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *)&v[0].s); + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &v[0].x); + glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &v[0].s); gl.prepareDraw(); gl.drawArrays(GL_QUADS, 0, 4); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + glDisableVertexAttribArray(ATTRIB_TEXCOORD); + glDisableVertexAttribArray(ATTRIB_POS); postdraw(); } diff --git a/src/modules/graphics/opengl/Font.cpp b/src/modules/graphics/opengl/Font.cpp index 159d523b1..6d0865b42 100644 --- a/src/modules/graphics/opengl/Font.cpp +++ b/src/modules/graphics/opengl/Font.cpp @@ -383,11 +383,11 @@ void Font::print(const std::string &text, float x, float y, float extra_spacing, OpenGL::TempTransform transform(gl); transform.get() *= t; - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableVertexAttribArray(ATTRIB_POS); + glEnableVertexAttribArray(ATTRIB_TEXCOORD); - glVertexPointer(2, GL_FLOAT, sizeof(GlyphVertex), (GLvoid *)&glyphverts[0].x); - glTexCoordPointer(2, GL_FLOAT, sizeof(GlyphVertex), (GLvoid *)&glyphverts[0].s); + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &glyphverts[0].x); + glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &glyphverts[0].s); gl.prepareDraw(); @@ -400,8 +400,8 @@ void Font::print(const std::string &text, float x, float y, float extra_spacing, gl.drawArrays(GL_QUADS, it->startvertex, it->vertexcount); } - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + glDisableVertexAttribArray(ATTRIB_TEXCOORD); + glDisableVertexAttribArray(ATTRIB_POS); } int Font::getWidth(const std::string &str) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 6d023b443..7437853a2 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -69,6 +69,12 @@ Graphics::~Graphics() // We do this manually so the love objects get released before the window. states.clear(); + if (Shader::defaultShader) + { + Shader::defaultShader->release(); + Shader::defaultShader = nullptr; + } + currentWindow->release(); } @@ -280,6 +286,13 @@ bool Graphics::setMode(int width, int height, bool &sRGB) pixel_size_stack.reserve(5); pixel_size_stack.push_back(1); + // We always need a default shader. + if (!Shader::defaultShader) + Shader::defaultShader = newShader(Shader::defaultCode[0]); + + if (!getShader()) + setShader(Shader::defaultShader); + return true; } @@ -1080,10 +1093,10 @@ void Graphics::arc(DrawMode mode, float x, float y, float radius, float angle1, { gl.prepareDraw(); gl.bindTexture(0); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, (const GLvoid *) coords); + glEnableVertexAttribArray(ATTRIB_POS); + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, coords); gl.drawArrays(GL_TRIANGLE_FAN, 0, points + 2); - glDisableClientState(GL_VERTEX_ARRAY); + glDisableVertexAttribArray(ATTRIB_POS); } delete[] coords; @@ -1104,10 +1117,10 @@ void Graphics::polygon(DrawMode mode, const float *coords, size_t count) { gl.prepareDraw(); gl.bindTexture(0); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, (const GLvoid *)coords); + glEnableVertexAttribArray(ATTRIB_POS); + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, coords); gl.drawArrays(GL_POLYGON, 0, count/2-1); // opengl will close the polygon for us - glDisableClientState(GL_VERTEX_ARRAY); + glDisableVertexAttribArray(ATTRIB_POS); } } diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index f691f990b..2adedc9cd 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -410,17 +410,17 @@ void Image::drawv(const Matrix &t, const Vertex *v) predraw(); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableVertexAttribArray(ATTRIB_POS); + glEnableVertexAttribArray(ATTRIB_TEXCOORD); - glVertexPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *)&v[0].x); - glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *)&v[0].s); + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &v[0].x); + glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &v[0].s); gl.prepareDraw(); gl.drawArrays(GL_QUADS, 0, 4); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); + glDisableVertexAttribArray(ATTRIB_TEXCOORD); + glDisableVertexAttribArray(ATTRIB_POS); postdraw(); } diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index 7bdbd1884..b62fd6c23 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -339,17 +339,17 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo // Make sure the VBO isn't mapped when we draw (sends data to GPU if needed.) vbo->unmap(); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableVertexAttribArray(ATTRIB_POS); + glEnableVertexAttribArray(ATTRIB_TEXCOORD); - glVertexPointer(2, GL_FLOAT, sizeof(Vertex), vbo->getPointer(pos_offset)); - glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), vbo->getPointer(tex_offset)); + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), vbo->getPointer(pos_offset)); + glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), vbo->getPointer(tex_offset)); if (hasVertexColors()) { // Per-vertex colors. - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), vbo->getPointer(color_offset)); + glEnableVertexAttribArray(ATTRIB_COLOR); + glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), vbo->getPointer(color_offset)); } GLenum mode = getGLDrawMode(draw_mode); @@ -391,12 +391,12 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo gl.drawArrays(mode, min, max - min + 1); } - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableVertexAttribArray(ATTRIB_TEXCOORD); + glDisableVertexAttribArray(ATTRIB_POS); if (hasVertexColors()) { - glDisableClientState(GL_COLOR_ARRAY); + glDisableVertexAttribArray(ATTRIB_COLOR); // Using the color array leaves the GL constant color undefined. gl.setColor(gl.getColor()); } diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index a696bb475..c94d46b89 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -75,15 +75,11 @@ void OpenGL::setupContext() if (!contextInitialized) return; - // Store the current color so we don't have to get it through GL later. - GLfloat glcolor[4]; - glGetFloatv(GL_CURRENT_COLOR, glcolor); - state.color.r = glcolor[0] * 255; - state.color.g = glcolor[1] * 255; - state.color.b = glcolor[2] * 255; - state.color.a = glcolor[3] * 255; + state.color = Color(255, 255, 255, 255); + GLfloat glcolor[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + glVertexAttrib4fv(ATTRIB_COLOR, glcolor); - // Same with the current clear color. + // Get the current clear color so we don't have to get it through GL later. glGetFloatv(GL_COLOR_CLEAR_VALUE, glcolor); state.clearColor.r = glcolor[0] * 255; state.clearColor.g = glcolor[1] * 255; @@ -360,7 +356,9 @@ void OpenGL::drawElementsInstanced(GLenum mode, GLsizei count, GLenum type, cons void OpenGL::setColor(const Color &c) { - glColor4ubv(&c.r); + GLfloat glc[] = {c.r / 255.0f, c.g / 255.0f, c.b / 255.0f, c.a / 255.0f}; + glVertexAttrib4fv(ATTRIB_COLOR, glc); + state.color = c; } diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 63e263d19..cd22dc52f 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -48,6 +48,17 @@ namespace opengl // no clashes with other GL libraries when linking, etc. using namespace glad; +// Vertex attribute indices used in shaders by LOVE. The values map to OpenGL +// generic vertex attribute indices. +enum VertexAttribID +{ + ATTRIB_POS = 0, + ATTRIB_TEXCOORD, + ATTRIB_COLOR, + ATTRIB_PSEUDO_INSTANCE_ID, // Instance ID used with pseudo-instancing. + ATTRIB_MAX_ENUM +}; + /** * Thin layer between OpenGL and the rest of the program. * Internally shadows some OpenGL context state for improved efficiency and @@ -71,17 +82,6 @@ public: VENDOR_UNKNOWN }; - // Vertex attributes used in shaders by LOVE. The values map to OpenGL - // generic vertex attribute indices, when applicable. - // LOVE uses the old hard-coded attribute APIs for positions, colors, etc. - // (for now.) - enum VertexAttrib - { - // Instance ID when pseudo-instancing is used. - ATTRIB_PSEUDO_INSTANCE_ID = 1, - ATTRIB_MAX_ENUM - }; - // A rectangle representing an OpenGL viewport or a scissor box. struct Viewport { diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index c4c5b0524..e64fbb1dd 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -869,20 +869,20 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo texture->predraw(); - glEnableClientState(GL_COLOR_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableVertexAttribArray(ATTRIB_COLOR); + glEnableVertexAttribArray(ATTRIB_POS); + glEnableVertexAttribArray(ATTRIB_TEXCOORD); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (GLvoid *) &particleVerts[0].r); - glVertexPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *) &particleVerts[0].x); - glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (GLvoid *) &particleVerts[0].s); + glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), &particleVerts[0].r); + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &particleVerts[0].x); + glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &particleVerts[0].s); gl.prepareDraw(); gl.drawArrays(GL_QUADS, 0, pCount * 4); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); + glDisableVertexAttribArray(ATTRIB_TEXCOORD); + glDisableVertexAttribArray(ATTRIB_POS); + glDisableVertexAttribArray(ATTRIB_COLOR); texture->postdraw(); diff --git a/src/modules/graphics/opengl/Polyline.cpp b/src/modules/graphics/opengl/Polyline.cpp index 58c2eff11..94f489f64 100644 --- a/src/modules/graphics/opengl/Polyline.cpp +++ b/src/modules/graphics/opengl/Polyline.cpp @@ -331,8 +331,8 @@ void Polyline::draw() // draw the core line gl.bindTexture(0); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, 0, (const GLvoid *)vertices); + glEnableVertexAttribArray(ATTRIB_POS); + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, vertices); gl.drawArrays(draw_mode, 0, vertex_count); if (overdraw) @@ -342,18 +342,18 @@ void Polyline::draw() Color *colors = new Color[overdraw_vertex_count]; fill_color_array(colors, c); - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors); - glVertexPointer(2, GL_FLOAT, 0, (const GLvoid *)overdraw); + glEnableVertexAttribArray(ATTRIB_COLOR); + glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors); + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, overdraw); gl.drawArrays(draw_mode, 0, overdraw_vertex_count); - glDisableClientState(GL_COLOR_ARRAY); + glDisableVertexAttribArray(ATTRIB_COLOR); delete[] colors; gl.setColor(c); } - glDisableClientState(GL_VERTEX_ARRAY); + glDisableVertexAttribArray(ATTRIB_POS); } void Polyline::fill_color_array(Color *colors, const Color &c) diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index e548fa07e..30a32683b 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -62,6 +62,9 @@ namespace Shader *Shader::current = nullptr; +Shader *Shader::defaultShader = nullptr; + +Shader::ShaderSources Shader::defaultCode[1]; // TODO: RENDERER_MAX_ENUM GLint Shader::maxTexUnits = 0; std::vector Shader::textureCounters; @@ -178,18 +181,26 @@ void Shader::createProgram(const std::vector &shaderids) if (program == 0) throw love::Exception("Cannot create shader program object."); - for (GLuint id : shaderids) - glAttachShader(program, id); - - // Bind generic vertex attribute indices to names in the shader. - for (int i = 0; i < int(OpenGL::ATTRIB_MAX_ENUM); i++) + try { - OpenGL::VertexAttrib attrib = (OpenGL::VertexAttrib) i; + for (GLuint id : shaderids) + glAttachShader(program, id); + } + catch (love::Exception &) + { + glDeleteProgram(program); + throw; + } + + // Bind love's vertex attribute indices to names in the shader. + for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++) + { + VertexAttribID attrib = (VertexAttribID) i; // FIXME: We skip this both because pseudo-instancing is temporarily // disabled (see graphics.lua), and because binding a non-existant - // attribute name to a location causes a shader linker warning. - if (attrib == OpenGL::ATTRIB_PSEUDO_INSTANCE_ID) + // attribute name to a location can cause a shader linker warning. + if (attrib == ATTRIB_PSEUDO_INSTANCE_ID) continue; const char *name = nullptr; @@ -199,10 +210,6 @@ void Shader::createProgram(const std::vector &shaderids) glLinkProgram(program); - // flag shaders for auto-deletion when the program object is deleted. - for (GLuint id : shaderids) - glDeleteShader(id); - GLint status; glGetProgramiv(program, GL_LINK_STATUS, &status); @@ -211,9 +218,12 @@ void Shader::createProgram(const std::vector &shaderids) std::string warnings = getProgramWarnings(); glDeleteProgram(program); program = 0; - throw love::Exception("Cannot link shader program object:\n%s", warnings.c_str()); } + + // flag shaders for auto-deletion when the program object is deleted. + for (GLuint id : shaderids) + glDeleteShader(id); } void Shader::mapActiveUniforms() @@ -280,18 +290,38 @@ bool Shader::loadVolatile() shaderids.push_back(shaderid); } + // The shader program must have both vertex and pixel shader stages. + ShaderSources &defaults = defaultCode[0]; + + ShaderSources::const_iterator source = shaderSources.find(TYPE_VERTEX); + if (source == shaderSources.end()) + shaderids.push_back(compileCode(TYPE_VERTEX, defaults[TYPE_VERTEX])); + + source = shaderSources.find(TYPE_PIXEL); + if (source == shaderSources.end()) + shaderids.push_back(compileCode(TYPE_PIXEL, defaults[TYPE_PIXEL])); + if (shaderids.empty()) throw love::Exception("Cannot create shader: no valid source code!"); - createProgram(shaderids); + try + { + createProgram(shaderids); + } + catch (love::Exception &) + { + for (GLuint id : shaderids) + glDeleteShader(id); + throw; + } // Retreive all active uniform variables in this shader from OpenGL. mapActiveUniforms(); - for (int i = 0; i < int(OpenGL::ATTRIB_MAX_ENUM); i++) + for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++) { const char *name = nullptr; - if (attribNames.find(OpenGL::VertexAttrib(i), name)) + if (attribNames.find(VertexAttribID(i), name)) vertexAttributes[i] = glGetAttribLocation(program, name); else vertexAttributes[i] = -1; @@ -327,7 +357,7 @@ void Shader::unloadVolatile() // active texture list is probably invalid, clear it activeTexUnits.clear(); - activeTexUnits.insert(activeTexUnits.begin(), maxTexUnits, 0); + activeTexUnits.resize(maxTexUnits, 0); // same with uniform location list uniforms.clear(); @@ -416,72 +446,6 @@ const Shader::Uniform &Shader::getUniform(const std::string &name) const return it->second; } -int Shader::getUniformTypeSize(GLenum type) const -{ - switch (type) - { - case GL_INT: - case GL_FLOAT: - case GL_BOOL: - case GL_SAMPLER_1D: - case GL_SAMPLER_2D: - case GL_SAMPLER_3D: - return 1; - case GL_INT_VEC2: - case GL_FLOAT_VEC2: - case GL_FLOAT_MAT2: - case GL_BOOL_VEC2: - return 2; - case GL_INT_VEC3: - case GL_FLOAT_VEC3: - case GL_FLOAT_MAT3: - case GL_BOOL_VEC3: - return 3; - case GL_INT_VEC4: - case GL_FLOAT_VEC4: - case GL_FLOAT_MAT4: - case GL_BOOL_VEC4: - return 4; - default: - break; - } - - return 1; -} - -Shader::UniformType Shader::getUniformBaseType(GLenum type) const -{ - switch (type) - { - case GL_INT: - case GL_INT_VEC2: - case GL_INT_VEC3: - case GL_INT_VEC4: - return UNIFORM_INT; - case GL_FLOAT: - case GL_FLOAT_VEC2: - case GL_FLOAT_VEC3: - case GL_FLOAT_VEC4: - case GL_FLOAT_MAT2: - case GL_FLOAT_MAT3: - case GL_FLOAT_MAT4: - return UNIFORM_FLOAT; - case GL_BOOL: - case GL_BOOL_VEC2: - case GL_BOOL_VEC3: - case GL_BOOL_VEC4: - return UNIFORM_BOOL; - case GL_SAMPLER_1D: - case GL_SAMPLER_2D: - case GL_SAMPLER_3D: - return UNIFORM_SAMPLER; - default: - break; - } - - return UNIFORM_UNKNOWN; -} - void Shader::checkSetUniformError(const Uniform &u, int size, int count, UniformType sendtype) const { if (!program) @@ -611,11 +575,12 @@ void Shader::sendTexture(const std::string &name, Texture *texture) void Shader::retainObject(const std::string &name, Object *object) { + object->retain(); + auto it = boundRetainables.find(name); if (it != boundRetainables.end()) it->second->release(); - object->retain(); boundRetainables[name] = object; } @@ -669,7 +634,7 @@ Shader::UniformType Shader::getExternVariable(const std::string &name, int &comp return it->second.baseType; } -bool Shader::hasVertexAttrib(OpenGL::VertexAttrib attrib) const +bool Shader::hasVertexAttrib(VertexAttribID attrib) const { return vertexAttributes[int(attrib)] != -1; } @@ -771,6 +736,68 @@ bool Shader::isSupported() return getGLSLVersion() >= "1.2"; } +int Shader::getUniformTypeSize(GLenum type) const +{ + switch (type) + { + case GL_INT: + case GL_FLOAT: + case GL_BOOL: + case GL_SAMPLER_1D: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + return 1; + case GL_INT_VEC2: + case GL_FLOAT_VEC2: + case GL_FLOAT_MAT2: + case GL_BOOL_VEC2: + return 2; + case GL_INT_VEC3: + case GL_FLOAT_VEC3: + case GL_FLOAT_MAT3: + case GL_BOOL_VEC3: + return 3; + case GL_INT_VEC4: + case GL_FLOAT_VEC4: + case GL_FLOAT_MAT4: + case GL_BOOL_VEC4: + return 4; + default: + return 1; + } +} + +Shader::UniformType Shader::getUniformBaseType(GLenum type) const +{ + switch (type) + { + case GL_INT: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_INT_VEC4: + return UNIFORM_INT; + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT4: + return UNIFORM_FLOAT; + case GL_BOOL: + case GL_BOOL_VEC2: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + return UNIFORM_BOOL; + case GL_SAMPLER_1D: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + return UNIFORM_SAMPLER; + default: + return UNIFORM_UNKNOWN; + } +} + bool Shader::getConstant(const char *in, UniformType &out) { return uniformTypes.find(in, out); @@ -800,12 +827,15 @@ StringMap::Entry Shader::uniformT StringMap Shader::uniformTypes(Shader::uniformTypeEntries, sizeof(Shader::uniformTypeEntries)); -StringMap::Entry Shader::attribNameEntries[] = +StringMap::Entry Shader::attribNameEntries[] = { - {"love_PseudoInstanceID", OpenGL::ATTRIB_PSEUDO_INSTANCE_ID}, + {"VertexPosition", ATTRIB_POS}, + {"VertexTexCoord", ATTRIB_TEXCOORD}, + {"VertexColor", ATTRIB_COLOR}, + {"love_PseudoInstanceID", ATTRIB_PSEUDO_INSTANCE_ID}, }; -StringMap Shader::attribNames(Shader::attribNameEntries, sizeof(Shader::attribNameEntries)); +StringMap Shader::attribNames(Shader::attribNameEntries, sizeof(Shader::attribNameEntries)); StringMap::Entry Shader::builtinNameEntries[] = { diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 38c70a137..019fd91ca 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -46,9 +46,6 @@ class Shader : public Object, public Volatile { public: - // Pointer to currently active Shader. - static Shader *current; - enum ShaderType { TYPE_VERTEX, @@ -77,6 +74,15 @@ public: // Type for a list of shader source codes in the form of sources[shadertype] = code typedef std::map ShaderSources; + // Pointer to currently active Shader. + static Shader *current; + + // Pointer to the default Shader. + static Shader *defaultShader; + + // Default shader code (a shader is always required internally.) + static ShaderSources defaultCode[1]; // TODO: RENDERER_MAX_ENUM + /** * Creates a new Shader using a list of source codes. * Sources must contain either vertex or pixel shader code, or both. @@ -162,7 +168,7 @@ public: /** * Internal use only. **/ - bool hasVertexAttrib(OpenGL::VertexAttrib attrib) const; + bool hasVertexAttrib(VertexAttribID attrib) const; bool hasBuiltinUniform(BuiltinUniform builtin) const; bool sendBuiltinFloat(BuiltinUniform builtin, int size, const GLfloat *m, int count); void checkSetScreenParams(); @@ -219,7 +225,7 @@ private: GLint builtinUniforms[BUILTIN_MAX_ENUM]; // Location values for any generic vertex attribute variables. - GLint vertexAttributes[OpenGL::ATTRIB_MAX_ENUM]; + GLint vertexAttributes[ATTRIB_MAX_ENUM]; // Uniform location buffer map std::map uniforms; @@ -248,8 +254,8 @@ private: static StringMap uniformTypes; // Names for the generic vertex attributes used by love. - static StringMap::Entry attribNameEntries[]; - static StringMap attribNames; + static StringMap::Entry attribNameEntries[]; + static StringMap attribNames; // Names for the built-in uniform variables. static StringMap::Entry builtinNameEntries[]; diff --git a/src/modules/graphics/opengl/SpriteBatch.cpp b/src/modules/graphics/opengl/SpriteBatch.cpp index 5d578e023..c60f3dcc8 100644 --- a/src/modules/graphics/opengl/SpriteBatch.cpp +++ b/src/modules/graphics/opengl/SpriteBatch.cpp @@ -283,25 +283,25 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float // Apply per-sprite color, if a color is set. if (color) { - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), array_buf->getPointer(color_offset)); + glEnableVertexAttribArray(ATTRIB_COLOR); + glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), array_buf->getPointer(color_offset)); } - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(2, GL_FLOAT, sizeof(Vertex), array_buf->getPointer(pos_offset)); + glEnableVertexAttribArray(ATTRIB_POS); + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), array_buf->getPointer(pos_offset)); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), array_buf->getPointer(texel_offset)); + glEnableVertexAttribArray(ATTRIB_TEXCOORD); + glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), array_buf->getPointer(texel_offset)); gl.prepareDraw(); gl.drawElements(GL_TRIANGLES, element_buf->getIndexCount(next), element_buf->getType(), element_buf->getPointer(0)); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableVertexAttribArray(ATTRIB_TEXCOORD); + glDisableVertexAttribArray(ATTRIB_POS); if (color) { - glDisableClientState(GL_COLOR_ARRAY); + glDisableVertexAttribArray(ATTRIB_COLOR); gl.setColor(curcolor); } diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index b1c818e30..ee82661f0 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -960,6 +960,26 @@ int w_getShader(lua_State *L) return 1; } +int w_setDefaultShaderCode(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TTABLE); + + lua_getfield(L, 1, "opengl"); + lua_rawgeti(L, -1, 1); + lua_rawgeti(L, -2, 2); + + Shader::ShaderSources openglcode; + openglcode[Shader::TYPE_VERTEX] = luax_checkstring(L, -2); + openglcode[Shader::TYPE_PIXEL] = luax_checkstring(L, -1); + + lua_pop(L, 3); + + Shader::defaultCode[0] = openglcode; + + return 0; +} + + int w_getSupported(lua_State *L) { lua_createtable(L, 0, (int) Graphics::SUPPORT_MAX_ENUM); @@ -1438,6 +1458,7 @@ static const luaL_Reg functions[] = { "setShader", w_setShader }, { "getShader", w_getShader }, + { "_setDefaultShaderCode", w_setDefaultShaderCode }, { "getSupported", w_getSupported }, { "getCanvasFormats", w_getCanvasFormats }, diff --git a/src/modules/graphics/opengl/wrap_Graphics.h b/src/modules/graphics/opengl/wrap_Graphics.h index f20c1285f..26a3f3e36 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.h +++ b/src/modules/graphics/opengl/wrap_Graphics.h @@ -89,6 +89,7 @@ int w_setCanvas(lua_State *L); int w_getCanvas(lua_State *L); int w_setShader(lua_State *L); int w_getShader(lua_State *L); +int w_setDefaultShaderCode(lua_State *L); int w_getSupported(lua_State *L); int w_getCanvasFormats(lua_State *L); int w_getCompressedImageFormats(lua_State *L); diff --git a/src/scripts/graphics.lua b/src/scripts/graphics.lua index 95bb8f236..90b45ef86 100644 --- a/src/scripts/graphics.lua +++ b/src/scripts/graphics.lua @@ -1310,12 +1310,12 @@ uniform vec4 love_ScreenSize;]] HEADER = [[ #define VERTEX -#define VertexPosition gl_Vertex -#define VertexTexCoord gl_MultiTexCoord0 -#define VertexColor gl_Color +attribute vec4 VertexPosition; +attribute vec4 VertexTexCoord; +attribute vec4 VertexColor; -#define VaryingTexCoord gl_TexCoord[0] -#define VaryingColor gl_FrontColor +varying vec4 VaryingTexCoord; +varying vec4 VaryingColor; // #if defined(GL_ARB_draw_instanced) // #extension GL_ARB_draw_instanced : enable @@ -1338,8 +1338,8 @@ void main() { HEADER = [[ #define PIXEL -#define VaryingTexCoord gl_TexCoord[0] -#define VaryingColor gl_Color]], +varying vec4 VaryingTexCoord; +varying vec4 VaryingColor;]], FOOTER = [[ void main() { @@ -1465,4 +1465,24 @@ void main() { if #lines == 1 then return message end return table_concat(lines, "\n") end + + local defaultcode = { + vertex = [[ +vec4 position(mat4 transform_proj, vec4 vertpos) { + return transform_proj * vertpos; +}]], + pixel = [[ +vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord) { + return Texel(tex, texcoord) * vcolor; +}]] + } + + local defaults = { + opengl = { + createVertexCode(defaultcode.vertex), + createPixelCode(defaultcode.pixel, false), + }, + } + + love.graphics._setDefaultShaderCode(defaults) end diff --git a/src/scripts/graphics.lua.h b/src/scripts/graphics.lua.h index 6a3463cc6..064f69023 100644 --- a/src/scripts/graphics.lua.h +++ b/src/scripts/graphics.lua.h @@ -6301,18 +6301,16 @@ const unsigned char graphics_lua[] = 0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x45, 0x52, 0x54, 0x45, 0x58, 0x0a, - 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x50, 0x6f, 0x73, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x67, 0x6c, 0x5f, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x0a, - 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x54, 0x65, 0x78, 0x43, - 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x67, 0x6c, 0x5f, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x54, 0x65, 0x78, 0x43, 0x6f, - 0x6f, 0x72, 0x64, 0x30, 0x0a, - 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, - 0x72, 0x20, 0x67, 0x6c, 0x5f, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x0a, - 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x78, - 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x67, 0x6c, 0x5f, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x5b, - 0x30, 0x5d, 0x0a, - 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, - 0x6f, 0x72, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x0a, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x65, 0x72, + 0x74, 0x65, 0x78, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3b, 0x0a, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x65, 0x72, + 0x74, 0x65, 0x78, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x65, 0x72, + 0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a, + 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, + 0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a, + 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, + 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a, 0x2f, 0x2f, 0x20, 0x23, 0x69, 0x66, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x28, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x29, 0x0a, @@ -6347,11 +6345,10 @@ const unsigned char graphics_lua[] = 0x3d, 0x20, 0x7b, 0x0a, 0x09, 0x09, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x50, 0x49, 0x58, 0x45, 0x4c, 0x0a, - 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x78, - 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x67, 0x6c, 0x5f, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x5b, - 0x30, 0x5d, 0x0a, - 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, - 0x6f, 0x72, 0x20, 0x67, 0x6c, 0x5f, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x5d, 0x5d, 0x2c, 0x0a, + 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, + 0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a, + 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, + 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 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, 0x63, 0x72, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x69, @@ -6610,6 +6607,39 @@ const unsigned char graphics_lua[] = 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x28, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x2c, 0x20, 0x22, 0x5c, 0x6e, 0x22, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x63, 0x6f, 0x64, 0x65, + 0x20, 0x3d, 0x20, 0x7b, 0x0a, + 0x09, 0x09, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, + 0x76, 0x65, 0x63, 0x34, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6d, 0x61, 0x74, 0x34, + 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x2c, 0x20, 0x76, + 0x65, 0x63, 0x34, 0x20, 0x76, 0x65, 0x72, 0x74, 0x70, 0x6f, 0x73, 0x29, 0x20, 0x7b, 0x0a, + 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x6f, 0x72, 0x6d, 0x5f, + 0x70, 0x72, 0x6f, 0x6a, 0x20, 0x2a, 0x20, 0x76, 0x65, 0x72, 0x74, 0x70, 0x6f, 0x73, 0x3b, 0x0a, + 0x7d, 0x5d, 0x5d, 0x2c, 0x0a, + 0x09, 0x09, 0x70, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, + 0x76, 0x65, 0x63, 0x34, 0x20, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x28, 0x76, 0x65, 0x63, 0x34, 0x20, 0x76, + 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x2c, 0x20, 0x49, 0x6d, 0x61, 0x67, 0x65, 0x20, 0x74, 0x65, 0x78, 0x2c, 0x20, + 0x76, 0x65, 0x63, 0x32, 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x2c, 0x20, 0x76, 0x65, 0x63, + 0x32, 0x20, 0x70, 0x69, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x29, 0x20, 0x7b, 0x0a, + 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x54, 0x65, 0x78, 0x65, 0x6c, 0x28, 0x74, 0x65, 0x78, 0x2c, + 0x20, 0x74, 0x65, 0x78, 0x63, 0x6f, 0x6f, 0x72, 0x64, 0x29, 0x20, 0x2a, 0x20, 0x76, 0x63, 0x6f, 0x6c, 0x6f, + 0x72, 0x3b, 0x0a, + 0x7d, 0x5d, 0x5d, 0x0a, + 0x09, 0x7d, 0x0a, + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x3d, 0x20, + 0x7b, 0x0a, + 0x09, 0x09, 0x6f, 0x70, 0x65, 0x6e, 0x67, 0x6c, 0x20, 0x3d, 0x20, 0x7b, 0x0a, + 0x09, 0x09, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x43, 0x6f, 0x64, + 0x65, 0x28, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x65, 0x72, 0x74, + 0x65, 0x78, 0x29, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x43, 0x6f, 0x64, 0x65, + 0x28, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x69, 0x78, 0x65, 0x6c, + 0x2c, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x29, 0x2c, 0x0a, + 0x09, 0x09, 0x7d, 0x2c, 0x0a, + 0x09, 0x7d, 0x0a, + 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x5f, 0x73, 0x65, + 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x68, 0x61, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x64, 0x65, + 0x28, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, }; // [graphics.lua] } // love