Commits

vrld committed 6e0f6a4

Add Geometries (replaces Quads).

A Geometry is a collection of vertices describing a non self-intersecting
(simple) polygon. In addition to screen coordinates, the vertices have
attributes for texture coordinates (s,t) and color (r,g,b,a).

It can be used as a quad, to display distorted images, or anything in between.

Added:
^^^^^^

-- geometry from table, where table has the format:
-- info = {
-- {x,y, s,t, [r = 255, g = 255, b = 255, a = 255]}
-- {x,y, s,t, [r = 255, g = 255, b = 255, a = 255]}
-- ...
-- }
geom = love.graphics.newGeometry(info)

-- convenience wrapper for quads (same as before)
geom = love.graphics.newQuad(x,y, w,h, sw,sh)

-- retrieve vertex i (1-indexed)
x,y,s,t,r,g,b,a = geom:getVertex(i)

-- set vertex i (1-indexed)
geom:setVertex(i, x,y, s,t, [r,g,b,a])

-- flip geometry
geom:flip(x, y)

Renamed:
^^^^^^^^

love.graphics.drawq() -> love.graphics.drawg()

Removed:
^^^^^^^^

quad:setViewport()
quad:getViewport()

Comments (1)

Files changed (28)

src/common/math.h

 
 struct vertex
 {
+	vertex()
+		: r(255), g(255), b(255), a(255)
+		, x(0), y(0)
+		, s(0), t(0)
+	{}
+
+	vertex(float x, float y,
+	       float s, float t)
+		: r(255), g(255), b(255), a(255)
+		, x(x), y(y)
+		, s(s), t(t)
+	{}
+
+	vertex(float x, float y,
+	       float s, float t,
+	       unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+		: r(r), g(g), b(b), a(a)
+		, x(x), y(y)
+		, s(s), t(t)
+	{}
+
 	unsigned char r, g, b, a;
 	float x, y;
 	float s, t;

src/common/runtime.cpp

 	// Graphics
 	{"Drawable", GRAPHICS_DRAWABLE_ID},
 	{"Image", GRAPHICS_IMAGE_ID},
-	{"Quad", GRAPHICS_QUAD_ID},
+	{"Geometry", GRAPHICS_GEOMETRY_ID},
 	{"Font", GRAPHICS_FONT_ID},
 	{"ParticleSystem", GRAPHICS_PARTICLE_SYSTEM_ID},
 	{"SpriteBatch", GRAPHICS_SPRITE_BATCH_ID},

src/common/runtime.h

 enum Registry
 {
 	REGISTRY_GC = 1,
-	REGISTRY_MODULES,
+	REGISTRY_MODULES
 };
 
 /**

src/common/types.h

 
 	// Graphics
 	GRAPHICS_DRAWABLE_ID,
-	GRAPHICS_DRAWQABLE_ID,
+	GRAPHICS_DRAWGABLE_ID,
 	GRAPHICS_IMAGE_ID,
-	GRAPHICS_QUAD_ID,
+	GRAPHICS_GEOMETRY_ID,
 	GRAPHICS_FONT_ID,
 	GRAPHICS_PARTICLE_SYSTEM_ID,
 	GRAPHICS_SPRITE_BATCH_ID,
 
 // Graphics.
 const bits GRAPHICS_DRAWABLE_T = (bits(1) << GRAPHICS_DRAWABLE_ID) | OBJECT_T;
-const bits GRAPHICS_DRAWQABLE_T = (bits(1) << GRAPHICS_DRAWQABLE_ID) | GRAPHICS_DRAWABLE_T;
-const bits GRAPHICS_IMAGE_T = (bits(1) << GRAPHICS_IMAGE_ID) | GRAPHICS_DRAWQABLE_T;
-const bits GRAPHICS_QUAD_T = (bits(1) << GRAPHICS_QUAD_ID) | OBJECT_T;
+const bits GRAPHICS_DRAWGABLE_T = (bits(1) << GRAPHICS_DRAWGABLE_ID) | GRAPHICS_DRAWABLE_T;
+const bits GRAPHICS_IMAGE_T = (bits(1) << GRAPHICS_IMAGE_ID) | GRAPHICS_DRAWGABLE_T;
+const bits GRAPHICS_GEOMETRY_T = (bits(1) << GRAPHICS_GEOMETRY_ID) | OBJECT_T;
 const bits GRAPHICS_FONT_T = (bits(1) << GRAPHICS_FONT_ID) | OBJECT_T;
 const bits GRAPHICS_PARTICLE_SYSTEM_T = (bits(1) << GRAPHICS_PARTICLE_SYSTEM_ID) | GRAPHICS_DRAWABLE_T;
 const bits GRAPHICS_SPRITE_BATCH_T = (bits(1) << GRAPHICS_SPRITE_BATCH_ID) | GRAPHICS_DRAWABLE_T;
-const bits GRAPHICS_CANVAS_T = (bits(1) << GRAPHICS_CANVAS_ID) | GRAPHICS_DRAWQABLE_T;
+const bits GRAPHICS_CANVAS_T = (bits(1) << GRAPHICS_CANVAS_ID) | GRAPHICS_DRAWGABLE_T;
 const bits GRAPHICS_SHADER_T = (bits(1) << GRAPHICS_SHADER_ID) | OBJECT_T;
 
 // Image.

src/modules/graphics/DrawGable.cpp

+/**
+ * Copyright (c) 2006-2013 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "DrawGable.h"
+
+namespace love
+{
+namespace graphics
+{
+
+DrawGable::~DrawGable()
+{
+}
+
+} // graphics
+} // love

src/modules/graphics/DrawGable.h

+/**
+ * Copyright (c) 2006-2013 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_GRAPHICS_DRAWGABLE_H
+#define LOVE_GRAPHICS_DRAWGABLE_H
+
+// LOVE
+#include "Drawable.h"
+#include "Geometry.h"
+
+namespace love
+{
+namespace graphics
+{
+
+/**
+ * A DrawGable is anything that be drawn in part with a Geometry object.
+ **/
+class DrawGable : public Drawable
+{
+public:
+
+	/**
+	 * Destructor.
+	 **/
+	virtual ~DrawGable();
+
+	/**
+	 * Draws the object with the specified transformation.
+	 *
+	 * @param geom The Geometry object to use to draw the object.
+	 * @param x The position of the object along the x-axis.
+	 * @param y The position of the object along the y-axis.
+	 * @param angle The angle of the object (in radians).
+	 * @param sx The scale factor along the x-axis.
+	 * @param sy The scale factor along the y-axis.
+	 * @param ox The origin offset along the x-axis.
+	 * @param oy The origin offset along the y-axis.
+	 * @param kx Shear along the x-axis.
+	 * @param ky Shear along the y-axis.
+	 **/
+	virtual void drawg(Geometry *geom, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const = 0;
+};
+
+} // graphics
+} // love
+
+#endif // LOVE_GRAPHICS_DRAWGABLE_H

src/modules/graphics/Geometry.cpp

+/**
+ * Copyright (c) 2006-2012 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "Geometry.h"
+#include "common/Exception.h"
+#include "modules/math/MathModule.h"
+
+using love::math::Math;
+
+// STD
+#include <limits>
+#include <algorithm> // for std::swap()
+#include <cstring> // For memcpy
+
+namespace love
+{
+namespace graphics
+{
+
+
+Geometry::Geometry(const std::vector<vertex> &p)
+	: polygon(p)
+	, vertexArray(NULL)
+	, x_min(std::numeric_limits<float>::max())
+	, x_max(std::numeric_limits<float>::min())
+	, y_min(std::numeric_limits<float>::max())
+	, y_max(std::numeric_limits<float>::min())
+{
+	for (size_t i = 0; i < polygon.size(); ++i)
+	{
+		const vertex &v = polygon[i];
+		x_min = v.x < x_min ? v.x : x_min;
+		x_max = v.x > x_max ? v.x : x_max;
+		y_min = v.y < y_min ? v.y : y_min;
+		y_max = v.y > y_max ? v.y : y_max;
+	}
+
+	triangulate();
+}
+
+Geometry::Geometry(float x, float y, float w, float h, float sw, float sh)
+	: vertexArray(NULL)
+	, x_min(x)
+	, x_max(x+w)
+	, y_min(y)
+	, y_max(y+h)
+{
+	float s0 = x/sw, s1 = (x+w)/sw, t0 = y/sh, t1 = (y+h)/sh;
+	polygon.resize(4);
+	polygon[0] = vertex(0,0, s0,t0);
+	polygon[1] = vertex(w,0, s1,t0);
+	polygon[2] = vertex(w,h, s1,t1);
+	polygon[3] = vertex(0,h, s0,t1);
+
+	triangulate();
+}
+
+Geometry::Geometry(const Geometry &other)
+	: polygon(other.polygon)
+	, vertexCount(other.vertexCount)
+	, x_min(other.x_min)
+	, x_max(other.x_max)
+	, y_min(other.y_min)
+	, y_max(other.y_max)
+{
+	vertexArray = new vertex[vertexCount];
+	memcpy(vertexArray, other.vertexArray, vertexCount * sizeof(vertex));
+}
+
+Geometry &Geometry::operator=(const Geometry &other)
+{
+	if (this != &other)
+	{
+		Geometry temp(other);
+		std::swap(polygon, temp.polygon);
+		std::swap(vertexArray, temp.vertexArray);
+
+		vertexCount = temp.vertexCount;
+		x_min       = temp.x_min;
+		x_max       = temp.x_max;
+		y_min       = temp.y_min;
+		y_max       = temp.y_max;
+	}
+	return *this;
+}
+
+Geometry::~Geometry()
+{
+	if (vertexArray)
+	{
+		delete[] vertexArray;
+		vertexArray = NULL;
+	}
+}
+
+const vertex &Geometry::getVertex(size_t i) const
+{
+	if (i >= polygon.size())
+		throw Exception("Invalid vertex index");
+	return polygon[i];
+}
+
+void Geometry::setVertex(size_t i, const vertex &v)
+{
+	if (i >= polygon.size())
+		throw Exception("Invalid vertex index");
+
+	polygon[i] = v;
+	x_min = v.x < x_min ? v.x : x_min;
+	x_max = v.x > x_max ? v.x : x_max;
+	y_min = v.y < y_min ? v.y : y_min;
+	y_max = v.y > y_max ? v.y : y_max;
+
+	triangulate();
+}
+
+void Geometry::flip(bool x, bool y)
+{
+	for (size_t i = 0; i < vertexCount; ++i)
+	{
+		vertex &v = vertexArray[i];
+		if (x) v.x = x_max + x_min - v.x;
+		if (y) v.y = y_max + y_min - v.y;
+	}
+}
+
+void Geometry::triangulate()
+{
+	const std::vector<Triangle> triangles = Math::instance.triangulate(polygon);
+
+	if (vertexArray)
+		delete[] vertexArray;
+
+	vertexCount = triangles.size() * 3;
+	vertexArray = new vertex[vertexCount];
+
+	for (size_t i = 0; i < triangles.size(); ++i)
+	{
+		const Triangle &t = triangles[i];
+		vertexArray[i*3]   = t.a;
+		vertexArray[i*3+1] = t.b;
+		vertexArray[i*3+2] = t.c;
+	}
+}
+
+} // graphics
+} // love

src/modules/graphics/Geometry.h

+/**
+ * Copyright (c) 2006-2012 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_GRAPHICS_GEOMETRY_H
+#define LOVE_GRAPHICS_GEOMETRY_H
+
+// LOVE
+#include "common/Object.h"
+#include "common/math.h"
+
+// std
+#include <vector>
+
+namespace love
+{
+namespace graphics
+{
+
+class Geometry : public Object
+{
+public:
+	/**
+	 * Creates a new geometry object from a std::vector<vertex>.
+	 * @param v
+	 **/
+	Geometry(const std::vector<vertex> &polygon);
+
+	/**
+	 * Creates a new geometry from (texture) quad information.
+	 * @param x Top left position in the image.
+	 * @param y Top left position in the image.
+	 * @param w Width of the quad.
+	 * @param h Height of the quad.
+	 * @param sw The reference width, the width of the Image.
+	 * @param sh The reference height, the height of the Image.
+	 */
+	Geometry(float x, float y, float w, float h, float sw, float sh);
+
+	Geometry(const Geometry &other);
+	Geometry &operator=(const Geometry &other);
+	virtual ~Geometry();
+
+	/**
+	 * Returns number of vertices in the *polygon* defining the geometry.
+	 **/
+	size_t getNumVertices() const
+	{
+		return polygon.size();
+	}
+
+	const vertex &getVertex(size_t i) const;
+	void setVertex(size_t i, const vertex &v);
+
+	void flip(bool x, bool y);
+
+	/**
+	 * Returns a pointer to the vertex array.
+	 **/
+	const vertex *getVertexArray() const
+	{
+		return vertexArray;
+	}
+
+	/**
+	 * Returns the size of the vertex array.
+	 **/
+	size_t getVertexArraySize() const
+	{
+		return vertexCount;
+	}
+
+private:
+	void triangulate();
+
+	std::vector<vertex> polygon;
+
+	vertex *vertexArray;
+	size_t vertexCount;
+
+	float x_min;
+	float x_max;
+
+	float y_min;
+	float y_max;
+};
+
+} // graphics
+} // love
+
+#endif // LOVE_GRAPHICS_GEOMETRY_H

