Browse Source

Merged bartbes/love-experiments/Mesh into default

Alex Szpakowski 12 years ago
parent
commit
83a9e5912f

+ 36 - 24
platform/macosx/love-framework.xcodeproj/project.pbxproj

@@ -259,6 +259,8 @@
 		FA636D8E171B72A70065623F /* wrap_RandomGenerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA636D8C171B72A70065623F /* wrap_RandomGenerator.cpp */; };
 		FA636D8F171B72A70065623F /* wrap_RandomGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = FA636D8D171B72A70065623F /* wrap_RandomGenerator.h */; };
 		FA7175AA178E8418001FE7FE /* lua.h in Headers */ = {isa = PBXBuildFile; fileRef = FA7175A9178E8418001FE7FE /* lua.h */; };
+		FA7AA59217F6AC1F00704BE2 /* wrap_Mesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA7AA59017F6AC1F00704BE2 /* wrap_Mesh.cpp */; };
+		FA7AA59317F6AC1F00704BE2 /* wrap_Mesh.h in Headers */ = {isa = PBXBuildFile; fileRef = FA7AA59117F6AC1F00704BE2 /* wrap_Mesh.h */; };
 		FA7C937A16DCC6C2006F2BEE /* wrap_Math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA7C937516DCC6C2006F2BEE /* wrap_Math.cpp */; };
 		FA7C937B16DCC6C2006F2BEE /* wrap_Math.h in Headers */ = {isa = PBXBuildFile; fileRef = FA7C937616DCC6C2006F2BEE /* wrap_Math.h */; };
 		FA9B4A0816E1578300074F42 /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA9B4A0716E1578300074F42 /* SDL2.framework */; };
@@ -277,12 +279,11 @@
 		FAC5710117402D1100D147E4 /* BezierCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC570FD17402D1100D147E4 /* BezierCurve.h */; };
 		FAC5710217402D1100D147E4 /* wrap_BezierCurve.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC570FE17402D1100D147E4 /* wrap_BezierCurve.cpp */; };
 		FAC5710317402D1100D147E4 /* wrap_BezierCurve.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC570FF17402D1100D147E4 /* wrap_BezierCurve.h */; };
-		FAC86E631724552C00EED715 /* wrap_Geometry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC86E611724552C00EED715 /* wrap_Geometry.cpp */; };
-		FAC86E641724552C00EED715 /* wrap_Geometry.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC86E621724552C00EED715 /* wrap_Geometry.h */; };
-		FAC86E691724555D00EED715 /* DrawGable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC86E651724555D00EED715 /* DrawGable.cpp */; };
-		FAC86E6A1724555D00EED715 /* DrawGable.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC86E661724555D00EED715 /* DrawGable.h */; };
-		FAC86E6B1724555D00EED715 /* Geometry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC86E671724555D00EED715 /* Geometry.cpp */; };
-		FAC86E6C1724555D00EED715 /* Geometry.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC86E681724555D00EED715 /* Geometry.h */; };
+		FAC86E631724552C00EED715 /* wrap_Quad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC86E611724552C00EED715 /* wrap_Quad.cpp */; };
+		FAC86E641724552C00EED715 /* wrap_Quad.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC86E621724552C00EED715 /* wrap_Quad.h */; };
+		FAC86E6A1724555D00EED715 /* DrawQable.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC86E661724555D00EED715 /* DrawQable.h */; };
+		FAC86E6B1724555D00EED715 /* Quad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC86E671724555D00EED715 /* Quad.cpp */; };
+		FAC86E6C1724555D00EED715 /* Quad.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC86E681724555D00EED715 /* Quad.h */; };
 		FAE010DB170DDE99006F29D0 /* ddsinfo.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE010D8170DDE99006F29D0 /* ddsinfo.h */; };
 		FAE010DC170DDE99006F29D0 /* ddsparse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE010D9170DDE99006F29D0 /* ddsparse.cpp */; };
 		FAE010DD170DDE99006F29D0 /* ddsparse.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE010DA170DDE99006F29D0 /* ddsparse.h */; };
@@ -310,6 +311,8 @@
 		FAF272B616E3D46400CC193A /* Thread.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF272B216E3D46400CC193A /* Thread.h */; };
 		FAF272B716E3D46400CC193A /* threads.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF272B316E3D46400CC193A /* threads.cpp */; };
 		FAF272B816E3D46400CC193A /* threads.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF272B416E3D46400CC193A /* threads.h */; };
+		FAF4376F17F4AC530074F9E2 /* Mesh.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF4376D17F4AC530074F9E2 /* Mesh.cpp */; };
+		FAF4377017F4AC530074F9E2 /* Mesh.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF4376E17F4AC530074F9E2 /* Mesh.h */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
@@ -798,6 +801,8 @@
 		FA636D8C171B72A70065623F /* wrap_RandomGenerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_RandomGenerator.cpp; sourceTree = "<group>"; };
 		FA636D8D171B72A70065623F /* wrap_RandomGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_RandomGenerator.h; sourceTree = "<group>"; };
 		FA7175A9178E8418001FE7FE /* lua.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lua.h; sourceTree = "<group>"; };
+		FA7AA59017F6AC1F00704BE2 /* wrap_Mesh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Mesh.cpp; sourceTree = "<group>"; };
+		FA7AA59117F6AC1F00704BE2 /* wrap_Mesh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Mesh.h; sourceTree = "<group>"; };
 		FA7C937516DCC6C2006F2BEE /* wrap_Math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Math.cpp; sourceTree = "<group>"; };
 		FA7C937616DCC6C2006F2BEE /* wrap_Math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Math.h; sourceTree = "<group>"; };
 		FA9B4A0716E1578300074F42 /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = /Library/Frameworks/SDL2.framework; sourceTree = "<absolute>"; };
@@ -816,12 +821,11 @@
 		FAC570FD17402D1100D147E4 /* BezierCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BezierCurve.h; sourceTree = "<group>"; };
 		FAC570FE17402D1100D147E4 /* wrap_BezierCurve.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_BezierCurve.cpp; sourceTree = "<group>"; };
 		FAC570FF17402D1100D147E4 /* wrap_BezierCurve.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_BezierCurve.h; sourceTree = "<group>"; };
-		FAC86E611724552C00EED715 /* wrap_Geometry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Geometry.cpp; sourceTree = "<group>"; };
-		FAC86E621724552C00EED715 /* wrap_Geometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Geometry.h; sourceTree = "<group>"; };
-		FAC86E651724555D00EED715 /* DrawGable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DrawGable.cpp; sourceTree = "<group>"; };
-		FAC86E661724555D00EED715 /* DrawGable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DrawGable.h; sourceTree = "<group>"; };
-		FAC86E671724555D00EED715 /* Geometry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Geometry.cpp; sourceTree = "<group>"; };
-		FAC86E681724555D00EED715 /* Geometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Geometry.h; sourceTree = "<group>"; };
+		FAC86E611724552C00EED715 /* wrap_Quad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Quad.cpp; sourceTree = "<group>"; };
+		FAC86E621724552C00EED715 /* wrap_Quad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Quad.h; sourceTree = "<group>"; };
+		FAC86E661724555D00EED715 /* DrawQable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DrawQable.h; sourceTree = "<group>"; };
+		FAC86E671724555D00EED715 /* Quad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Quad.cpp; sourceTree = "<group>"; };
+		FAC86E681724555D00EED715 /* Quad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Quad.h; sourceTree = "<group>"; };
 		FAE010D8170DDE99006F29D0 /* ddsinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ddsinfo.h; sourceTree = "<group>"; };
 		FAE010D9170DDE99006F29D0 /* ddsparse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ddsparse.cpp; sourceTree = "<group>"; };
 		FAE010DA170DDE99006F29D0 /* ddsparse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ddsparse.h; sourceTree = "<group>"; };
@@ -849,6 +853,8 @@
 		FAF272B216E3D46400CC193A /* Thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Thread.h; sourceTree = "<group>"; };
 		FAF272B316E3D46400CC193A /* threads.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = threads.cpp; sourceTree = "<group>"; };
 		FAF272B416E3D46400CC193A /* threads.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = threads.h; sourceTree = "<group>"; };
+		FAF4376D17F4AC530074F9E2 /* Mesh.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Mesh.cpp; sourceTree = "<group>"; };
+		FAF4376E17F4AC530074F9E2 /* Mesh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Mesh.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -1437,15 +1443,14 @@
 				4941079838020ECA049B5C21 /* Color.h */,
 				58BA2BB460AF3C591B22690E /* Drawable.cpp */,
 				5D93601669875EE06721689E /* Drawable.h */,
-				FAC86E651724555D00EED715 /* DrawGable.cpp */,
-				FAC86E661724555D00EED715 /* DrawGable.h */,
-				FAC86E671724555D00EED715 /* Geometry.cpp */,
-				FAC86E681724555D00EED715 /* Geometry.h */,
+				FAC86E661724555D00EED715 /* DrawQable.h */,
 				03F17FF546D637744E263961 /* Graphics.cpp */,
 				777352284E262F48543E6E7F /* Graphics.h */,
 				58CC50E70A375FDF53EF01B6 /* Image.cpp */,
 				1DA41DFF0869489411A71AFC /* Image.h */,
 				75093EE94918576801F50993 /* opengl */,
+				FAC86E671724555D00EED715 /* Quad.cpp */,
+				FAC86E681724555D00EED715 /* Quad.h */,
 				4B731754147B27AF73AC5358 /* Volatile.cpp */,
 				0CFF64090F0F4F481BB80CF0 /* Volatile.h */,
 			);
@@ -1629,6 +1634,8 @@
 				389E3CEC356050A27784290E /* Graphics.h */,
 				56D6030A0B8F7397715062B9 /* Image.cpp */,
 				3CFE5C4A12D5675E7C9C7BF9 /* Image.h */,
+				FAF4376D17F4AC530074F9E2 /* Mesh.cpp */,
+				FAF4376E17F4AC530074F9E2 /* Mesh.h */,
 				2E406F8328543EC63EB922C6 /* OpenGL.cpp */,
 				2C87695707B046B536F347D8 /* OpenGL.h */,
 				48A206C9004150640C432100 /* ParticleSystem.cpp */,
@@ -1645,12 +1652,14 @@
 				3AFB3A18384A2D22352262B1 /* wrap_Canvas.h */,
 				7A3B52AF1FBE73FC36AD50C8 /* wrap_Font.cpp */,
 				3CDA3E9B364F17A902384AAC /* wrap_Font.h */,
-				FAC86E611724552C00EED715 /* wrap_Geometry.cpp */,
-				FAC86E621724552C00EED715 /* wrap_Geometry.h */,
+				FAC86E611724552C00EED715 /* wrap_Quad.cpp */,
+				FAC86E621724552C00EED715 /* wrap_Quad.h */,
 				1A9810F758AC1D1E4B6431FD /* wrap_Graphics.cpp */,
 				05DF237B657042515F3B4E52 /* wrap_Graphics.h */,
 				14AE68E14C2C74526A612FA0 /* wrap_Image.cpp */,
 				78A2127828793F7A778D7932 /* wrap_Image.h */,
+				FA7AA59017F6AC1F00704BE2 /* wrap_Mesh.cpp */,
+				FA7AA59117F6AC1F00704BE2 /* wrap_Mesh.h */,
 				5F42052D7C8271A1105541DE /* wrap_ParticleSystem.cpp */,
 				678E42771C9B415628A3234D /* wrap_ParticleSystem.h */,
 				FA577A8716C71CF000860150 /* wrap_Shader.cpp */,
@@ -1896,6 +1905,7 @@
 				FA7C937B16DCC6C2006F2BEE /* wrap_Math.h in Headers */,
 				FAF272A516E3D44400CC193A /* Channel.h in Headers */,
 				FAF272A716E3D44400CC193A /* LuaThread.h in Headers */,
+				FAF4377017F4AC530074F9E2 /* Mesh.h in Headers */,
 				FAF272A916E3D44400CC193A /* ThreadModule.h in Headers */,
 				FAF272AB16E3D44400CC193A /* wrap_Channel.h in Headers */,
 				FAF272AD16E3D44400CC193A /* wrap_LuaThread.h in Headers */,
@@ -1909,13 +1919,14 @@
 				FAE010E1170DE25E006F29D0 /* ddsHandler.h in Headers */,
 				FAE010E5170DF75C006F29D0 /* wrap_CompressedData.h in Headers */,
 				FA0CDE3D1710F9A50056E8D7 /* FormatHandler.h in Headers */,
+				FA7AA59317F6AC1F00704BE2 /* wrap_Mesh.h in Headers */,
 				FAEC808B1710FEA60057279A /* ImageData.h in Headers */,
 				FAEC808F1711E76C0057279A /* CompressedData.h in Headers */,
 				FA636D8B171B70920065623F /* RandomGenerator.h in Headers */,
 				FA636D8F171B72A70065623F /* wrap_RandomGenerator.h in Headers */,
