Browse Source

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
Alex Szpakowski 11 years ago
parent
commit
3a51f0ad08

+ 6 - 6
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();
 }

+ 6 - 6
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)

+ 19 - 6
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);
 	}
 }
 

+ 6 - 6
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();
 }

+ 9 - 9
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());
 	}

+ 8 - 10
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;
-
-	// Same with the current clear color.
+	state.color = Color(255, 255, 255, 255);
+	GLfloat glcolor[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+	glVertexAttrib4fv(ATTRIB_COLOR, glcolor);
+
+	// 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;
 }
 

+ 11 - 11
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
 	{

+ 9 - 9
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();
 

+ 7 - 7
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)

+ 117 - 87
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<int> Shader::textureCounters;
@@ -178,18 +181,26 @@ void Shader::createProgram(const std::vector<GLuint> &shaderids)
 	if (program == 0)
 		throw love::Exception("Cannot create shader program object.");
 
-	for (GLuint id : shaderids)
-		glAttachShader(program, id);
+	try
+	{
+		for (GLuint id : shaderids)
+			glAttachShader(program, id);
+	}
+	catch (love::Exception &)
+	{
+		glDeleteProgram(program);
+		throw;
+	}
 
-	// Bind generic vertex attribute indices to names in the shader.
-	for (int i = 0; i < int(OpenGL::ATTRIB_MAX_ENUM); i++)
+	// Bind love's vertex attribute indices to names in the shader.
+	for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
 	{
-		OpenGL::VertexAttrib attrib = (OpenGL::VertexAttrib) 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<GLuint> &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<GLuint> &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<Shader::UniformType, Shader::UNIFORM_MAX_ENUM>::Entry Shader::uniformT
 
 StringMap<Shader::UniformType, Shader::UNIFORM_MAX_ENUM> Shader::uniformTypes(Shader::uniformTypeEntries, sizeof(Shader::uniformTypeEntries));
 
-StringMap<OpenGL::VertexAttrib, OpenGL::ATTRIB_MAX_ENUM>::Entry Shader::attribNameEntries[] =
+StringMap<VertexAttribID, ATTRIB_MAX_ENUM>::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<OpenGL::VertexAttrib, OpenGL::ATTRIB_MAX_ENUM> Shader::attribNames(Shader::attribNameEntries, sizeof(Shader::attribNameEntries));
+StringMap<VertexAttribID, ATTRIB_MAX_ENUM> Shader::attribNames(Shader::attribNameEntries, sizeof(Shader::attribNameEntries));
 
 StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM>::Entry Shader::builtinNameEntries[] =
 {

+ 13 - 7
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<ShaderType, std::string> 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<std::string, Uniform> uniforms;
@@ -248,8 +254,8 @@ private:
 	static StringMap<UniformType, UNIFORM_MAX_ENUM> uniformTypes;
 
 	// Names for the generic vertex attributes used by love.
-	static StringMap<OpenGL::VertexAttrib, OpenGL::ATTRIB_MAX_ENUM>::Entry attribNameEntries[];
-	static StringMap<OpenGL::VertexAttrib, OpenGL::ATTRIB_MAX_ENUM> attribNames;
+	static StringMap<VertexAttribID, ATTRIB_MAX_ENUM>::Entry attribNameEntries[];
+	static StringMap<VertexAttribID, ATTRIB_MAX_ENUM> attribNames;
 
 	// Names for the built-in uniform variables.
 	static StringMap<BuiltinUniform, BUILTIN_MAX_ENUM>::Entry builtinNameEntries[];

+ 9 - 9
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);
 	}
 

+ 21 - 0
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 },

+ 1 - 0
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);

+ 27 - 7
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

+ 47 - 17
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