src/modules/graphics/Image.h

 
 // LOVE
 #include "graphics/Volatile.h"
-#include "graphics/DrawQable.h"
+#include "graphics/DrawGable.h"
 #include "common/StringMap.h"
 
 namespace love
 namespace graphics
 {
 
-class Image : public DrawQable, public Volatile
+class Image : public DrawGable, public Volatile
 {
 public:
 

src/modules/graphics/opengl/Canvas.cpp

 #include "common/config.h"
 
 #include <cstring> // For memcpy
+#include <limits>
 
 namespace love
 {
 	/**
 	 * @param[in] canvases List of canvases to attach
 	 **/
-	virtual void setAttachments(const std::vector<Canvas *> &canvases) {}
+	virtual void setAttachments(const std::vector<Canvas *> &canvases) { (void)canvases; }
 
 	/// stop using all additional attached canvases
 	virtual void setAttachments() {}
 		drawbuffers.push_back(GL_COLOR_ATTACHMENT0);
 
 		// attach the canvas framebuffer textures to the currently bound framebuffer
-		for (int i = 0; i < canvases.size(); i++)
+		for (size_t 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_ATTACHMENT0_EXT);
 
 		// attach the canvas framebuffer textures to the currently bound framebuffer
-		for (int i = 0; i < canvases.size(); i++)
+		for (size_t i = 0; i < canvases.size(); i++)
 		{
 			glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1_EXT + i,
 								   GL_TEXTURE_2D, canvases[i]->getTextureName(), 0);
 		if (!isMultiCanvasSupported())
 			throw love::Exception("Multi-canvas rendering is not supported on this system.");
 
-		if (canvases.size()+1 > maxDrawBuffers || canvases.size()+1 > maxFBOColorAttachments)
+		if (canvases.size()+1 > size_t(maxDrawBuffers) || canvases.size()+1 > size_t(maxFBOColorAttachments))
 			throw love::Exception("This system can't simultaniously render to %d canvases.", canvases.size()+1);
 	}
 
 	drawv(t, vertices);
 }
 
-void Canvas::drawq(love::graphics::Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
+void Canvas::drawg(love::graphics::Geometry *geom, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
 {
-	const vertex *v = quad->getVertices();
-
-	// mirror quad on x axis
-	vertex w[4];
-	memcpy(w, v, sizeof(vertex)*4);
-	for (size_t i = 0; i < 4; ++i)
-		w[i].t = 1. - w[i].t;
-
 	static Matrix t;
 	t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
 
-	drawv(t, w);
+	// flip texture coordinates vertically
+	size_t vcount = geom->getVertexArraySize();
+	const vertex *w = geom->getVertexArray();
+	vertex *v = new vertex[vcount];
+	for (size_t i = 0; i < vcount; ++i)
+	{
+		v[i] = w[i];
+		v[i].t = 1. - v[i].t;
+	}
+
+	// use colors stored in geometry (horrible, horrible hack)
+	glEnableClientState(GL_COLOR_ARRAY);
+	glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vertex), (GLvoid *)&v->r);
+	drawv(t, v, vcount, GL_TRIANGLES);
+	glDisableClientState(GL_COLOR_ARRAY);
+	delete[] v;
 }
 
 love::image::ImageData *Canvas::getImageData(love::image::Image *image)
 	return height;
 }
 