-				FAC86E641724552C00EED715 /* wrap_Geometry.h in Headers */,
-				FAC86E6A1724555D00EED715 /* DrawGable.h in Headers */,
-				FAC86E6C1724555D00EED715 /* Geometry.h in Headers */,
+				FAC86E641724552C00EED715 /* wrap_Quad.h in Headers */,
+				FAC86E6A1724555D00EED715 /* DrawQable.h in Headers */,
+				FAC86E6C1724555D00EED715 /* Quad.h in Headers */,
 				FA03546D1731F3A700284828 /* simplexnoise1234.h in Headers */,
 				FA3D9E0E16E68DE600CA6630 /* Cursor.h in Headers */,
 				FA3D9E1216E68EAE00CA6630 /* Cursor.h in Headers */,
@@ -2112,6 +2123,7 @@
 				FA08F61C16C7541400F007B5 /* Font.cpp in Sources */,
 				FA08F61D16C7541400F007B5 /* GLee.c in Sources */,
 				FA08F61E16C7541400F007B5 /* Graphics.cpp in Sources */,
+				FAF4376F17F4AC530074F9E2 /* Mesh.cpp in Sources */,
 				FA08F61F16C7541400F007B5 /* Image.cpp in Sources */,
 				FA08F62016C7541400F007B5 /* OpenGL.cpp in Sources */,
 				FA08F62116C7541400F007B5 /* ParticleSystem.cpp in Sources */,
@@ -2131,6 +2143,7 @@
 				FA08F63116C7542600F007B5 /* wrap_Image.cpp in Sources */,
 				FA08F63216C7542600F007B5 /* wrap_ImageData.cpp in Sources */,
 				FA08F63416C7542D00F007B5 /* JoystickModule.cpp in Sources */,
+				FA7AA59217F6AC1F00704BE2 /* wrap_Mesh.cpp in Sources */,
 				FA08F63516C7542D00F007B5 /* wrap_JoystickModule.cpp in Sources */,
 				FA08F63616C7543400F007B5 /* Keyboard.cpp in Sources */,
 				FA08F63716C7543400F007B5 /* Keyboard.cpp in Sources */,
@@ -2219,9 +2232,8 @@
 				FAEC808E1711E76C0057279A /* CompressedData.cpp in Sources */,
 				FA636D8A171B70920065623F /* RandomGenerator.cpp in Sources */,
 				FA636D8E171B72A70065623F /* wrap_RandomGenerator.cpp in Sources */,
-				FAC86E631724552C00EED715 /* wrap_Geometry.cpp in Sources */,
-				FAC86E691724555D00EED715 /* DrawGable.cpp in Sources */,
-				FAC86E6B1724555D00EED715 /* Geometry.cpp in Sources */,
+				FAC86E631724552C00EED715 /* wrap_Quad.cpp in Sources */,
+				FAC86E6B1724555D00EED715 /* Quad.cpp in Sources */,
 				FA03546C1731F3A700284828 /* simplexnoise1234.cpp in Sources */,
 				FA3D9E0D16E68DE600CA6630 /* Cursor.cpp in Sources */,
 				FA3D9E1116E68EAE00CA6630 /* Cursor.cpp in Sources */,

+ 2 - 2
src/common/runtime.cpp

@@ -670,14 +670,14 @@ StringMap<Type, TYPE_MAX_ENUM>::Entry typeEntries[] =
 
 	// Graphics
 	{"Drawable", GRAPHICS_DRAWABLE_ID},
-	{"DrawGable", GRAPHICS_DRAWGABLE_ID},
 	{"Image", GRAPHICS_IMAGE_ID},
-	{"Geometry", GRAPHICS_GEOMETRY_ID},
+	{"Quad", GRAPHICS_QUAD_ID},
 	{"Font", GRAPHICS_FONT_ID},
 	{"ParticleSystem", GRAPHICS_PARTICLE_SYSTEM_ID},
 	{"SpriteBatch", GRAPHICS_SPRITE_BATCH_ID},
 	{"Canvas", GRAPHICS_CANVAS_ID},
 	{"Shader", GRAPHICS_SHADER_ID},
+	{"Mesh", GRAPHICS_MESH_ID},
 
 	// Image
 	{"ImageData", IMAGE_IMAGE_DATA_ID},

+ 8 - 6
src/common/types.h

@@ -45,14 +45,15 @@ enum Type
 
 	// Graphics
 	GRAPHICS_DRAWABLE_ID,
-	GRAPHICS_DRAWGABLE_ID,
+	GRAPHICS_DRAWQABLE_ID,
 	GRAPHICS_IMAGE_ID,
-	GRAPHICS_GEOMETRY_ID,
+	GRAPHICS_QUAD_ID,
 	GRAPHICS_FONT_ID,
 	GRAPHICS_PARTICLE_SYSTEM_ID,
 	GRAPHICS_SPRITE_BATCH_ID,
 	GRAPHICS_CANVAS_ID,
 	GRAPHICS_SHADER_ID,
+	GRAPHICS_MESH_ID,
 
 	// Image
 	IMAGE_IMAGE_DATA_ID,