-void Canvas::drawv(const Matrix &t, const vertex *v) const
+void Canvas::drawv(const Matrix &t, const vertex *v, GLsizei count, GLenum mode) const
 {
 	glPushMatrix();
 
 
 	glEnableClientState(GL_VERTEX_ARRAY);
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	// XXX: drawg() enables/disables GL_COLOR_ARRAY in order to use the color
+	//      defined in the geometry to draw itself.
+	//      if the drawing method below is changed to use something other than
+	//      glDrawArrays(), drawg() needs to be updated accordingly!
 	glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&v[0].x);
 	glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&v[0].s);
-	glDrawArrays(GL_QUADS, 0, 4);
+	glDrawArrays(mode, 0, count);
+
 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 	glDisableClientState(GL_VERTEX_ARRAY);
 

src/modules/graphics/opengl/Canvas.h

 #ifndef LOVE_GRAPHICS_OPENGL_CANVAS_H
 #define LOVE_GRAPHICS_OPENGL_CANVAS_H
 
-// LOVE
-#include "graphics/DrawQable.h"
+#include "graphics/DrawGable.h"
 #include "graphics/Volatile.h"
 #include "graphics/Image.h"
 #include "graphics/Color.h"
 #include "common/Matrix.h"
 #include "OpenGL.h"
 