@@ -128,14 +129,15 @@ const bits FONT_RASTERIZER_T = (bits(1) << FONT_RASTERIZER_ID) | OBJECT_T;
 
 // Graphics.
 const bits GRAPHICS_DRAWABLE_T = (bits(1) << GRAPHICS_DRAWABLE_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_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_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_DRAWGABLE_T;
+const bits GRAPHICS_CANVAS_T = (bits(1) << GRAPHICS_CANVAS_ID) | GRAPHICS_DRAWQABLE_T;
 const bits GRAPHICS_SHADER_T = (bits(1) << GRAPHICS_SHADER_ID) | OBJECT_T;
+const bits GRAPHICS_MESH_T = (bits(1) << GRAPHICS_MESH_ID) | GRAPHICS_DRAWABLE_T;
 
 // Image.
 const bits IMAGE_IMAGE_DATA_T = (bits(1) << IMAGE_IMAGE_DATA_ID) | DATA_T;

+ 9 - 9
src/modules/graphics/DrawGable.h → src/modules/graphics/DrawQable.h

@@ -18,12 +18,12 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
-#ifndef LOVE_GRAPHICS_DRAWGABLE_H
-#define LOVE_GRAPHICS_DRAWGABLE_H
+#ifndef LOVE_GRAPHICS_DRAWQABLE_H
+#define LOVE_GRAPHICS_DRAWQABLE_H
 
 // LOVE
 #include "Drawable.h"
-#include "Geometry.h"
+#include "Quad.h"
 
 namespace love
 {
@@ -31,21 +31,21 @@ namespace graphics
 {
 
 /**
- * A DrawGable is anything that be drawn in part with a Geometry object.
+ * A DrawQable is anything that be drawn in part with a Quad object.
  **/
-class DrawGable : public Drawable
+class DrawQable : public Drawable
 {
 public:
 
 	/**
 	 * Destructor.
 	 **/
-	virtual ~DrawGable();
+	virtual ~DrawQable() {}
 
 	/**
 	 * Draws the object with the specified transformation.
 	 *
-	 * @param geom The Geometry object to use to draw the object.
+	 * @param quad The Quad 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).
@@ -56,10 +56,10 @@ public:
 	 * @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;
+	virtual void drawq(Quad *quad, 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
+#endif // LOVE_GRAPHICS_DRAWQABLE_H

+ 0 - 197
src/modules/graphics/Geometry.cpp

@@ -1,197 +0,0 @@
-/**
- * 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 "Geometry.h"
-#include "common/Exception.h"
-#include "common/Vector.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> &polygon, const std::vector<uint16> &elements, Geometry::DrawMode mode)
-	: vertexArray(NULL)
-	, vertexCount(polygon.size())
-	, elementArray(NULL)
-	, elementCount(elements.size())
-	, vertexColors(false)
-	, drawMode(mode)
-{
-	if (polygon.size() < 3)
-		throw love::Exception("At least 3 vertices are needed to create a Geometry.");
-
-	for (size_t i = 0; i < elementCount; i++)
-	{
-		// All values in the element array need to be a valid vertex index.
-		if (elements[i] >= vertexCount)
-			throw love::Exception("Invalid vertex map value");
-	}
-
-	vertexArray = new Vertex[vertexCount];
-	memcpy(vertexArray, &polygon[0], vertexCount * sizeof(Vertex));
-
-	if (elementCount > 0)
-	{
-		elementArray = new uint16[elementCount];
-		memcpy(elementArray, &elements[0], elementCount * sizeof(uint16));
-	}
-}
-
-Geometry::Geometry(float x, float y, float w, float h, float sw, float sh)
-	: vertexArray(NULL)
-	, vertexCount(4)
-	, elementArray(NULL)
-	, elementCount(0)
-	, vertexColors(false)
-	, drawMode(DRAW_MODE_FAN)
-{
-	float s0 = x/sw, s1 = (x+w)/sw, t0 = y/sh, t1 = (y+h)/sh;
-
-	Vertex verts[4] = {
-		{0,0, s0,t0, 255, 255, 255, 255},
-		{w,0, s1,t0, 255, 255, 255, 255},
-		{w,h, s1,t1, 255, 255, 255, 255},
-		{0,h, s0,t1, 255, 255, 255, 255}
-	};
-
-	vertexArray = new Vertex[4];
-
-	for (int i = 0; i < 4; i++)
-		vertexArray[i] = verts[i];
-}
-
-Geometry::Geometry(const Geometry &other)
-	: vertexCount(other.vertexCount)
-	, elementCount(other.elementCount)
-	, vertexColors(other.vertexColors)
-	, drawMode(other.drawMode)
-{
-	vertexArray = new Vertex[vertexCount];
-	memcpy(vertexArray, other.vertexArray, vertexCount * sizeof(Vertex));
-
-	if (elementCount > 0)
-	{
-		elementArray = new uint16[elementCount];
-		memcpy(elementArray, other.elementArray, elementCount * sizeof(uint16));
-	}
-}
-
-Geometry &Geometry::operator=(const Geometry &other)
-{
-	if (this != &other)
-	{
-		Geometry temp(other);
-		std::swap(vertexArray, temp.vertexArray);
-		std::swap(elementArray, temp.elementArray);
-
-		vertexCount  = temp.vertexCount;
-		elementCount = temp.elementCount;
-
-		vertexColors = other.vertexColors;
-		drawMode     = other.drawMode;
-	}
-
-	return *this;
-}
-
-Geometry::~Geometry()
-{
-	delete[] vertexArray;
-	delete[] elementArray;
-}
-
-const Vertex &Geometry::getVertex(size_t i) const
-{
-	if (i >= vertexCount)
-		throw Exception("Invalid vertex index");
-
-	return vertexArray[i];
-}
-
-void Geometry::setVertex(size_t i, const Vertex &v)
-{
-	if (i >= vertexCount)
-		throw Exception("Invalid vertex index");
-
-	vertexArray[i] = v;
-}
-
-
-void Geometry::setElementArray(const uint16 *elements, size_t count)
-{
-	if (count == 0 || elements == NULL)
-	{
-		delete[] elementArray;
-		elementArray = NULL;
-		elementCount = 0;
-		return;
-	}
-
-	for (size_t i = 0; i < count; i++)
-	{
-		if (elements[i] >= vertexCount)
-			throw love::Exception("Invalid vertex map value");
-	}
-
-	if (count > elementCount)
-	{
-		delete[] elementArray;
-		elementArray = new uint16[count];
-	}
-
-	elementCount = count;
-	memcpy(elementArray, elements, elementCount * sizeof(uint16));
-}
-
-void Geometry::setVertexColors(bool on)
-{
-	vertexColors = on;
-}
-
-bool Geometry::getConstant(const char *in, Geometry::DrawMode &out)
-{
-	return drawModes.find(in, out);
-}
-
-bool Geometry::getConstant(Geometry::DrawMode in, const char *&out)
-{
-	return drawModes.find(in, out);
-}
-
-StringMap<Geometry::DrawMode, Geometry::DRAW_MODE_MAX_ENUM>::Entry Geometry::drawModeEntries[] =
-{
-	{"fan", Geometry::DRAW_MODE_FAN},
-	{"strip", Geometry::DRAW_MODE_STRIP},
-	{"triangles", Geometry::DRAW_MODE_TRIANGLES}
-};
-
-StringMap<Geometry::DrawMode, Geometry::DRAW_MODE_MAX_ENUM> Geometry::drawModes(Geometry::drawModeEntries, sizeof(Geometry::drawModeEntries));
-
-} // graphics
-} // love

+ 0 - 146
src/modules/graphics/Geometry.h

@@ -1,146 +0,0 @@
-/**
- * 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_GEOMETRY_H
-#define LOVE_GRAPHICS_GEOMETRY_H
-
-// LOVE
-#include "common/Object.h"
-#include "common/math.h"
-#include "common/StringMap.h"
-#include "common/int.h"
-
-// stdlib
-#include <vector>
-
-namespace love
-{
-namespace graphics
-{
-
-class Geometry : public Object
-{
-public:
-
-	// How the Geometry's vertices are used when drawing.
-	// http://escience.anu.edu.au/lecture/cg/surfaceModeling/image/surfaceModeling015.png
-	enum DrawMode
-	{
-		DRAW_MODE_FAN,
-		DRAW_MODE_STRIP,
-		DRAW_MODE_TRIANGLES,
-		DRAW_MODE_MAX_ENUM
-	};
-
-	/**
-	 * Creates a new geometry object from a std::vector<vertex>.
-	 **/
-	Geometry(const std::vector<Vertex> &polygon, const std::vector<uint16> &elements, DrawMode mode = DRAW_MODE_FAN);
-
-	/**
-	 * 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();
-
-	const Vertex &getVertex(size_t i) const;
-	void setVertex(size_t i, const Vertex &v);
-
-	/**
-	 * Returns a pointer to the vertex array.
-	 **/
-	inline const Vertex *getVertexArray() const
-	{
-		return vertexArray;
-	}
-
-	/**
-	 * Returns the size of the vertex array.
-	 **/
-	inline size_t getVertexCount() const
-	{
-		return vertexCount;
-	}
-
-	inline const uint16 *getElementArray() const
-	{
-		return elementArray;
-	}
-
-	inline size_t getElementCount() const
-	{
-		return elementCount;
-	}
-
-	void setElementArray(const uint16 *elements, size_t count);
-
-	/**
-	 * Sets whether this Geometry will use custom per-vertex colors.
-	 **/
-	void setVertexColors(bool on);
-
-	/**
-	 * Returns whether this Geometry is using custom per-vertex colors.
-	 **/
-	inline bool hasVertexColors() const
-	{
-		return vertexColors;
-	};
-
-	/**
-	 * Returns the mode used when drawing this Geometry.
-	 **/
-	inline DrawMode getDrawMode() const
-	{
-		return drawMode;
-	}
-
-	static bool getConstant(const char *in, DrawMode &out);
-	static bool getConstant(DrawMode in, const char *&out);
-
-private:
-
-	Vertex *vertexArray;
-	size_t vertexCount;
-
-	uint16 *elementArray;
-	size_t elementCount;
-
-	bool vertexColors;
-
-	DrawMode drawMode;
-
-	static StringMap<DrawMode, DRAW_MODE_MAX_ENUM>::Entry drawModeEntries[];
-	static StringMap<DrawMode, DRAW_MODE_MAX_ENUM> drawModes;
-};
-
-} // graphics
-} // love
-
-#endif // LOVE_GRAPHICS_GEOMETRY_H

+ 2 - 2
src/modules/graphics/Image.h

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

+ 114 - 0
src/modules/graphics/Quad.cpp

@@ -0,0 +1,114 @@
+/**
+ * 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 "Quad.h"
+
+// C
+#include <cstring> // For memcpy
+
+namespace love
+{
+namespace graphics
+{
+
+Quad::Quad(const Quad::Viewport &v, float sw, float sh)
+	: sw(sw)
+	, sh(sh)
+{
+	memset(vertices, 255, sizeof(Vertex) * NUM_VERTICES);
+	refresh(v, sw, sh);
+}
+
+Quad::~Quad()
+{
+}
+
+void Quad::refresh(const Quad::Viewport &v, float sw, float sh)
+{
+	viewport = v;
+
+	vertices[0].x = 0;
+	vertices[0].y = 0;
+	vertices[1].x = 0;
+	vertices[1].y = v.h;
+	vertices[2].x = v.w;
+	vertices[2].y = v.h;
+	vertices[3].x = v.w;
+	vertices[3].y = 0;
+
+	vertices[0].s = v.x/sw;
+	vertices[0].t = v.y/sh;
+	vertices[1].s = v.x/sw;
+	vertices[1].t = (v.y+v.h)/sh;
+	vertices[2].s = (v.x+v.w)/sw;
+	vertices[2].t = (v.y+v.h)/sh;
+	vertices[3].s = (v.x+v.w)/sw;
+	vertices[3].t = v.y/sh;
+}
+
+void Quad::setViewport(const Quad::Viewport &v)
+{
+	refresh(v, sw, sh);
+}
+
+Quad::Viewport Quad::getViewport() const
+{
+	return viewport;
+}
+
+void Quad::flip(bool x, bool y)
+{
+	Vertex temp[NUM_VERTICES];
+
+	if (x)
+	{
+		memcpy(temp, vertices, sizeof(Vertex) * NUM_VERTICES);
+		vertices[0].s = temp[3].s;
+		vertices[0].t = temp[3].t;
+		vertices[1].s = temp[2].s;
+		vertices[1].t = temp[2].t;
+		vertices[2].s = temp[1].s;
+		vertices[2].t = temp[1].t;
+		vertices[3].s = temp[0].s;
+		vertices[3].t = temp[0].t;
+	}
+
+	if (y)
+	{
+		memcpy(temp, vertices, sizeof(Vertex) * NUM_VERTICES);
+		vertices[0].s = temp[1].s;
+		vertices[0].t = temp[1].t;
+		vertices[1].s = temp[0].s;
+		vertices[1].t = temp[0].t;
+		vertices[2].s = temp[3].s;
+		vertices[2].t = temp[3].t;
+		vertices[3].s = temp[2].s;
+		vertices[3].t = temp[2].t;
+	}
+}
+
+const Vertex *Quad::getVertices() const
+{
+	return vertices;
+}
+
+} // graphics
+} // love

+ 69 - 0
src/modules/graphics/Quad.h

@@ -0,0 +1,69 @@
+/**
+ * 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_QUAD_H
+#define LOVE_GRAPHICS_QUAD_H
+
+// LOVE
+#include "common/Object.h"
+#include "common/math.h"
+
+namespace love
+{
+namespace graphics
+{
+
+class Quad : public Object
+{
+public:
+
+	struct Viewport
+	{
+		float x, y;
+		float w, h;
+	};
+
+	static const size_t NUM_VERTICES = 4;
+
+	Quad(const Viewport &v, float sw, float sh);
+	virtual ~Quad();
+
+	void refresh(const Viewport &v, float sw, float sh);
+	void setViewport(const Viewport &v);
+	Viewport getViewport() const;
+
+	void flip(bool x, bool y);
+
+	const Vertex *getVertices() const;
+
+private:
+
+	Vertex vertices[NUM_VERTICES];
+
+	Viewport viewport;
+	float sw;
+	float sh;
+
+}; // Quad
+
+} // graphics
+} // love
+
+#endif // LOVE_GRAPHICS_QUAD_H

+ 10 - 49
src/modules/graphics/opengl/Canvas.cpp

@@ -607,52 +607,20 @@ void Canvas::draw(float x, float y, float angle, float sx, float sy, float ox, f
 	drawv(t, vertices);
 }
 
-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
+void Canvas::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
 {
 	static Matrix t;
 	t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
 
-	// flip texture coordinates vertically
-	size_t vcount = geom->getVertexCount();
-	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.f - v[i].t;
-	}
-
-	// use colors stored in geometry (horrible, horrible hack)
-	if (geom->hasVertexColors())
-	{
-		glEnableClientState(GL_COLOR_ARRAY);
-		glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (GLvoid *)&v->r);
-	}
-
-	GLenum glmode;
-	switch (geom->getDrawMode())
-	{
-	case Geometry::DRAW_MODE_FAN:
-	default:
-		glmode = GL_TRIANGLE_FAN;
-		break;
-	case Geometry::DRAW_MODE_STRIP:
-		glmode = GL_TRIANGLE_STRIP;
-		break;
-	case Geometry::DRAW_MODE_TRIANGLES:
-		glmode = GL_TRIANGLES;
-		break;
-	}
-
-	drawv(t, v, vcount, glmode, geom->getElementArray(), geom->getElementCount());
+	const Vertex *v = quad->getVertices();
 
-	if (geom->hasVertexColors())
-	{
-		glDisableClientState(GL_COLOR_ARRAY);
-		gl.setColor(gl.getColor());
-	}
+	// flip texture coordinates vertically.
+	Vertex w[4];
+	memcpy(w, v, sizeof(Vertex) * 4);
+	for (size_t i = 0; i < 4; i++)
+		w[i].t = 1.0f - w[i].t;
 
-	delete[] v;
+	drawv(t, w);
 }
 
 bool Canvas::checkCreateStencil()
@@ -785,7 +753,7 @@ int Canvas::getHeight()
 	return height;
 }
 
-void Canvas::drawv(const Matrix &t, const Vertex *v, GLsizei count, GLenum mode, const uint16 *e, GLsizei ecount) const
+void Canvas::drawv(const Matrix &t, const Vertex *v) const
 {
 	glPushMatrix();
 
@@ -796,17 +764,10 @@ void Canvas::drawv(const Matrix &t, const Vertex *v, GLsizei count, GLenum mode,
 	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);
 
-	if (e != 0 && ecount > 0)
-		glDrawElements(mode, ecount, GL_UNSIGNED_SHORT, (GLvoid *) e);
-	else
-		glDrawArrays(mode, 0, count);
+	glDrawArrays(GL_QUADS, 0, 4);
 
 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 	glDisableClientState(GL_VERTEX_ARRAY);

+ 5 - 5
src/modules/graphics/opengl/Canvas.h

@@ -21,7 +21,7 @@
 #ifndef LOVE_GRAPHICS_OPENGL_CANVAS_H
 #define LOVE_GRAPHICS_OPENGL_CANVAS_H
 
-#include "graphics/DrawGable.h"
+#include "graphics/DrawQable.h"
 #include "graphics/Volatile.h"
 #include "graphics/Image.h"
 #include "graphics/Color.h"
@@ -38,7 +38,7 @@ namespace graphics
 namespace opengl
 {
 
-class Canvas : public DrawGable, public Volatile
+class Canvas : public DrawQable, public Volatile
 {
 public:
 
@@ -65,9 +65,9 @@ public:
 	virtual void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
 
 	/**
-	 * @copydoc DrawGable::drawg()
+	 * @copydoc DrawQable::drawq()
 	 **/
-	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;
+	void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
 
 	/**
 	 * Create and attach a stencil buffer to this Canvas' framebuffer, if necessary.
@@ -142,7 +142,7 @@ private:
 	std::vector<Canvas *> attachedCanvases;
 
 	void setupGrab();
-	void drawv(const Matrix &t, const Vertex *v, GLsizei count = 4, GLenum mode = GL_QUADS, const uint16 *e = 0, GLsizei ecount = 0) const;
+	void drawv(const Matrix &t, const Vertex *v) const;
 
 	static StringMap<TextureType, TYPE_MAX_ENUM>::Entry textureTypeEntries[];
 	static StringMap<TextureType, TYPE_MAX_ENUM> textureTypes;

+ 0 - 1
src/modules/graphics/opengl/Font.cpp

@@ -20,7 +20,6 @@
 #include "common/config.h"
 #include "Font.h"
 #include "font/GlyphData.h"
-#include "modules/graphics/Geometry.h"
 #include "Image.h"
 
 #include "libraries/utf8/utf8.h"

+ 7 - 7
src/modules/graphics/opengl/Graphics.cpp

@@ -353,14 +353,9 @@ Image *Graphics::newImage(love::image::CompressedData *cdata)
 	return image;
 }
 
-Geometry *Graphics::newGeometry(const std::vector<Vertex> &vertices, const std::vector<uint16> &vertexmap, Geometry::DrawMode mode)
+Quad *Graphics::newQuad(Quad::Viewport v, float sw, float sh)
 {
-	return new Geometry(vertices, vertexmap, mode);
-}
-
-Geometry *Graphics::newQuad(float x, float y, float w, float h, float sw, float sh)
-{
-	return new Geometry(x, y, w, h, sw, sh);
+	return new Quad(v, sw, sh);
 }
 
 Font *Graphics::newFont(love::font::Rasterizer *r, const Image::Filter &filter)
@@ -441,6 +436,11 @@ Shader *Graphics::newShader(const Shader::ShaderSources &sources)
 	return new Shader(sources);
 }
 
+Mesh *Graphics::newMesh(const std::vector<Vertex> &vertices, Mesh::DrawMode mode)
+{
+	return new Mesh(vertices, mode);
+}
+
 void Graphics::setColor(const Color &c)
 {
 	gl.setColor(c);

+ 5 - 10
src/modules/graphics/opengl/Graphics.h

@@ -40,11 +40,12 @@
 
 #include "Font.h"
 #include "Image.h"
-#include "graphics/Geometry.h"
+#include "graphics/Quad.h"
 #include "SpriteBatch.h"
 #include "ParticleSystem.h"
 #include "Canvas.h"
 #include "Shader.h"
+#include "Mesh.h"
 
 using love::window::WindowFlags;
 
@@ -199,15 +200,7 @@ public:
 	Image *newImage(love::image::ImageData *data);
 	Image *newImage(love::image::CompressedData *cdata);
 
-	/**
-	 * Creates a Geometry object.
-	 **/
-	Geometry *newGeometry(const std::vector<Vertex> &vertices, const std::vector<uint16> &vertexmap, Geometry::DrawMode mode);
-
-	/**
-	 * Creates a quadliteral Geometry object.
-	 **/
-	Geometry *newQuad(float x, float y, float w, float h, float sw, float sh);
+	Quad *newQuad(Quad::Viewport v, float sw, float sh);
 
 	/**
 	 * Creates a Font object.
@@ -222,6 +215,8 @@ public:
 
 	Shader *newShader(const Shader::ShaderSources &sources);
 
+	Mesh *newMesh(const std::vector<Vertex> &vertices, Mesh::DrawMode mode = Mesh::DRAW_MODE_FAN);
+
 	/**
 	 * Sets the foreground color.
 	 * @param c The new foreground color.

+ 28 - 69
src/modules/graphics/opengl/Image.cpp

@@ -42,6 +42,7 @@ Image::Image(love::image::ImageData *data)
 	, width((float)(data->getWidth()))
 	, height((float)(data->getHeight()))
 	, texture(0)
+	, texCoordScale(1.0, 1.0)
 	, mipmapSharpness(defaultMipmapSharpness)
 	, mipmapsCreated(false)
 	, compressed(false)
@@ -108,51 +109,37 @@ void Image::draw(float x, float y, float angle, float sx, float sy, float ox, fl
 	drawv(t, vertices);
 }
 
-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
+void Image::drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
 {
 	static Matrix t;
 	t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
 
-	const Vertex *v = geom->getVertexArray();
-	size_t vertcount = geom->getVertexCount();
-
-	// Padded NPOT images require texture coordinate scaling with Geometry.
-	if (!hasNpot())
-		v = scaleNPOT(v, vertcount);
+	const Vertex *v = quad->getVertices();
+	drawv(t, v);
+}
 
-	// use colors stored in geometry (horrible, horrible hack)
-	if (geom->hasVertexColors())
-	{
-		glEnableClientState(GL_COLOR_ARRAY);
-		glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (GLvoid *) &v[0].r);
-	}
+void Image::predraw() const
+{
+	bind();
 
-	GLenum glmode;
-	switch (geom->getDrawMode())
+	if (texCoordScale.x < 1.0f || texCoordScale.y < 1.0f)
 	{
-	case Geometry::DRAW_MODE_FAN:
-	default:
-		glmode = GL_TRIANGLE_FAN;
-		break;
-	case Geometry::DRAW_MODE_STRIP:
-		glmode = GL_TRIANGLE_STRIP;
-		break;
-	case Geometry::DRAW_MODE_TRIANGLES:
-		glmode = GL_TRIANGLES;
-		break;
+		// NPOT image but no NPOT support, so the texcoords should be scaled.
+		glMatrixMode(GL_TEXTURE);
+		glPushMatrix();
+		glScalef(texCoordScale.x, texCoordScale.y, 0.0f);
+		glMatrixMode(GL_MODELVIEW);
 	}
+}
 
-	drawv(t, v, vertcount, glmode, geom->getElementArray(), geom->getElementCount());
-
-	if (geom->hasVertexColors())
+void Image::postdraw() const
+{
+	if (texCoordScale.x < 1.0f || texCoordScale.y < 1.0f)
 	{
-		glDisableClientState(GL_COLOR_ARRAY);
-		gl.setColor(gl.getColor());
+		glMatrixMode(GL_TEXTURE);
+		glPopMatrix();
+		glMatrixMode(GL_MODELVIEW);
 	}
-
-	// If we made new verts with scaled texcoords then we should clean them up.
-	if (!hasNpot())
-		delete[] v;
 }
 
 void Image::uploadCompressedMipmaps()
@@ -404,10 +391,8 @@ bool Image::loadVolatilePOT()
 		return true;
 	}
 
-	vertices[1].t = t;
-	vertices[2].t = t;
-	vertices[2].s = s;
-	vertices[3].s = s;
+	texCoordScale.x = s;
+	texCoordScale.y = t;
 
 	// We want this lock to potentially cover mipmap creation as well.
 	love::thread::EmptyLock lock;
@@ -596,30 +581,9 @@ void Image::uploadDefaultTexture()
 	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, px);
 }
 
-love::Vector Image::getTexCoordScale() const
+void Image::drawv(const Matrix &t, const Vertex *v) const
 {
-	// FIXME: this should be changed if Image::loadVolatilePOT changes.
-	return love::Vector(vertices[2].s, vertices[2].t);
-}
-
-Vertex *Image::scaleNPOT(const love::Vertex *v, size_t count) const
-{
-	Vertex *newverts = new Vertex[count];
-	love::Vector scale = getTexCoordScale();
-
-	for (size_t i = 0; i < count; i++)
-	{
-		newverts[i] = v[i];
-		newverts[i].s *= scale.x;
-		newverts[i].t *= scale.y;
-	}
-
-	return newverts;
-}
-
-void Image::drawv(const Matrix &t, const Vertex *v, GLsizei count, GLenum mode, const uint16 *e, GLsizei ecount) const
-{
-	bind();
+	predraw();
 
 	glPushMatrix();
 
@@ -628,22 +592,17 @@ void Image::drawv(const Matrix &t, const Vertex *v, GLsizei count, GLenum mode,
 	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);
 
-	if (e != 0 && ecount > 0)
-		glDrawElements(mode, ecount, GL_UNSIGNED_SHORT, (GLvoid *) e);
-	else
-		glDrawArrays(mode, 0, count);
+	glDrawArrays(GL_QUADS, 0, 4);
 
 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 	glDisableClientState(GL_VERTEX_ARRAY);
 
 	glPopMatrix();
+
+	postdraw();
 }
 
 void Image::setDefaultMipmapSharpness(float sharpness)

+ 14 - 10
src/modules/graphics/opengl/Image.h

@@ -84,9 +84,17 @@ public:
 	void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
 
 	/**
-	 * @copydoc DrawGable::drawg()
+	 * @copydoc DrawQable::drawq()
 	 **/
-	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;
+	void drawq(Quad *quad, float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
+
+	/**
+	 * Call before using this Image's texture to draw. Binds the texture,
+	 * globally scales texture coordinates if the Image has NPOT dimensions and
+	 * NPOT isn't supported, etc.
+	 **/
+	void predraw() const;
+	void postdraw() const;
 
 	/**
 	 * Sets the filter mode.
@@ -124,12 +132,6 @@ public:
 	 **/
 	bool refresh();
 
-	/**
-	 * Gets the texture coordinate scale used for drawing auto-padded NPOT
-	 * images correctly.
-	 **/
-	love::Vector getTexCoordScale() const;
-
 	static void setDefaultMipmapSharpness(float sharpness);
 	static float getDefaultMipmapSharpness();
 	static void setDefaultMipmapFilter(FilterMode f);
@@ -145,10 +147,9 @@ public:
 
 private:
 
-	Vertex *scaleNPOT(const Vertex *v, size_t count) const;
 	void uploadDefaultTexture();
 
-	void drawv(const Matrix &t, const Vertex *v, GLsizei count = 4, GLenum mode = GL_QUADS, const uint16 *e = 0, GLsizei ecount = 0) const;
+	void drawv(const Matrix &t, const Vertex *v) const;
 
 	friend class Shader;
 	GLuint getTextureName() const
@@ -173,6 +174,9 @@ private:
 	// The source vertices of the image.
 	Vertex vertices[4];
 
+	// The scale applied to texcoords for NPOT images without NPOT support.
+	love::Vector texCoordScale;
+
 	// Mipmap texture LOD bias (sharpness) value.
 	float mipmapSharpness;
 

+ 317 - 0
src/modules/graphics/opengl/Mesh.cpp

@@ -0,0 +1,317 @@
+/**
+ * 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 "Mesh.h"
+#include "common/Matrix.h"
+#include "common/Exception.h"
+
+namespace love
+{
+namespace graphics
+{
+namespace opengl
+{
+
+Mesh::Mesh(const std::vector<Vertex> &verts, Mesh::DrawMode mode)
+	: vbo(nullptr)
+	, vertex_count(0)
+	, ibo(nullptr)
+	, element_count(0)
+	, draw_mode(mode)
+	, image(nullptr)
+	, colors_enabled(false)
+{
+	setVertices(verts);
+}
+
+Mesh::~Mesh()
+{
+	delete vbo;
+	delete ibo;
+}
+
+void Mesh::setVertices(const std::vector<Vertex> &verts)
+{
+	if (verts.size() < 3)
+		throw love::Exception("At least 3 vertices are required.");
+
+	size_t size = sizeof(Vertex) * verts.size();
+
+	if (vbo && size > vbo->getSize())
+	{
+		delete vbo;
+		vbo = nullptr;
+	}
+
+	if (!vbo)
+	{
+		// Full memory backing because we might access the data at any time.
+		vbo = VertexBuffer::Create(size, GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, VertexBuffer::BACKING_FULL);
+	}
+
+	vertex_count = verts.size();
+
+	VertexBuffer::Bind vbo_bind(*vbo);
+	VertexBuffer::Mapper vbo_mapper(*vbo);
+
+	// Fill the buffer with the vertices.
+	memcpy(vbo_mapper.get(), &verts[0], size);
+}
+
+void Mesh::setVertex(size_t index, const Vertex &v)
+{
+	if (index >= vertex_count)
+		throw love::Exception("Invalid vertex index: %ld", index);
+
+	VertexBuffer::Bind vbo_bind(*vbo);
+
+	// We unmap the vertex buffer in Mesh::draw. This lets us coalesce the
+	// buffer transfer calls into just one.
+	Vertex *vertices = (Vertex *) vbo->map();
+	vertices[index] = v;
+}
+
+Vertex Mesh::getVertex(size_t index) const
+{
+	if (index >= vertex_count)
+		throw love::Exception("Invalid vertex index: %ld", index);
+
+	VertexBuffer::Bind vbo_bind(*vbo);
+
+	// We unmap the vertex buffer in Mesh::draw.
+	Vertex *vertices = (Vertex *) vbo->map();
+	return vertices[index];
+}
+
+size_t Mesh::getVertexCount() const
+{
+	return vertex_count;
+}
+
+void Mesh::setVertexMap(const std::vector<uint32> &map)
+{
+	for (size_t i = 0; i < map.size(); i++)
+	{
+		if (map[i] >= vertex_count)
+			throw love::Exception("Invalid vertex map value: %d", map[i]);
+	}
+
+	size_t size = sizeof(uint32) * map.size();
+
+	if (ibo && size > ibo->getSize())
+	{
+		delete ibo;
+		ibo = nullptr;
+	}
+
+	if (!ibo)
+	{
+		// Full memory backing because we might access the data at any time.
+		ibo = VertexBuffer::Create(size, GL_ELEMENT_ARRAY_BUFFER, GL_DYNAMIC_DRAW, VertexBuffer::BACKING_FULL);
+	}
+
+	element_count = map.size();
+
+	if (element_count > 0)
+	{
+		VertexBuffer::Bind ibo_bind(*ibo);
+		VertexBuffer::Mapper ibo_map(*ibo);
+
+		// Fill the buffer.
+		memcpy(ibo_map.get(), &map[0], size);
+	}
+}
+
+const uint32 *Mesh::getVertexMap() const
+{
+	if (ibo && element_count > 0)
+	{
+		VertexBuffer::Bind ibo_bind(*ibo);
+
+		// We unmap the buffer in Mesh::draw and Mesh::setVertexMap.
+		return (uint32 *) ibo->map();
+	}
+
+	return 0;
+}
+
+size_t Mesh::getVertexMapCount() const
+{
+	return element_count;
+}
+
+void Mesh::setImage(Image *img)
+{
+	img->retain();
+
+	if (image)
+		image->release();
+
+	image = img;
+}
+
+void Mesh::setImage()
+{
+	if (image)
+		image->release();
+
+	image = nullptr;
+}
+
+Image *Mesh::getImage() const
+{
+	return image;
+}
+
+void Mesh::setDrawMode(Mesh::DrawMode mode)
+{
+	draw_mode = mode;
+}
+
+Mesh::DrawMode Mesh::getDrawMode() const
+{
+	return draw_mode;
+}
+
+void Mesh::setVertexColors(bool enable)
+{
+	colors_enabled = enable;
+}
+
+bool Mesh::hasVertexColors() const
+{
+	return colors_enabled;
+}
+
+void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const
+{
+	const size_t pos_offset   = offsetof(Vertex, x);
+	const size_t tex_offset   = offsetof(Vertex, s);
+	const size_t color_offset = offsetof(Vertex, r);
+
+	if (vertex_count == 0)
+		return;
+
+	if (image)
+		image->predraw();
+	else
+		gl.bindTexture(0);
+
+	Matrix m;
+	m.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
+
+	glPushMatrix();
+	glMultMatrixf(m.getElements());
+
+	VertexBuffer::Bind vbo_bind(*vbo);
+
+	// 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);
+
+	glVertexPointer(2, GL_FLOAT, sizeof(Vertex), vbo->getPointer(pos_offset));
+	glTexCoordPointer(2, GL_FLOAT, 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));
+	}
+
+	GLenum mode = getGLDrawMode(draw_mode);
+
+	if (element_count > 0)
+	{
+		VertexBuffer::Bind ibo_bind(*ibo);
+
+		// Make sure the index buffer isn't mapped (sends data to GPU if needed.)
+		ibo->unmap();
+
+		// Use the custom vertex map to draw the vertices.
+		glDrawElements(mode, element_count, GL_UNSIGNED_INT, ibo->getPointer(0));
+	}
+	else
+	{
+		// Normal non-indexed drawing (no custom vertex map.)
+		glDrawArrays(mode, 0, vertex_count);
+	}
+
+	glDisableClientState(GL_VERTEX_ARRAY);
+	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+	if (hasVertexColors())
+	{
+		glDisableClientState(GL_COLOR_ARRAY);
+		// Using the color array leaves the GL constant color undefined.
+		gl.setColor(gl.getColor());
+	}
+
+	glPopMatrix();
+
+	if (image)
+		image->postdraw();
+}
+
+GLenum Mesh::getGLDrawMode(Mesh::DrawMode mode) const
+{
+	switch (mode)
+	{
+	case DRAW_MODE_FAN:
+		return GL_TRIANGLE_FAN;
+	case DRAW_MODE_STRIP:
+		return GL_TRIANGLE_STRIP;
+	case DRAW_MODE_TRIANGLES:
+		return GL_TRIANGLES;
+	case DRAW_MODE_POINTS:
+		return GL_POINTS;
+	default:
+		break;
+	}
+
+	return GL_TRIANGLES;
+}
+
+bool Mesh::getConstant(const char *in, Mesh::DrawMode &out)
+{
+	return drawModes.find(in, out);
+}
+
+bool Mesh::getConstant(Mesh::DrawMode in, const char *&out)
+{
+	return drawModes.find(in, out);
+}
+
+StringMap<Mesh::DrawMode, Mesh::DRAW_MODE_MAX_ENUM>::Entry Mesh::drawModeEntries[] =
+{
+	{"fan", Mesh::DRAW_MODE_FAN},
+	{"strip", Mesh::DRAW_MODE_STRIP},
+	{"triangles", Mesh::DRAW_MODE_TRIANGLES},
+	{"points", Mesh::DRAW_MODE_POINTS},
+};
+
+StringMap<Mesh::DrawMode, Mesh::DRAW_MODE_MAX_ENUM> Mesh::drawModes(Mesh::drawModeEntries, sizeof(Mesh::drawModeEntries));
+
+} // opengl
+} // graphics
+} // love

+ 170 - 0
src/modules/graphics/opengl/Mesh.h

@@ -0,0 +1,170 @@
+/**
+ * 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_MESH_H
+#define LOVE_GRAPHICS_OPENGL_MESH_H
+
+// LOVE
+#include "common/int.h"
+#include "common/math.h"
+#include "common/StringMap.h"
+#include "graphics/Drawable.h"
+#include "Image.h"
+#include "VertexBuffer.h"
+
+// C++
+#include <vector>
+
+namespace love
+{
+namespace graphics
+{
+namespace opengl
+{
+
+/**
+ * Holds and draws arbitrary vertex geometry.
+ * Each vertex in the Mesh has a position, texture coordinate, and color.
+ **/
+class Mesh : public Drawable
+{
+public:
+
+	// How the Mesh's vertices are used when drawing.
+	// http://escience.anu.edu.au/lecture/cg/surfaceModeling/image/surfaceModeling015.png
+	enum DrawMode
+	{
+		DRAW_MODE_FAN,
+		DRAW_MODE_STRIP,
+		DRAW_MODE_TRIANGLES,
+		DRAW_MODE_POINTS,
+		DRAW_MODE_MAX_ENUM
+	};
+
+	/**
+	 * Constructor.
+	 * @param verts The vertices to use in the Mesh.
+	 * @param mode The draw mode to use when drawing the Mesh.
+	 **/
+	Mesh(const std::vector<Vertex> &verts, DrawMode mode = DRAW_MODE_FAN);
+	virtual ~Mesh();
+
+	/**
+	 * Replaces all the vertices in the Mesh with a new set of vertices.
+	 **/
+	void setVertices(const std::vector<Vertex> &verts);
+
+	/**
+	 * Sets an individual vertex in the Mesh.
+	 * @param index The index into the list of vertices to use.
+	 * @param v The new vertex.
+	 **/
+	void setVertex(size_t index, const Vertex &v);
+	Vertex getVertex(size_t index) const;
+
+	/**
+	 * Gets the total number of vertices in the Mesh.
+	 **/
+	size_t getVertexCount() const;
+
+	/**
+	 * Sets the vertex map to use when drawing the Mesh. The vertex map
+	 * determines the order in which vertices are used by the draw mode.
+	 * A 0-element vector is equivalent to the default vertex map:
+	 * {0, 1, 2, 3, 4, ...}
+	 **/
+	void setVertexMap(const std::vector<uint32> &map);
+
+	/**
+	 * Gets a pointer to the vertex map array. The pointer is only valid until
+	 * the next function call in the graphics module.
+	 * May return null if the vertex map is empty.
+	 **/
+	const uint32 *getVertexMap() const;
+
+	/**
+	 * Gets the total number of elements in the vertex map array.
+	 **/
+	size_t getVertexMapCount() const;
+
+	/**
+	 * Sets the Image used when drawing the Mesh.
+	 **/
+	void setImage(Image *img);
+
+	/**
+	 * Disables any Image from being used when drawing the Mesh.
+	 **/
+	void setImage();
+
+	/**
+	 * Gets the Image used when drawing the Mesh. May return null if no Image is
+	 * set.
+	 **/
+	Image *getImage() const;
+
+	/**
+	 * Sets the draw mode used when drawing the Mesh.
+	 **/
+	void setDrawMode(DrawMode mode);
+	DrawMode getDrawMode() const;
+
+	/**
+	 * Sets whether per-vertex colors are enabled. If this is disabled, the
+	 * global color (love.graphics.setColor) will be used for the entire Mesh.
+	 **/
+	void setVertexColors(bool enable);
+	bool hasVertexColors() const;
+
+	// Implements Drawable.
+	void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const;
+
+	static bool getConstant(const char *in, DrawMode &out);
+	static bool getConstant(DrawMode in, const char *&out);
+
+private:
+
+	GLenum getGLDrawMode(DrawMode mode) const;
+
+	// Vertex buffer.
+	VertexBuffer *vbo;
+	size_t vertex_count;
+
+	// Element (vertex index) buffer, for the vertex map.
+	VertexBuffer *ibo;
+	size_t element_count;
+
+	DrawMode draw_mode;
+
+	Image *image;
+
+	// Whether the per-vertex colors are used when drawing.
+	bool colors_enabled;
+
+	static StringMap<DrawMode, DRAW_MODE_MAX_ENUM>::Entry drawModeEntries[];
+	static StringMap<DrawMode, DRAW_MODE_MAX_ENUM> drawModes;
+
+}; // Mesh
+
+} // opengl
+} // graphics
+} // love
+
+#endif // LOVE_GRAPHICS_OPENGL_MESH_H

+ 3 - 1
src/modules/graphics/opengl/ParticleSystem.cpp

@@ -779,7 +779,7 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo
 		p = p->next;
 	}
 
-	image->bind();
+	image->predraw();
 
 	glEnableClientState(GL_COLOR_ARRAY);
 	glEnableClientState(GL_VERTEX_ARRAY);
@@ -795,6 +795,8 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo
 	glDisableClientState(GL_VERTEX_ARRAY);
 	glDisableClientState(GL_COLOR_ARRAY);
 
+	image->postdraw();
+
 	glPopMatrix();
 
 	gl.setColor(curcolor);

+ 7 - 52
src/modules/graphics/opengl/SpriteBatch.cpp

@@ -26,7 +26,6 @@
 
 // LOVE
 #include "Image.h"
-#include "modules/graphics/Geometry.h"
 #include "VertexBuffer.h"
 
 // C++
@@ -117,9 +116,6 @@ int SpriteBatch::add(float x, float y, float a, float sx, float sy, float ox, fl
 	if (color)
 		setColorv(sprite, *color);
 
-	// Auto-padded NPOT images require texcoord scaling for their vertices.
-	scaleNPOT(sprite, 4);
-
 	addv(sprite, (index == -1) ? next : index);
 
 	// Increment counter.
@@ -129,50 +125,24 @@ int SpriteBatch::add(float x, float y, float a, float sx, float sy, float ox, fl
 	return index;
 }
 
-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*/)
+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*/)
 {
 	// Only do this if there's a free slot.
 	if ((index == -1 && next >= size) || index < -1 || index >= next)
 		return -1;
 
-	size_t vertexcount = geom->getVertexCount();
-	if (vertexcount > 4)
-		throw love::Exception("Cannot add Geometries with more than 4 vertices to SpriteBatch");
-
-	// Which vertices to add to the SpriteBatch.
-	size_t vertex_indices[4] = {0, 1, 2, 3};
-
-	if (geom->getDrawMode() == Geometry::DRAW_MODE_STRIP)
-	{
-		// We have to do some vertex reordering shenanigans to get 4-vertex
-		// triangle strip Geometries to render properly.
-		std::swap(vertex_indices[0], vertex_indices[1]);
-	}
-
-	// If the Geometry has 3 vertices, then 2 triangles will be added to the
-	// SpriteBatch: 0-1-2 and 0-2-0. 0-2-0 will get ignored during rasterization.
-	for (size_t i = geom->getVertexCount(); i < 4; i++)
-		vertex_indices[i] = vertex_indices[0];
-
-	for (size_t i = 0; i < 4; i++)
-		sprite[i] = geom->getVertex(vertex_indices[i]);
+	// Needed for colors.
+	memcpy(sprite, quad->getVertices(), sizeof(Vertex) * 4);
 
 	static Matrix t;
 	t.setTransformation(x, y, a, sx, sy, ox, oy, kx, ky);
 	t.transform(sprite, sprite, 4);
 
-	if (color && !geom->hasVertexColors())
+	if (color)
 		setColorv(sprite, *color);
 
-	// Auto-padded NPOT images require texcoord scaling for their vertices.
-	scaleNPOT(sprite, 4);
-
 	addv(sprite, (index == -1) ? next : index);
 
-	// Make sure SpriteBatch colors are enabled if the Geometry has custom colors.
-	if (!color && geom->hasVertexColors())
-		setColor(Color(255, 255, 255, 255));
-
 	// Increment counter.
 	if (index == -1)
 		return next++;
@@ -309,7 +279,7 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float
 	t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
 	glMultMatrixf((const GLfloat *)t.getElements());
 
-	image->bind();
+	image->predraw();
 
 	VertexBuffer::Bind array_bind(*array_buf);
 	VertexBuffer::Bind element_bind(*element_buf->getVertexBuffer());
@@ -340,24 +310,9 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float
 		gl.setColor(curcolor);
 	}
 