-// STL
-#include <vector>
-
 namespace love
 {
 namespace graphics
 namespace opengl
 {
 
-class Canvas : public DrawQable, public Volatile
+class Canvas : public DrawGable, public Volatile
 {
 public:
 	enum TextureType {
 	virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
 
 	/**
-	 * @copydoc DrawQable::drawq()
+	 * @copydoc DrawGable::drawg()
 	 **/
-	void drawq(love::graphics::Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
+	void drawg(love::graphics::Geometry *geom, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
 
 	love::image::ImageData *getImageData(love::image::Image *image);
 
 
 	const std::vector<Canvas *> &getAttachedCanvases() const;
 
-	void setFilter(const Image::Filter &f);
+void setFilter(const Image::Filter &f);
 	Image::Filter getFilter() const;
 
 	void setWrap(const Image::Wrap &w);
 	std::vector<Canvas *> attachedCanvases;
 
 	void setupGrab();
-	void drawv(const Matrix &t, const vertex *v) const;
+	void drawv(const Matrix &t, const vertex *v, GLsizei count = 4, GLenum mode = GL_QUADS) const;
 
 	static StringMap<TextureType, TYPE_MAX_ENUM>::Entry textureTypeEntries[];
 	static StringMap<TextureType, TYPE_MAX_ENUM> textureTypes;

src/modules/graphics/opengl/Font.cpp

 #include "common/config.h"
 #include "Font.h"
 #include "font/GlyphData.h"
-#include "Quad.h"
+#include "modules/graphics/Geometry.h"
 #include "Image.h"
 
 #include "libraries/utf8/utf8.h"
 
 		g->texture = t;
 
-		Quad::Viewport v;
-		v.x = (float) textureX;
-		v.y = (float) textureY;
-		v.w = (float) w;
-		v.h = (float) h;
-
-		Quad q = Quad(v, (const float) textureWidth, (const float) textureHeight);
-		const vertex *verts = q.getVertices();
+		const vertex verts[4] = {
+			vertex(0, 0, float(textureX)/float(textureWidth),   float(textureY)/float(textureHeight)),
+			vertex(w, 0, float(textureX+w)/float(textureWidth), float(textureY)/float(textureHeight)),
+			vertex(w, h, float(textureX+w)/float(textureWidth), float(textureY+h)/float(textureHeight)),
+			vertex(0, h, float(textureX)/float(textureWidth),   float(textureY+h)/float(textureHeight)),
+		};
 
 		// copy vertex data to the glyph and set proper bearing
 		for (int i = 0; i < 4; i++)

src/modules/graphics/opengl/Graphics.cpp

 	setColorMask(s.colorMask[0], s.colorMask[1], s.colorMask[2], s.colorMask[3]);
 }
 
+static void APIENTRY myErrorCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const char *message, void *ud)
+{
+	(void)ud;
+	std::cerr << "source = " << source << ", type = " << type << ", id = " << id << ", severity = " << severity << ", length = " << length << "\n" << message << std::endl;
+}
+
 bool Graphics::setMode(int width, int height, WindowFlags *flags)
 {
 	// This operation destroys the OpenGL context, so
 	glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &matrixLimit);
 	matrixLimit -= 5;
 
+	if (GLEE_ARB_debug_output)
+	{
+		std::cerr << "debug on" << std::endl;
+		glDebugMessageCallbackARB(myErrorCallback, NULL);
+		glEnable(GL_DEBUG_OUTPUT);
+	}
+
 	return success;
 }
 
 	return image;
 }
 
-Quad *Graphics::newQuad(float x, float y, float w, float h, float sw, float sh)
+Geometry *Graphics::newGeometry(const std::vector<vertex> &vertices)
 {
-	Quad::Viewport v;
-	v.x = x;
-	v.y = y;
-	v.w = w;
-	v.h = h;
-	return new Quad(v, sw, sh);
+	return new Geometry(vertices);
+}
+
+Geometry *Graphics::newQuad(float x, float y, float w, float h, float sw, float sh)
+{
+	return new Geometry(x, y, w, h, sw, sh);
 }
 
 Font *Graphics::newFont(love::font::Rasterizer *r, const Image::Filter &filter)

src/modules/graphics/opengl/Graphics.h

 
 #include "Font.h"
 #include "Image.h"
-#include "Quad.h"
+#include "graphics/Geometry.h"
 #include "SpriteBatch.h"
 #include "ParticleSystem.h"
 #include "Canvas.h"
 	Image *newImage(love::image::CompressedData *cdata);
 
 	/**
-	 * Creates a Quad object.
+	 * Creates a Geometry object.
 	 **/
-	Quad *newQuad(float x, float y, float w, float h, float sw, float sh);
+	Geometry *newGeometry(const std::vector<vertex> &vertices);
+
+	/**
+	 * Creates a quadliteral Geometry object.
+	 **/
+	Geometry *newQuad(float x, float y, float w, float h, float sw, float sh);
 
 	/**
 	 * Creates a Font object.

src/modules/graphics/opengl/Image.cpp

 	drawv(t, vertices);
 }
 
-void Image::drawq(love::graphics::Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
+void Image::drawg(love::graphics::Geometry *geom, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
 {
 	static Matrix t;
-	const vertex *v = quad->getVertices();
+	t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
 
-	t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
-	drawv(t, v);
+	// use colors stored in geometry (horrible, horrible hack)
+	const vertex *v = geom->getVertexArray();
+
+	glEnableClientState(GL_COLOR_ARRAY);
+	glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vertex), (GLvoid *)&v->r);
+	drawv(t, v, geom->getVertexArraySize(), GL_TRIANGLES);
+	glDisableClientState(GL_COLOR_ARRAY);
 }
 
 void Image::uploadCompressedMipmaps()
 	return true;
 }
 
-void Image::drawv(const Matrix &t, const vertex *v) const
+void Image::drawv(const Matrix &t, const vertex *v, GLsizei count, GLenum mode) const
 {
 	bind();
 
 
 	glEnableClientState(GL_VERTEX_ARRAY);
 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	// XXX: drawg() enables/disables GL_COLOR_ARRAY in order to use the color
+	//      defined in the geometry to draw itself.
+	//      if the drawing method below is changed to use something other than
+	//      glDrawArrays(), drawg() needs to be updated accordingly!
 	glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&v[0].x);
 	glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&v[0].s);
-	glDrawArrays(GL_QUADS, 0, 4);
+	glDrawArrays(mode, 0, count);
+
 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 	glDisableClientState(GL_VERTEX_ARRAY);
 

src/modules/graphics/opengl/Image.h

 	void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
 
 	/**
-	 * @copydoc DrawQable::drawq()
+	 * @copydoc DrawGable::drawg()
 	 **/
-	void drawq(love::graphics::Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
+	void drawg(love::graphics::Geometry *geom, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
 
 	/**
 	 * Sets the filter mode.
 
 private:
 
-	void drawv(const Matrix &t, const vertex *v) const;
+	void drawv(const Matrix &t, const vertex *v, GLsizei count = 4, GLenum mode = GL_QUADS) const;
 
 	friend class Shader;
 	GLuint getTextureName() const

src/modules/graphics/opengl/ParticleSystem.cpp

 
 ParticleSystem::~ParticleSystem()
 {
-	for (size_t i = 0; i < quads.size(); i++)
-		quads[i]->release();
-
 	if (this->image != 0)
 		this->image->release();
 
 	return ncolors;
 }
 
-void ParticleSystem::setQuads(const std::vector<Quad *> &newQuads)
-{
-	for (size_t i = 0; i < quads.size(); i++)
-		quads[i]->release();
-
-	quads.resize(newQuads.size());
-
-	for (size_t i = 0; i < newQuads.size(); i++)
-	{
-		quads[i] = newQuads[i];
-		quads[i]->retain();
-	}
-}
-
-void ParticleSystem::setQuads()
-{
-	for (size_t i = 0; i < quads.size(); i++)
-		quads[i]->release();
-
-	quads.resize(0);
-}
-
-const std::vector<Quad *> &ParticleSystem::getQuads() const
-{
-	return quads;
-}
-
 int ParticleSystem::count() const
 {
 	return (int)(pLast - pStart);
 	const vertex *imageVerts = image->getVertices();
 	const vertex *tVerts;
 
-	size_t numQuads = quads.size();
-
 	// set the vertex data for each particle (transformation, texcoords, color)
 	for (int i = 0; i < numParticles; i++)
 	{
 		particle *p = pStart + i;
 
-		if (numQuads > 0)
-		{
-			// Make sure the quad index is valid
-			size_t quadIndex = (p->quadIndex >= numQuads) ? numQuads - 1 : p->quadIndex;
-			tVerts = quads[quadIndex]->getVertices();
-		}
-		else
-			tVerts = imageVerts;
+		tVerts = imageVerts;
 
 		// particle vertices are image vertices transformed by particle information
 		t.setTransformation(p->position[0], p->position[1], p->rotation, p->size, p->size, offsetX, offsetY, 0.0f, 0.0f);
 			s -= (float)i;                            // 0 <= s <= 1
 			p->color = colors[i] * (1.0f - s) + colors[k] * s;
 
-			// Update quad index
-			k = quads.size();
-			if (k > 0)
-			{
-				s = t * (float) k; // [0:numquads-1]
-				i = (s > 0) ? (size_t) s : 0;
-				p->quadIndex = (i < k) ? i : k - 1;
-			}
-			else
-				p->quadIndex = 0;
-
 			// Next particle.
 			p++;
 		}

src/modules/graphics/opengl/ParticleSystem.h

 #include "common/Vector.h"
 #include "graphics/Drawable.h"
 #include "graphics/Color.h"
-#include "Quad.h"
 #include "Image.h"
 #include <vector>
 
 	float spinEnd;
 
 	Colorf color;
-
-	size_t quadIndex;
 };
 
 /**
 		DISTRIBUTION_NONE,
 		DISTRIBUTION_UNIFORM,
 		DISTRIBUTION_NORMAL,
-		DISTRIBUTION_MAX_ENUM,
+		DISTRIBUTION_MAX_ENUM
 	};
 
 	/**
 	std::vector<Color> getColor() const;
 
 	/**
-	 * Sets the quads used when drawing the particles.
-	 * @param newQuads Array of quads.
-	 **/
-	void setQuads(const std::vector<Quad *> &newQuads);
-
-	/**
-	 * Removes all quads from the particle system.
-	 **/
-	void setQuads();
-
-	/**
-	 * Returns the list of quads used when drawing the particles.
-	 **/
-	const std::vector<Quad *> &getQuads() const;
-
-	/**
 	 * Returns the amount of particles that are currently active in the system.
 	 **/
 	int count() const;
 	// Color.
 	std::vector<Colorf> colors;
 
-	std::vector<Quad *> quads;
-
 	void add();
 	void remove(particle *p);
 

src/modules/graphics/opengl/SpriteBatch.cpp

 
 // LOVE
 #include "Image.h"
-#include "Quad.h"
+#include "modules/graphics/Geometry.h"
 #include "VertexBuffer.h"
 
 namespace love
 	return index;
 }
 
-int SpriteBatch::addq(Quad *quad, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky, int index /*= -1*/)
+int SpriteBatch::addg(Geometry *geom, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky, int index /*= -1*/)
 {
 	// Only do this if there's a free slot.
 	if ((index == -1 && next >= size) || index < -1 || index >= next)
 		return -1;
 
 	// Needed for colors.
-	memcpy(sprite, quad->getVertices(), sizeof(vertex)*4);
+	size_t vcount = geom->getVertexArraySize();
+	memcpy(sprite, geom->getVertexArray(), vcount * sizeof(vertex));
 
 	// Transform.
 	Matrix t;
 	t.setTransformation(x, y, a, sx, sy, ox, oy, kx, ky);
-	t.transform(sprite, sprite, 4);
+	t.transform(sprite, sprite, vcount);
 
 	if (color)
 		setColorv(sprite, *color);
 
-	addv(sprite, (index == -1) ? next : index);
+	addv(sprite, (index == -1) ? next : index, vcount);
 
 	// Increment counter.
 	if (index == -1)
 	glPopMatrix();
 }
 
-void SpriteBatch::addv(const vertex *v, int index)
+void SpriteBatch::addv(const vertex *v, int index, int sprite_size)
 {
-	int sprite_size = sizeof(vertex) * 4;
-
+	sprite_size *= sizeof(vertex); // bytecount
 	VertexBuffer::Bind bind(*array_buf);
-
 	array_buf->fill(index * sprite_size, sprite_size, v);
 }
 

src/modules/graphics/opengl/SpriteBatch.h

 #include "graphics/Drawable.h"
 #include "graphics/Volatile.h"
 #include "graphics/Color.h"
+#include "graphics/Geometry.h"
 
 namespace love
 {
 
 // Forward declarations.
 class Image;
-class Quad;
 class VertexBuffer;
 class VertexIndex;
 
 	virtual ~SpriteBatch();
 
 	int add(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky, int index = -1);
-	int addq(Quad *quad, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky, int index = -1);
+	int addg(Geometry *geom, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky, int index = -1);
 	void clear();
 
 	void *lock();
 	void setColor(const Color &color);
 
 	/**
-	 * Disable per-quad colors for this SpriteBatch. The next call to
+	 * Disable per-geometry colors for this SpriteBatch. The next call to
 	 * draw will use the global color for all sprites.
 	 */
 	void setColor();
 
 private:
 
-	void addv(const vertex *v, int index);
+	void addv(const vertex *v, int index, int sprite_size = 4);
 
 	/**
 	 * Set the color for vertices.
 	vertex sprite[4];
 
 	// Current color. This color, if present, will be applied to the next
-	// added quad.
+	// added geometry.
 	Color *color;
 
 	VertexBuffer *array_buf;

src/modules/graphics/opengl/wrap_Geometry.cpp

+/**
+ * Copyright (c) 2006-2013 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+// LOVE
+#include "wrap_Geometry.h"
+#include "common/Exception.h"
+
+namespace love
+{
+namespace graphics
+{
+namespace opengl
+{
+
+Geometry *luax_checkgeometry(lua_State *L, int idx)
+{
+	return luax_checktype<Geometry>(L, idx, "Geometry", GRAPHICS_GEOMETRY_T);
+}
+
+// different name than in Geometry.cpp to make the triangulation transparent
+int w_Geometry_getVertexCount(lua_State *L)
+{
+	Geometry *geom = luax_checktype<Geometry>(L, 1, "Geometry", GRAPHICS_GEOMETRY_T);
+	lua_pushinteger(L, geom->getNumVertices());
+	return 1;
+}
+
+int w_Geometry_getVertex(lua_State *L)
+{
+	Geometry *geom = luax_checktype<Geometry>(L, 1, "Geometry", GRAPHICS_GEOMETRY_T);
+	size_t i = size_t(luaL_checkint(L, 2));
+	try
+	{
+		const vertex &v = geom->getVertex(i-1);
+		lua_pushnumber(L, v.x);
+		lua_pushnumber(L, v.y);
+		lua_pushnumber(L, v.s);
+		lua_pushnumber(L, v.t);
+		lua_pushnumber(L, v.r);
+		lua_pushnumber(L, v.g);
+		lua_pushnumber(L, v.b);
+		lua_pushnumber(L, v.a);
+	}
+	catch (Exception &e)
+	{
+		return luaL_error(L, e.what());
+	}
+
+	return 8;
+}
+
+int w_Geometry_setVertex(lua_State *L)
+{
+	Geometry *geom = luax_checktype<Geometry>(L, 1, "Geometry", GRAPHICS_GEOMETRY_T);
+	size_t i = size_t(luaL_checkint(L, 2));
+
+	vertex v;
+	v.x = luaL_checknumber(L, 3);
+	v.y = luaL_checknumber(L, 4);
+	v.s = luaL_checknumber(L, 5);
+	v.t = luaL_checknumber(L, 6);
+	v.r = luaL_optint(L,  7, 255);
+	v.g = luaL_optint(L,  8, 255);
+	v.b = luaL_optint(L,  9, 255);
+	v.a = luaL_optint(L, 10, 255);
+
+	try
+	{
+		geom->setVertex(i-1, v);
+	}
+	catch (Exception &e)
+	{
+		return luaL_error(L, e.what());
+	}
+
+	return 0;
+}
+
+int w_Geometry_flip(lua_State *L)
+{
+	Geometry *geom = luax_checktype<Geometry>(L, 1, "Geometry", GRAPHICS_GEOMETRY_T);
+	geom->flip(luax_toboolean(L, 2), luax_toboolean(L, 3));
+	return 0;
+}
+
+static const luaL_Reg w_Geometry_functions[] =
+{
+	{ "getVertexCount", w_Geometry_getVertexCount },
+	{ "getVertex", w_Geometry_getVertex },
+	{ "setVertex", w_Geometry_setVertex },
+	{ "flip", w_Geometry_flip },
+	{ 0, 0 }
+};
+
+extern "C" int luaopen_geometry(lua_State *L)
+{
+	return luax_register_type(L, "Geometry", w_Geometry_functions);
+}
+
+} // opengl
+} // graphics
+} // love

src/modules/graphics/opengl/wrap_Geometry.h

+/**
+ * Copyright (c) 2006-2013 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#ifndef LOVE_GRAPHICS_OPENGL_WRAP_GEOMETRY_H
+#define LOVE_GRAPHICS_OPENGL_WRAP_GEOMETRY_H
+
+// LOVE
+#include "common/runtime.h"
+#include "graphics/Geometry.h"
+
+namespace love
+{
+namespace graphics
+{
+namespace opengl
+{
+
+Geometry *luax_checkgeometry(lua_State *L, int idx);
+int w_Geometry_flip(lua_State *L);
+int w_Geometry_getVertexCount(lua_State *L);
+int w_Geometry_getVertex(lua_State *L);
+int w_Geometry_setVertex(lua_State *L);
+extern "C" int luaopen_geometry(lua_State *L);
+
+} // opengl
+} // graphics
+} // love
+
+#endif // LOVE_GRAPHICS_OPENGL_WRAP_GEOMETRY_H

src/modules/graphics/opengl/wrap_Graphics.cpp

 
 #include "wrap_Graphics.h"
 #include "OpenGL.h"
-#include "graphics/DrawQable.h"
+#include "graphics/DrawGable.h"
 #include "image/ImageData.h"
 #include "font/Rasterizer.h"
 
 	return 1;
 }
 
+int w_newGeometry(lua_State *L)
+{
+	std::vector<vertex> vertices;
+	if (!lua_istable(L, 1))
+		return luaL_typerror(L, 1, "table");
+
+	size_t n = lua_objlen(L, 1);
+	if (n < 3)
+		return luaL_error(L, "Need at least three points to construct a geometry.");
+
+	vertices.reserve(n);
+	for (size_t i = 0; i < n; ++i)
+	{
+		vertex v;
+		lua_rawgeti(L, 1, i+1);
+		if (!lua_istable(L, -1))
+			return luaL_typerror(L, 1, "table of tables");
+
+		lua_rawgeti(L, -1, 1);
+		v.x = luaL_checknumber(L, -1);
+
+		lua_rawgeti(L, -2, 2);
+		v.y = luaL_checknumber(L, -1);
+
+		lua_rawgeti(L, -3, 3);
+		v.s = luaL_checknumber(L, -1);
+
+		lua_rawgeti(L, -4, 4);
+		v.t = luaL_checknumber(L, -1);
+
+		lua_rawgeti(L, -5, 5);
+		v.r = luaL_optint(L, -1, 255);
+
+		lua_rawgeti(L, -6, 6);
+		v.g = luaL_optint(L, -1, 255);
+
+		lua_rawgeti(L, -7, 7);
+		v.b = luaL_optint(L, -1, 255);
+
+		lua_rawgeti(L, -8, 8);
+		v.a = luaL_optint(L, -1, 255);
+
+		lua_pop(L, 9);
+		vertices.push_back(v);
+	}
+
+	Geometry *geom = instance->newGeometry(vertices);
+
+	if (geom == 0)
+		return luaL_error(L, "Could not create geometry.");
+
+	luax_newtype(L, "Geometry", GRAPHICS_GEOMETRY_T, (void *)geom);
+	return 1;
+}
+
 int w_newQuad(lua_State *L)
 {
 	float x = (float) luaL_checknumber(L, 1);
 	float sw = (float) luaL_checknumber(L, 5);
 	float sh = (float) luaL_checknumber(L, 6);
 
-	Quad *quad = instance->newQuad(x, y, w, h, sw, sh);
+	Geometry *quad = instance->newQuad(x, y, w, h, sw, sh);
 
-	luax_newtype(L, "Quad", GRAPHICS_QUAD_T, (void *)quad);
+	luax_newtype(L, "Geometry", GRAPHICS_GEOMETRY_T, (void *)quad);
 	return 1;
 }
 
 		canvas = luax_checkcanvas(L, -1);
 		lua_pop(L, 1);
 
-		for (int i = 2; i <= lua_objlen(L, 1); i++)
+		for (size_t i = 2; i <= lua_objlen(L, 1); i++)
 		{
 			lua_rawgeti(L, 1, i);
 			attachments.push_back(luax_checkcanvas(L, -1));
 }
 
 /**
- * Draws an Quad of a DrawQable at the specified coordinates,
+ * Draws a portion of a DrawGable at the specified coordinates,
  * with rotation and scaling along both axes.
  *
  * @param q The Quad to draw.
  * @param kx Shear along the x-axis.
  * @param ky Shear along the y-axis.
  **/
-int w_drawq(lua_State *L)
+int w_drawg(lua_State *L)
 {
-	DrawQable *dq = luax_checktype<DrawQable>(L, 1, "DrawQable", GRAPHICS_DRAWQABLE_T);
-	Quad *q = luax_checkquad(L, 2);
+	DrawGable *dq = luax_checktype<DrawGable>(L, 1, "DrawGable", GRAPHICS_DRAWGABLE_T);
+	Geometry *geom = luax_checkgeometry(L, 2);
 	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 oy = (float)luaL_optnumber(L, 9, 0);
 	float kx = (float)luaL_optnumber(L, 10, 0);
 	float ky = (float)luaL_optnumber(L, 11, 0);
-	dq->drawq(q, x, y, angle, sx, sy, ox, oy, kx, ky);
+	dq->drawg(geom, x, y, angle, sx, sy, ox, oy, kx, ky);
 	return 0;
 }
 
 
 	{ "newImage", w_newImage },
 	{ "newQuad", w_newQuad },
+	{ "newGeometry", w_newGeometry },
 	{ "newFont", w_newFont },
 	{ "newImageFont", w_newImageFont },
 	{ "newSpriteBatch", w_newSpriteBatch },
 	{ "isSupported", w_isSupported },
 
 	{ "draw", w_draw },
-	{ "drawq", w_drawq },
+	{ "drawq", w_drawg }, // legacy
+	{ "drawg", w_drawg },
 
 	{ "print", w_print },
 	{ "printf", w_printf },
 {
 	luaopen_font,
 	luaopen_image,
-	luaopen_quad,
+	luaopen_geometry,
 	luaopen_spritebatch,
 	luaopen_particlesystem,
 	luaopen_canvas,

src/modules/graphics/opengl/wrap_Graphics.h

 // LOVE
 #include "wrap_Font.h"
 #include "wrap_Image.h"
-#include "wrap_Quad.h"
+#include "wrap_Geometry.h"
 #include "wrap_SpriteBatch.h"
 #include "wrap_ParticleSystem.h"
 #include "wrap_Canvas.h"
 int w_setAlphaTest(lua_State *L);
 int w_getAlphaTest(lua_State *L);
 int w_newImage(lua_State *L);
-int w_newQuad(lua_State *L);
+int w_newGeometry(lua_State *L);
 int w_newQuad(lua_State *L);
 int w_newFont(lua_State *L);
 int w_newImageFont(lua_State *L);
 int w_getShader(lua_State *L);
 int w_isSupported(lua_State *L);
 int w_draw(lua_State *L);
-int w_drawq(lua_State *L);
+int w_drawg(lua_State *L);
 int w_print(lua_State *L);
 int w_printf(lua_State *L);
 int w_point(lua_State *L);

src/modules/graphics/opengl/wrap_ParticleSystem.cpp

  **/
 
 #include "wrap_ParticleSystem.h"
-#include "wrap_Quad.h"
 
 #include "common/Vector.h"
 
 	return colors.size();
 }
 
-int w_ParticleSystem_setQuads(lua_State *L)
-{
-	ParticleSystem *t = luax_checkparticlesystem(L, 1);
-
-	int nQuads = lua_gettop(L) - 1;
-	if (lua_istable(L, 2))
-		nQuads = lua_objlen(L, 2);
-
-	// Remove all quads if no argument is given.
-	if (nQuads == 0)
-	{
-		t->setQuads();
-		return 0;
-	}
-
-	std::vector<Quad *> quads(nQuads);
-
-	if (lua_istable(L, 2))
-	{
-		for (int i = 0; i < nQuads; i++)
-		{
-			lua_rawgeti(L, 2, i + 1); // array index
-			quads[i] = luax_checkquad(L, -1);
-			lua_pop(L, 1);
-		}
-	}
-	else
-	{
-		for (int i = 0; i < nQuads; i++)
-			quads[i] = luax_checkquad(L, i + 2);
-	}
-
-	t->setQuads(quads);
-
-	return 0;
-}
-
-int w_ParticleSystem_getQuads(lua_State *L)
-{
-	ParticleSystem *t = luax_checkparticlesystem(L, 1);
-
-	const std::vector<Quad *> &quads = t->getQuads();
-
-	for (size_t i = 0; i < quads.size(); i++)
-	{
-		quads[i]->retain();
-		luax_newtype(L, "Quad", GRAPHICS_QUAD_T, (void *) quads[i]);
-	}
-
-	return quads.size();
-}
-
 int w_ParticleSystem_count(lua_State *L)
 {
 	ParticleSystem *t = luax_checkparticlesystem(L, 1);
 	{ "getSpinVariation", w_ParticleSystem_getSpinVariation },
 	{ "setColors", w_ParticleSystem_setColors },
 	{ "getColors", w_ParticleSystem_getColors },
-	{ "setQuads", w_ParticleSystem_setQuads },
-	{ "getQuads", w_ParticleSystem_getQuads },
 	{ "setOffset", w_ParticleSystem_setOffset },
 	{ "getOffset", w_ParticleSystem_getOffset },
 	{ "count", w_ParticleSystem_count },

src/modules/graphics/opengl/wrap_ParticleSystem.h

 int w_ParticleSystem_getSpinVariation(lua_State *L);
 int w_ParticleSystem_setColors(lua_State *L);
 int w_ParticleSystem_getColors(lua_State *L);
-int w_ParticleSystem_setQuads(lua_State *L);
-int w_ParticleSystem_getQuads(lua_State *L);
 int w_ParticleSystem_setOffset(lua_State *L);
 int w_ParticleSystem_getOffset(lua_State *L);
 int w_ParticleSystem_count(lua_State *L);

src/modules/graphics/opengl/wrap_SpriteBatch.cpp

 	return 1;
 }
 
-int w_SpriteBatch_addq(lua_State *L)
+int w_SpriteBatch_addg(lua_State *L)
 {
 	SpriteBatch *t = luax_checkspritebatch(L, 1);
-	Quad *q = luax_checktype<Quad>(L, 2, "Quad", GRAPHICS_QUAD_T);
+	Geometry *g = luax_checktype<Geometry>(L, 2, "Geometry", GRAPHICS_GEOMETRY_T);
+
 	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.0f);
 	float oy = (float)luaL_optnumber(L, 9, 0);
 	float kx = (float)luaL_optnumber(L, 10, 0);
 	float ky = (float)luaL_optnumber(L, 11, 0);
-	lua_pushnumber(L, t->addq(q, x, y, angle, sx, sy, ox, oy, kx, ky));
+	lua_pushnumber(L, t->addg(g, x, y, angle, sx, sy, ox, oy, kx, ky));
 	return 1;
 }
 
 {
 	SpriteBatch *t = luax_checkspritebatch(L, 1);
 	int index = luaL_checkinteger(L, 2);
-	Quad *q = luax_checktype<Quad>(L, 3, "Quad", GRAPHICS_QUAD_T);
+	Geometry *g = luax_checktype<Geometry>(L, 3, "Geometry", GRAPHICS_GEOMETRY_T);
+
 	float x = (float)luaL_optnumber(L, 4, 0.0f);
 	float y = (float)luaL_optnumber(L, 5, 0.0f);
 	float angle = (float)luaL_optnumber(L, 6, 0.0f);
 	float oy = (float)luaL_optnumber(L, 10, 0);
 	float kx = (float)luaL_optnumber(L, 11, 0);
 	float ky = (float)luaL_optnumber(L, 12, 0);
-	t->addq(q, x, y, angle, sx, sy, ox, oy, kx, ky, index);
+	t->addg(g, x, y, angle, sx, sy, ox, oy, kx, ky, index);
 	return 0;
 }
 
 static const luaL_Reg functions[] =
 {
 	{ "add", w_SpriteBatch_add },
-	{ "addq", w_SpriteBatch_addq },
+	{ "addg", w_SpriteBatch_addg },
 	{ "set", w_SpriteBatch_set },
 	{ "setq", w_SpriteBatch_setq },
 	{ "clear", w_SpriteBatch_clear },

src/modules/math/MathModule.cpp

 
 namespace
 {
-
 	// check if an angle is oriented counter clockwise
 	inline bool is_oriented_ccw(const vertex &a, const vertex &b, const vertex &c)
 	{