-	glPopMatrix();
-}
-
-void SpriteBatch::scaleNPOT(Vertex *v, size_t count)
-{
-	if (Image::hasNpot())
-		return;
-
-	love::Vector scale = image->getTexCoordScale();
+	image->postdraw();
 
-	if (scale.x == 1.0f && scale.y == 1.0f)
-		return;
-
-	for (size_t i = 0; i < count; i++)
-	{
-		v[i].s *= scale.x;
-		v[i].t *= scale.y;
-	}
+	glPopMatrix();
 }
 
 void SpriteBatch::addv(const Vertex *v, int index)

+ 6 - 8
src/modules/graphics/opengl/SpriteBatch.h

@@ -32,7 +32,7 @@
 #include "graphics/Drawable.h"
 #include "graphics/Volatile.h"
 #include "graphics/Color.h"
-#include "graphics/Geometry.h"
+#include "graphics/Quad.h"
 
 namespace love
 {
@@ -62,7 +62,7 @@ public:
 	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 addg(Geometry *geom, 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);
 	void clear();
 
 	void *lock();
@@ -72,16 +72,16 @@ public:
 	Image *getImage();
 
 	/**
-	 * Set the current color for this SpriteBatch. The geometry added
+	 * Set the current color for this SpriteBatch. The sprites added
 	 * after this call will use this color. Note that global color
 	 * will not longer apply to the SpriteBatch if this is used.
 	 *
-	 * @param color The color to use for the following geometry.
+	 * @param color The color to use for the following sprites.
 	 */
 	void setColor(const Color &color);
 
 	/**
-	 * Disable per-geometry colors for this SpriteBatch. The next call to
+	 * Disable per-sprite colors for this SpriteBatch. The next call to
 	 * draw will use the global color for all sprites.
 	 */
 	void setColor();
@@ -116,8 +116,6 @@ public:
 
 private:
 
-	void scaleNPOT(Vertex *v, size_t count);
-
 	void addv(const Vertex *v, int index);
 
 	/**
@@ -140,7 +138,7 @@ private:
 	Vertex sprite[4];
 
 	// Current color. This color, if present, will be applied to the next
-	// added geometry.
+	// added sprite.
 	Color *color;
 
 	VertexBuffer *array_buf;

+ 32 - 21
src/modules/graphics/opengl/VertexBuffer.cpp

@@ -42,25 +42,27 @@ namespace opengl
 
 // VertexBuffer
 
-VertexBuffer *VertexBuffer::Create(size_t size, GLenum target, GLenum usage)
+VertexBuffer *VertexBuffer::Create(size_t size, GLenum target, GLenum usage, MemoryBacking backing)
 {
 	try
 	{
 		// Try to create a VBO.
-		return new VBO(size, target, usage);
+		return new VBO(size, target, usage, backing);
 	}
 	catch(const love::Exception &)
 	{
 		// VBO not supported ... create regular array.
-		return new VertexArray(size, target, usage);
+		return new VertexArray(size, target, usage, backing);
 	}
 }
 
-VertexBuffer::VertexBuffer(size_t size, GLenum target, GLenum usage)
+VertexBuffer::VertexBuffer(size_t size, GLenum target, GLenum usage, MemoryBacking backing)
 	: is_bound(false)
+	, is_mapped(false)
 	, size(size)
 	, target(target)
 	, usage(usage)
+	, backing(backing)
 {
 }
 
@@ -70,8 +72,8 @@ VertexBuffer::~VertexBuffer()
 
 // VertexArray
 
-VertexArray::VertexArray(size_t size, GLenum target, GLenum usage)
-	: VertexBuffer(size, target, usage)
+VertexArray::VertexArray(size_t size, GLenum target, GLenum usage, MemoryBacking backing)
+	: VertexBuffer(size, target, usage, backing)
 	, buf(new char[size])
 {
 }
@@ -83,11 +85,13 @@ VertexArray::~VertexArray()
 
 void *VertexArray::map()
 {
+	is_mapped = true;
 	return buf;
 }
 
 void VertexArray::unmap()
 {
+	is_mapped = false;
 }
 
 void VertexArray::bind()
@@ -112,20 +116,25 @@ const void *VertexArray::getPointer(size_t offset) const
 
 // VBO
 
-VBO::VBO(size_t size, GLenum target, GLenum usage)
-	: VertexBuffer(size, target, usage)
+VBO::VBO(size_t size, GLenum target, GLenum usage, MemoryBacking backing)
+	: VertexBuffer(size, target, usage, backing)
 	, vbo(0)
 	, memory_map(0)
-	, is_mapped(false)
 	, is_dirty(true)
 {
 	if (!(GLEE_ARB_vertex_buffer_object || GLEE_VERSION_1_5))
 		throw love::Exception("Not supported");
 
+	if (getMemoryBacking() == BACKING_FULL)
+		memory_map = malloc(getSize());
+
 	bool ok = load(false);
 
 	if (!ok)
+	{
+		free(memory_map);
 		throw love::Exception("Could not load VBO.");
+	}
 }
 
 VBO::~VBO()
@@ -150,10 +159,12 @@ void *VBO::map()
 	}
 
 	if (is_dirty)
+	{
 		glGetBufferSubDataARB(getTarget(), 0, getSize(), memory_map);
+		is_dirty = false;
+	}
 
 	is_mapped = true;
-	is_dirty = false;
 
 	return memory_map;
 }
@@ -198,11 +209,10 @@ void VBO::unbind()
 
 void VBO::fill(size_t offset, size_t size, const void *data)
 {
-	if (is_mapped)
-	{
+	if (is_mapped || getMemoryBacking() == BACKING_FULL)
 		memcpy(static_cast<char *>(memory_map) + offset, data, size);
-	}
-	else
+
+	if (!is_mapped)
 	{
 		// Not all systems have access to some faster paths...
 		if (GLEE_APPLE_flush_buffer_range)
@@ -226,7 +236,8 @@ void VBO::fill(size_t offset, size_t size, const void *data)
 			glBufferSubDataARB(getTarget(), offset, size, data);
 		}
 
-		is_dirty = true;
+		if (getMemoryBacking() != BACKING_FULL)
+			is_dirty = true;
 	}
 }
 
@@ -257,23 +268,23 @@ bool VBO::load(bool restore)
 	while (GL_NO_ERROR != glGetError())
 		/* clear error messages */;
 
-	// Note that if 'src' is '0', no data will be copied.
-	glBufferDataARB(getTarget(), getSize(), src, getUsage());
-	GLenum err = glGetError();
-
 	// We don't want to flush the entire buffer when we just modify a small
 	// portion of it (VBO::fill without VBO::map), so we'll handle the flushing
 	// ourselves when we can.
 	if (GLEE_APPLE_flush_buffer_range)
 		glBufferParameteriAPPLE(getTarget(), GL_BUFFER_FLUSHING_UNMAP_APPLE, GL_FALSE);
 
+	// Note that if 'src' is '0', no data will be copied.
+	glBufferDataARB(getTarget(), getSize(), src, getUsage());
+	GLenum err = glGetError();
+
 	return (GL_NO_ERROR == err);
 }
 
 void VBO::unload(bool save)
 {
-	// Save data before unloading.
-	if (save)
+	// Save data before unloading, if we need to.
+	if (save && getMemoryBacking() == BACKING_PARTIAL)
 	{
 		VertexBuffer::Bind bind(*this);
 

+ 39 - 13
src/modules/graphics/opengl/VertexBuffer.h

@@ -48,6 +48,18 @@ class VertexBuffer
 {
 public:
 
+	// Different guarantees for VertexBuffer data storage.
+	enum MemoryBacking
+	{
+		// The VertexBuffer is will have a valid copy of its data in main memory
+		// at all times.
+		BACKING_FULL,
+
+		// The VertexBuffer will have a valid copy of its data in main memory
+		// when it needs to be reloaded and when it's mapped.
+		BACKING_PARTIAL
+	};
+
 	/**
 	 * Create a new VertexBuffer (either a plain vertex array, or a VBO),
 	 * based on what's supported on the system.
@@ -58,9 +70,10 @@ public:
 	 * @param size The size of the VertexBuffer (in bytes).
 	 * @param target GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER.
 	 * @param usage GL_DYNAMIC_DRAW, etc.
+	 * @param backing Determines what guarantees are placed on the data.
 	 * @return A new VertexBuffer.
 	 */
-	static VertexBuffer *Create(size_t size, GLenum target, GLenum usage);
+	static VertexBuffer *Create(size_t size, GLenum target, GLenum usage, MemoryBacking backing = BACKING_PARTIAL);
 
 	/**
 	 * Constructor.
@@ -68,8 +81,9 @@ public:
 	 * @param size The size of the VertexBuffer in bytes.
 	 * @param target The target VertexBuffer object, e.g. GL_ARRAY_BUFFER.
 	 * @param usage Usage hint, e.g. GL_DYNAMIC_DRAW.
+	 * @param backing Determines what guarantees are placed on the data.
 	 */
-	VertexBuffer(size_t size, GLenum target, GLenum usage);
+	VertexBuffer(size_t size, GLenum target, GLenum usage, MemoryBacking backing = BACKING_PARTIAL);
 
 	/**
 	 * Destructor. Does nothing, but must be declared virtual.
@@ -111,6 +125,16 @@ public:
 		return is_bound;
 	}
 
+	bool isMapped() const
+	{
+		return is_mapped;
+	}
+
+	MemoryBacking getMemoryBacking() const
+	{
+		return backing;
+	}
+
 	/**
 	 * Map the VertexBuffer to client memory.
 	 *
@@ -230,6 +254,9 @@ protected:
 	// Whether the buffer is currently bound.
 	bool is_bound;
 
+	// Whether the buffer is currently mapped to main memory.
+	bool is_mapped;
+
 private:
 
 	// The size of the buffer, in bytes.
@@ -240,6 +267,9 @@ private:
 
 	// Usage hint. GL_[DYNAMIC, STATIC, STREAM]_DRAW.
 	GLenum usage;
+
+	//
+	MemoryBacking backing;
 };
 
 /**
@@ -253,9 +283,9 @@ class VertexArray : public VertexBuffer
 public:
 
 	/**
-	 * @copydoc VertexBuffer(int, GLenum, GLenum)
+	 * @copydoc VertexBuffer(int, GLenum, GLenum, Backing)
 	 */
-	VertexArray(size_t size, GLenum target, GLenum usage);
+	VertexArray(size_t size, GLenum target, GLenum usage, MemoryBacking backing);
 
 	/**
 	 * Frees the data we've allocated.
@@ -281,19 +311,19 @@ private:
  * This will be used on all systems that support it. It's in general
  * faster than vertex arrays, but especially in use-cases where there
  * is no need to update the data every frame.
- */
+ **/
 class VBO : public VertexBuffer, public Volatile
 {
 public:
 
 	/**
-	 * @copydoc VertexBuffer(size_t, GLenum, GLenum)
-	 */
-	VBO(size_t size, GLenum target, GLenum usage);
+	 * @copydoc VertexBuffer(size_t, GLenum, GLenum, Backing)
+	 **/
+	VBO(size_t size, GLenum target, GLenum usage, MemoryBacking backing);
 
 	/**
 	 * Deletes the VBOs from OpenGL.
-	 */
+	 **/
 	virtual ~VBO();
 
 	// Implements VertexBuffer.
@@ -332,10 +362,6 @@ private:
 	// call to map().
 	void *memory_map;
 
-	// Set if the vbo currently operates on main instead of gpu
-	// memory.
-	bool is_mapped;
-
 	// Set if the buffer was modified while operating on gpu memory
 	// and needs to be synchronized.
 	bool is_dirty;

+ 87 - 155
src/modules/graphics/opengl/wrap_Graphics.cpp

@@ -20,7 +20,7 @@
 
 #include "wrap_Graphics.h"
 #include "OpenGL.h"
-#include "graphics/DrawGable.h"
+#include "graphics/DrawQable.h"
 #include "image/ImageData.h"
 #include "font/Rasterizer.h"
 
@@ -194,156 +194,19 @@ int w_newImage(lua_State *L)
 	return 1;
 }
 
-int w_newGeometry(lua_State *L)
-{
-	luaL_checktype(L, 1, LUA_TTABLE);
-
-	// Determine whether a table of vertices is being given. We assume it is if
-	// type(args[1][1]) == "table", otherwise assume the args are the verts.
-	lua_rawgeti(L, 1, 1);
-	bool is_table = lua_istable(L, -1);
-	lua_pop(L, 1);
-
-	// Get rid of any trailing nils in the arg list (it messes with our style.)
-	for (int i = lua_gettop(L); i >= 2; i--)
-	{
-		if (lua_isnil(L, i))
-			lua_pop(L, 1);
-		else
-			break;
-	}
-
-	Geometry::DrawMode mode = Geometry::DRAW_MODE_FAN;
-	std::string txt;
-	bool has_vertexmap = false;
-
-	// The last argument (or second-last) may be an optional draw mode.
-	if (lua_type(L, -1) == LUA_TSTRING)
-	{
-		txt = luaL_checkstring(L, -1);
-		lua_remove(L, -1);
-	}
-	else if (lua_type(L, -2) == LUA_TSTRING && lua_istable(L, -1))
-	{
-		txt = luaL_checkstring(L, -2);
-		lua_remove(L, -2);
-
-		// If the draw mode is the second-last argument, the last argument will
-		// be the vertex map.
-		has_vertexmap = true;
-	}
-
-	if (txt.length() > 0 && !Geometry::getConstant(txt.c_str(), mode))
-		return luaL_error(L, "Invalid Geometry draw mode: %s", txt.c_str());
-
-	std::vector<uint16> vertexmap;
-
-	// Get the vertex map table, if it exists.
-	if (has_vertexmap)
-	{
-		// It will always be the last argument.
-		int tableidx = lua_gettop(L);
-
-		size_t elementcount = lua_objlen(L, -1);
-		vertexmap.reserve(elementcount);
-
-		for (size_t i = 0; i < elementcount; i++)
-		{
-			lua_rawgeti(L, tableidx, i + 1);
-			if (!lua_isnumber(L, -1))
-				return luaL_argerror(L, tableidx + 1, "vertex index expected");
-
-			vertexmap.push_back(uint16(lua_tointeger(L, -1) - 1));
-			lua_pop(L, 1);
-		}
-
-		// We don't want to read the vertex map as a vertex table later.
-		lua_remove(L, -1);
-	}
-
-	size_t vertexcount = is_table ? lua_objlen(L, 1) : lua_gettop(L);
-	if (vertexcount < 3)
-		return luaL_error(L, "At least three points are needed to construct a Geometry.");
-
-	if (!lua_checkstack(L, 9))
-		return luaL_error(L, "Too many arguments!");
-
-	bool hasvertexcolors = false;
-
-	std::vector<Vertex> vertices;
-	vertices.reserve(vertexcount);
-
-	for (size_t i = 0; i < vertexcount; ++i)
-	{
-		Vertex v;
-
-		if (is_table)
-		{
-			lua_rawgeti(L, 1, i+1);
-			if (!lua_istable(L, -1))
-				return luax_typerror(L, 1, "table of tables");
-		}
-		else
-		{
-			// Push the vertex table at this arg index to the top of the stack.
-			luaL_checktype(L, i + 1, LUA_TTABLE);
-			lua_pushvalue(L, i + 1);
-		}
-
-		for (int j = 1; j <= 8; j++)
-			lua_rawgeti(L, -j, j);
-
-		v.x = (float) luaL_checknumber(L, -8);
-		v.y = (float) luaL_checknumber(L, -7);
-
-		v.s = (float) luaL_checknumber(L, -6);
-		v.t = (float) luaL_checknumber(L, -5);
-
-		v.r = (unsigned char) luaL_optinteger(L, -4, 255);
-		v.g = (unsigned char) luaL_optinteger(L, -3, 255);
-		v.b = (unsigned char) luaL_optinteger(L, -2, 255);
-		v.a = (unsigned char) luaL_optinteger(L, -1, 255);
-
-		lua_pop(L, 9);
-
-		// Custom vertex colors are disabled by default unless a unique color
-		// is used for at least one vertex.
-		if (v.r != 255 || v.g != 255 || v.b != 255 || v.a != 255)
-			hasvertexcolors = true;
-
-		vertices.push_back(v);
-	}
-
-	Geometry *geom = 0;
-	EXCEPT_GUARD(geom = instance->newGeometry(vertices, vertexmap, mode);)
-
-	if (geom == 0)
-		return luaL_error(L, "Could not create geometry.");
-
-	geom->setVertexColors(hasvertexcolors);
-
-	// Note: This should be changed to luax_pushtype if the new Geometry is ever
-	// expected to be pushed to Lua from another C++ function!
-	// We're only using rawnewtype instead of pushtype for performance.
-	luax_rawnewtype(L, "Geometry", GRAPHICS_GEOMETRY_T, geom);
-	return 1;
-}
-
 int w_newQuad(lua_State *L)
 {
-	float x = (float) luaL_checknumber(L, 1);
-	float y = (float) luaL_checknumber(L, 2);
-	float w = (float) luaL_checknumber(L, 3);
-	float h = (float) luaL_checknumber(L, 4);
+	Quad::Viewport v;
+	v.x = (float) luaL_checknumber(L, 1);
+	v.y = (float) luaL_checknumber(L, 2);
+	v.w = (float) luaL_checknumber(L, 3);
+	v.h = (float) luaL_checknumber(L, 4);
+
 	float sw = (float) luaL_checknumber(L, 5);
 	float sh = (float) luaL_checknumber(L, 6);
 
-	Geometry *quad = instance->newQuad(x, y, w, h, sw, sh);
-
-	// Note: This should be changed to luax_pushtype if the new Geometry is ever
-	// expected to be pushed to Lua from another C++ function!
-	// We're only using rawnewtype instead of pushtype for performance.
-	luax_rawnewtype(L, "Geometry", GRAPHICS_GEOMETRY_T, quad);
+	Quad *quad = instance->newQuad(v, sw, sh);
+	luax_pushtype(L, "Quad", GRAPHICS_QUAD_T, quad);
 	return 1;
 }
 
@@ -568,6 +431,74 @@ int w_newShader(lua_State *L)
 	return 1;
 }
 
+int w_newMesh(lua_State *L)
+{
+	// Check first argument: mandatory table of vertices.
+	luaL_checktype(L, 1, LUA_TTABLE);
+
+	// Second argument: optional image.
+	Image *img = 0;
+	if (!lua_isnoneornil(L, 2))
+		img = luax_checkimage(L, 2);
+
+	// Third argument: optional draw mode.
+	const char *str = 0;
+	Mesh::DrawMode mode = Mesh::DRAW_MODE_FAN;
+	str = lua_isnoneornil(L, 3) ? 0 : luaL_checkstring(L, 3);
+
+	if (str && !Mesh::getConstant(str, mode))
+		return luaL_error(L, "Invalid mesh draw mode: %s", str);
+
+	size_t vertex_count = lua_objlen(L, 1);
+	std::vector<Vertex> vertices;
+	vertices.reserve(vertex_count);
+
+	bool use_colors = false;
+
+	// Get the vertices from the table.
+	for (size_t i = 1; i <= vertex_count; i++)
+	{
+		lua_rawgeti(L, 1, i);
+
+		if (lua_type(L, -1) != LUA_TTABLE)
+			return luax_typerror(L, 1, "table of tables");
+
+		for (int j = 1; j <= 8; j++)
+			lua_rawgeti(L, -j, j);
+
+		Vertex v;
+
+		v.x = (float) luaL_checknumber(L, -8);
+		v.y = (float) luaL_checknumber(L, -7);
+
+		v.s = (float) luaL_checknumber(L, -6);
+		v.t = (float) luaL_checknumber(L, -5);
+
+		v.r = (unsigned char) luaL_optinteger(L, -4, 255);
+		v.g = (unsigned char) luaL_optinteger(L, -3, 255);
+		v.b = (unsigned char) luaL_optinteger(L, -2, 255);
+		v.a = (unsigned char) luaL_optinteger(L, -1, 255);
+
+		// Enable per-vertex coloring if any color is not the default.
+		if (!use_colors && (v.r != 255 || v.g != 255 || v.b != 255 || v.a != 255))
+			use_colors = true;
+
+		lua_pop(L, 9);
+		vertices.push_back(v);
+	}
+
+	Mesh *t = 0;
+	EXCEPT_GUARD(t = instance->newMesh(vertices, mode);)
+
+	if (img)
+		t->setImage(img);
+
+	t->setVertexColors(use_colors);
+
+	luax_pushtype(L, "Mesh", GRAPHICS_MESH_T, t);
+	return 1;
+}
+
 int w_setColor(lua_State *L)
 {
 	Color c;
@@ -1076,14 +1007,14 @@ int w_getRendererInfo(lua_State *L)
 int w_draw(lua_State *L)
 {
 	Drawable *drawable = 0;
-	DrawGable *drawgable = 0;
-	Geometry *geom = 0;
+	DrawQable *drawqable = 0;
+	Quad *quad = 0;
 	int startidx = 2;
 
-	if (luax_istype(L, 2, GRAPHICS_GEOMETRY_T))
+	if (luax_istype(L, 2, GRAPHICS_QUAD_T))
 	{
-		drawgable = luax_checktype<DrawGable>(L, 1, "DrawGable", GRAPHICS_DRAWGABLE_T);
-		geom = luax_totype<Geometry>(L, 2, "Geometry", GRAPHICS_GEOMETRY_T);
+		drawqable = luax_checktype<DrawQable>(L, 1, "DrawQable", GRAPHICS_DRAWQABLE_T);
+		quad = luax_totype<Quad>(L, 2, "Quad", GRAPHICS_QUAD_T);
 		startidx = 3;
 	}
 	else
@@ -1102,8 +1033,8 @@ int w_draw(lua_State *L)
 	float kx = (float) luaL_optnumber(L, startidx + 7, 0.0);
 	float ky = (float) luaL_optnumber(L, startidx + 8, 0.0);
 
-	if (drawgable && geom)
-		drawgable->drawg(geom, x, y, a, sx, sy, ox, oy, kx, ky);
+	if (drawqable && quad)
+		drawqable->drawq(quad, x, y, a, sx, sy, ox, oy, kx, ky);
 	else if (drawable)
 		drawable->draw(x, y, a, sx, sy, ox, oy, kx, ky);
 
@@ -1371,13 +1302,13 @@ static const luaL_Reg functions[] =
 
 	{ "newImage", w_newImage },
 	{ "newQuad", w_newQuad },
-	{ "newGeometry", w_newGeometry },
 	{ "newFont", w_newFont },
 	{ "newImageFont", w_newImageFont },
 	{ "newSpriteBatch", w_newSpriteBatch },
 	{ "newParticleSystem", w_newParticleSystem },
 	{ "newCanvas", w_newCanvas },
 	{ "newShader", w_newShader },
+	{ "newMesh", w_newMesh },
 
 	{ "setColor", w_setColor },
 	{ "getColor", w_getColor },
@@ -1457,11 +1388,12 @@ static const lua_CFunction types[] =
 {
 	luaopen_font,
 	luaopen_image,
-	luaopen_geometry,
+	luaopen_quad,
 	luaopen_spritebatch,
 	luaopen_particlesystem,
 	luaopen_canvas,
 	luaopen_shader,
+	luaopen_mesh,
 	0
 };
 

+ 3 - 3
src/modules/graphics/opengl/wrap_Graphics.h

@@ -24,11 +24,12 @@
 // LOVE
 #include "wrap_Font.h"
 #include "wrap_Image.h"
-#include "wrap_Geometry.h"
+#include "wrap_Quad.h"
 #include "wrap_SpriteBatch.h"
 #include "wrap_ParticleSystem.h"
 #include "wrap_Canvas.h"
 #include "wrap_Shader.h"
+#include "wrap_Mesh.h"
 #include "Graphics.h"
 
 namespace love
@@ -51,7 +52,6 @@ int w_setStencil(lua_State *L);
 int w_setInvertedStencil(lua_State *L);
 int w_getMaxImageSize(lua_State *L);
 int w_newImage(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);
@@ -59,6 +59,7 @@ int w_newSpriteBatch(lua_State *L);
 int w_newParticleSystem(lua_State *L);
 int w_newCanvas(lua_State *L);  // comments in function
 int w_newShader(lua_State *L);
+int w_newMesh(lua_State *L);
 int w_setColor(lua_State *L);
 int w_getColor(lua_State *L);
 int w_setBackgroundColor(lua_State *L);
@@ -92,7 +93,6 @@ int w_getShader(lua_State *L);
 int w_isSupported(lua_State *L);
 int w_getRendererInfo(lua_State *L);
 int w_draw(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);

+ 280 - 0
src/modules/graphics/opengl/wrap_Mesh.cpp

@@ -0,0 +1,280 @@
+/**
+ * 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_Mesh.h"
+#include "wrap_Image.h"
+
+namespace love
+{
+namespace graphics
+{
+namespace opengl
+{
+
+Mesh *luax_checkmesh(lua_State *L, int idx)
+{
+	return luax_checktype<Mesh>(L, idx, "Mesh", GRAPHICS_MESH_T);
+}
+
+int w_Mesh_setVertex(lua_State *L)
+{
+	Mesh *t = luax_checkmesh(L, 1);
+	size_t i = size_t(luaL_checkinteger(L, 2) - 1);
+
+	Vertex v;
+
+	if (lua_istable(L, 3))
+	{
+		for (int i = 1; i <= 8; i++)
+			lua_rawgeti(L, 3, i);
+
+		v.x = luaL_checknumber(L, -8);
+		v.y = luaL_checknumber(L, -7);
+		v.s = luaL_checknumber(L, -6);
+		v.t = luaL_checknumber(L, -5);
+		v.r = luaL_optinteger(L, -4, 255);
+		v.g = luaL_optinteger(L, -3, 255);
+		v.b = luaL_optinteger(L, -2, 255);
+		v.a = luaL_optinteger(L, -1, 255);
+
+		lua_pop(L, 8);
+	}
+	else
+	{
+		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_optinteger(L,  7, 255);
+		v.g = luaL_optinteger(L,  8, 255);
+		v.b = luaL_optinteger(L,  9, 255);
+		v.a = luaL_optinteger(L, 10, 255);
+	}
+
+	EXCEPT_GUARD(t->setVertex(i, v);)
+	return 0;
+}
+
+int w_Mesh_getVertex(lua_State *L)
+{
+	Mesh *t = luax_checkmesh(L, 1);
+	size_t i = (size_t) (luaL_checkinteger(L, 2) - 1);
+
+	Vertex v;
+	EXCEPT_GUARD(v = t->getVertex(i);)
+
+	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);
+
+	return 8;
+}
+
+int w_Mesh_setVertices(lua_State *L)
+{
+	Mesh *t = luax_checkmesh(L, 1);
+
+	size_t vertex_count = lua_objlen(L, 2);
+	std::vector<Vertex> vertices;
+	vertices.reserve(vertex_count);
+
+	// Get the vertices from the table.
+	for (size_t i = 1; i <= vertex_count; i++)
+	{
+		lua_rawgeti(L, 2, i);
+
+		if (lua_type(L, -1) != LUA_TTABLE)
+			return luax_typerror(L, 2, "table of tables");
+
+		for (int j = 1; j <= 8; j++)
+			lua_rawgeti(L, -j, j);
+
+		Vertex v;
+
+		v.x = (float) luaL_checknumber(L, -8);
+		v.y = (float) luaL_checknumber(L, -7);
+
+		v.s = (float) luaL_checknumber(L, -6);
+		v.t = (float) luaL_checknumber(L, -5);
+
+		v.r = (unsigned char) luaL_optinteger(L, -4, 255);
+		v.g = (unsigned char) luaL_optinteger(L, -3, 255);
+		v.b = (unsigned char) luaL_optinteger(L, -2, 255);
+		v.a = (unsigned char) luaL_optinteger(L, -1, 255);
+
+		lua_pop(L, 9);
+		vertices.push_back(v);
+	}
+
+	EXCEPT_GUARD(t->setVertices(vertices);)
+	return 0;
+}
+
+int w_Mesh_getVertexCount(lua_State *L)
+{
+	Mesh *t = luax_checkmesh(L, 1);
+	lua_pushinteger(L, t->getVertexCount());
+	return 1;
+}
+
+int w_Mesh_setVertexMap(lua_State *L)
+{
+	Mesh *t = luax_checkmesh(L, 1);
+
+	bool is_table = lua_istable(L, 2);
+	int nargs = is_table ? lua_objlen(L, 2) : lua_gettop(L) - 1;
+
+	std::vector<uint32> vertexmap;
+	vertexmap.reserve(nargs);
+
+	for (int i = 0; i < nargs; i++)
+	{
+		if (is_table)
+		{
+			lua_rawgeti(L, 2, i + 1);
+			vertexmap.push_back(uint32(luaL_checkinteger(L, -1) - 1));
+			lua_pop(L, 1);
+		}
+		else
+			vertexmap.push_back(uint32(luaL_checkinteger(L, i + 2) - 1));
+	}
+
+	EXCEPT_GUARD(t->setVertexMap(vertexmap);)
+	return 0;
+}
+
+int w_Mesh_getVertexMap(lua_State *L)
+{
+	Mesh *t = luax_checkmesh(L, 1);
+	const uint32 *vertex_map = 0;
+
+	EXCEPT_GUARD(vertex_map = t->getVertexMap();)
+	size_t elements = t->getVertexMapCount();
+
+	lua_createtable(L, elements, 0);
+
+	for (size_t i = 0; i < elements; i++)
+	{
+		lua_pushinteger(L, lua_Integer(vertex_map[i]) + 1);
+		lua_rawseti(L, -2, i + 1);
+	}
+
+	return 1;
+}
+
+int w_Mesh_setImage(lua_State *L)
+{
+	Mesh *t = luax_checkmesh(L, 1);
+
+	if (lua_isnoneornil(L, 2))
+		t->setImage();
+	else
+	{
+		Image *img = luax_checkimage(L, 2);
+		t->setImage(img);
+	}
+
+	return 0;
+}
+
+int w_Mesh_getImage(lua_State *L)
+{
+	Mesh *t = luax_checkmesh(L, 1);
+	Image *img = t->getImage();
+
+	if (img == NULL)
+		return 0;
+
+	img->retain();
+	luax_pushtype(L, "Image", GRAPHICS_IMAGE_T, img);
+	return 1;
+}
+
+int w_Mesh_setDrawMode(lua_State *L)
+{
+	Mesh *t = luax_checkmesh(L, 1);
+	const char *str = luaL_checkstring(L, 2);
+	Mesh::DrawMode mode;
+
+	if (!Mesh::getConstant(str, mode))
+		return luaL_error(L, "Invalid mesh draw mode: %s", str);
+
+	t->setDrawMode(mode);
+	return 0;
+}
+
+int w_Mesh_getDrawMode(lua_State *L)
+{
+	Mesh *t = luax_checkmesh(L, 1);
+	Mesh::DrawMode mode = t->getDrawMode();
+	const char *str;
+
+	if (!Mesh::getConstant(mode, str))
+		return luaL_error(L, "Unknown mesh draw mode.");
+
+	lua_pushstring(L, str);
+	return 1;
+}
+
+int w_Mesh_setVertexColors(lua_State *L)
+{
+	Mesh *t = luax_checkmesh(L, 1);
+	t->setVertexColors(luax_toboolean(L, 2));
+	return 0;
+}
+
+int w_Mesh_hasVertexColors(lua_State *L)
+{
+	Mesh *t = luax_checkmesh(L, 1);
+	luax_pushboolean(L, t->hasVertexColors());
+	return 1;
+}
+
+static const luaL_Reg functions[] =
+{
+	{ "setVertex", w_Mesh_setVertex },
+	{ "getVertex", w_Mesh_getVertex },
+	{ "setVertices", w_Mesh_setVertices },
+	{ "getVertexCount", w_Mesh_getVertexCount },
+	{ "setVertexMap", w_Mesh_setVertexMap },
+	{ "getVertexMap", w_Mesh_getVertexMap },
+	{ "setImage", w_Mesh_setImage },
+	{ "getImage", w_Mesh_getImage },
+	{ "setDrawMode", w_Mesh_setDrawMode },
+	{ "getDrawMode", w_Mesh_getDrawMode },
+	{ "setVertexColors", w_Mesh_setVertexColors },
+	{ "hasVertexColors", w_Mesh_hasVertexColors },
+	{ 0, 0 }
+};
+
+extern "C" int luaopen_mesh(lua_State *L)
+{
+	return luax_register_type(L, "Mesh", functions);
+}
+
+} // opengl
+} // graphics
+} // love

+ 20 - 14
src/modules/graphics/opengl/wrap_Geometry.h → src/modules/graphics/opengl/wrap_Mesh.h

@@ -18,12 +18,12 @@
  * 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
+#ifndef LOVE_GRAPHICS_OPENGL_WRAP_MESH_H
+#define LOVE_GRAPHICS_OPENGL_WRAP_MESH_H
 
 // LOVE
 #include "common/runtime.h"
-#include "graphics/Geometry.h"
+#include "Mesh.h"
 
 namespace love
 {
@@ -32,19 +32,25 @@ namespace graphics
 namespace opengl
 {
 
-Geometry *luax_checkgeometry(lua_State *L, int idx);
-int w_Geometry_getVertexCount(lua_State *L);
-int w_Geometry_getVertex(lua_State *L);
-int w_Geometry_setVertex(lua_State *L);
-int w_Geometry_setVertexColors(lua_State *L);
-int w_Geometry_hasVertexColors(lua_State *L);
-int w_Geometry_getDrawMode(lua_State *L);
-int w_Geometry_getVertexMap(lua_State *L);
-int w_Geometry_setVertexMap(lua_State *L);
-extern "C" int luaopen_geometry(lua_State *L);
+Mesh *luax_checkmesh(lua_State *L, int idx);
+
+int w_Mesh_setVertex(lua_State *L);
+int w_Mesh_getVertex(lua_State *L);
+int w_Mesh_setVertices(lua_State *L);
+int w_Mesh_getVertexCount(lua_State *L);
+int w_Mesh_setVertexMap(lua_State *L);
+int w_Mesh_getVertexMap(lua_State *L);
+int w_Mesh_setImage(lua_State *L);
+int w_Mesh_getImage(lua_State *L);
+int w_Mesh_setDrawMode(lua_State *L);
+int w_Mesh_getDrawMode(lua_State *L);
+int w_Mesh_setVertexColors(lua_State *L);
+int w_Mesh_hasVertexColors(lua_State *L);
+
+extern "C" int luaopen_mesh(lua_State *L);
 
 } // opengl
 } // graphics
 } // love
 
-#endif // LOVE_GRAPHICS_OPENGL_WRAP_GEOMETRY_H
+#endif // LOVE_GRAPHICS_OPENGL_WRAP_MESH_H

+ 91 - 0
src/modules/graphics/opengl/wrap_Quad.cpp

@@ -0,0 +1,91 @@
+/**
+ * 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_Quad.h"
+
+namespace love
+{
+namespace graphics
+{
+namespace opengl
+{
+
+Quad *luax_checkquad(lua_State *L, int idx)
+{
+	return luax_checktype<Quad>(L, idx, "Quad", GRAPHICS_QUAD_T);
+}
+
+int w_Quad_flip(lua_State *L)
+{
+	Quad *quad = luax_checkquad(L, 1);
+	quad->flip(luax_toboolean(L, 2), luax_toboolean(L, 3));
+	return 0;
+}
+
+int w_Quad_setViewport(lua_State *L)
+{
+	Quad *quad = luax_checkquad(L, 1);
+
+	Quad::Viewport v;
+	v.x = (float) luaL_checknumber(L, 2);
+	v.y = (float) luaL_checknumber(L, 3);
+	v.w = (float) luaL_checknumber(L, 4);
+	v.h = (float) luaL_checknumber(L, 5);
+
+	if (lua_isnoneornil(L, 6))
+		quad->setViewport(v);
+	else
+	{
+		float sw = (float) luaL_checknumber(L, 6);
+		float sh = (float) luaL_checknumber(L, 7);
+		quad->refresh(v, sw, sh);
+	}
+
+	return 0;
+}
+
+int w_Quad_getViewport(lua_State *L)
+{
+	Quad *quad = luax_checkquad(L, 1);
+	Quad::Viewport v = quad->getViewport();
+	lua_pushnumber(L, v.x);
+	lua_pushnumber(L, v.y);
+	lua_pushnumber(L, v.w);
+	lua_pushnumber(L, v.h);
+	return 4;
+}
+
+static const luaL_Reg functions[] =
+{
+	{ "flip", w_Quad_flip },
+	{ "setViewport", w_Quad_setViewport },
+	{ "getViewport", w_Quad_getViewport },
+	{ 0, 0 }
+};
+
+extern "C" int luaopen_quad(lua_State *L)
+{
+	return luax_register_type(L, "Quad", functions);
+}
+
+} // opengl
+} // graphics
+} // love

+ 16 - 4
src/modules/graphics/DrawGable.cpp → src/modules/graphics/opengl/wrap_Quad.h

@@ -18,16 +18,28 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
-#include "DrawGable.h"
+#ifndef LOVE_GRAPHICS_OPENGL_WRAP_QUAD_H
+#define LOVE_GRAPHICS_OPENGL_WRAP_QUAD_H
+
+// LOVE
+#include "common/runtime.h"
+#include "graphics/Quad.h"
 
 namespace love
 {
 namespace graphics
 {
-
-DrawGable::~DrawGable()
+namespace opengl
 {
-}
 
+Quad *luax_checkquad(lua_State *L, int idx);
+int w_Quad_flip(lua_State *L);
+int w_Quad_setViewport(lua_State *L);
+int w_Quad_getViewport(lua_State *L);
+extern "C" int luaopen_quad(lua_State *L);
+
+} // opengl
 } // graphics
 } // love
+
+#endif // LOVE_GRAPHICS_OPENGL_WRAP_QUAD_H

+ 10 - 10
src/modules/graphics/opengl/wrap_SpriteBatch.cpp

@@ -36,12 +36,12 @@ SpriteBatch *luax_checkspritebatch(lua_State *L, int idx)
 int w_SpriteBatch_add(lua_State *L)
 {
 	SpriteBatch *t = luax_checkspritebatch(L, 1);
-	Geometry *geom = 0;
+	Quad *quad = 0;
 	int startidx = 2;
 
-	if (luax_istype(L, 2, GRAPHICS_GEOMETRY_T))
+	if (luax_istype(L, 2, GRAPHICS_QUAD_T))
 	{
-		geom = luax_totype<Geometry>(L, 2, "Geometry", GRAPHICS_GEOMETRY_T);
+		quad = luax_totype<Quad>(L, 2, "Quad", GRAPHICS_QUAD_T);
 		startidx = 3;
 	}
 
@@ -57,8 +57,8 @@ int w_SpriteBatch_add(lua_State *L)
 
 	int id = 0;
 	EXCEPT_GUARD(
-		if (geom)
-			id = t->addg(geom, x, y, a, sx, sy, ox, oy, kx, ky);
+		if (quad)
+			id = t->addq(quad, x, y, a, sx, sy, ox, oy, kx, ky);
 		else
 			id = t->add(x, y, a, sx, sy, ox, oy, kx, ky);
 	)
@@ -72,12 +72,12 @@ int w_SpriteBatch_set(lua_State *L)
 	SpriteBatch *t = luax_checkspritebatch(L, 1);
 	int id = luaL_checkinteger(L, 2);
 
-	Geometry *geom = 0;
+	Quad *quad = 0;
 	int startidx = 3;
 
-	if (luax_istype(L, 3, GRAPHICS_GEOMETRY_T))
+	if (luax_istype(L, 3, GRAPHICS_QUAD_T))
 	{
-		geom = luax_totype<Geometry>(L, 3, "Geometry", GRAPHICS_GEOMETRY_T);
+		quad = luax_totype<Quad>(L, 3, "Quad", GRAPHICS_QUAD_T);
 		startidx = 4;
 	}
 
@@ -92,8 +92,8 @@ int w_SpriteBatch_set(lua_State *L)
 	float ky = (float) luaL_optnumber(L, startidx + 8, 0.0);
 
 	EXCEPT_GUARD(
-		if (geom)
-			t->addg(geom, x, y, a, sx, sy, ox, oy, kx, ky, id);
+		if (quad)
+			t->addq(quad, x, y, a, sx, sy, ox, oy, kx, ky, id);
 		else
 			t->add(x, y, a, sx, sy, ox, oy, kx, ky, id);
 	)