Browse Source

More code restructuring.

Move all love.graphics functionality that doesn’t call OpenGL out of the OpenGL backend Graphics class.

--HG--
branch : minor
Alex Szpakowski 8 years ago
parent
commit
f12596dd19
38 changed files with 1582 additions and 1410 deletions
  1. 8 4
      CMakeLists.txt
  2. 38 20
      platform/xcode/liblove.xcodeproj/project.pbxproj
  3. 52 0
      src/modules/graphics/Canvas.cpp
  4. 65 0
      src/modules/graphics/Canvas.h
  5. 1 2
      src/modules/graphics/Font.h
  6. 498 2
      src/modules/graphics/Graphics.cpp
  7. 302 10
      src/modules/graphics/Graphics.h
  8. 145 0
      src/modules/graphics/Shader.cpp
  9. 184 0
      src/modules/graphics/Shader.h
  10. 4 11
      src/modules/graphics/Texture.cpp
  11. 4 7
      src/modules/graphics/Texture.h
  12. 3 27
      src/modules/graphics/opengl/Canvas.cpp
  13. 12 28
      src/modules/graphics/opengl/Canvas.h
  14. 2 1
      src/modules/graphics/opengl/Font.h
  15. 8 6
      src/modules/graphics/opengl/GLBuffer.cpp
  16. 5 6
      src/modules/graphics/opengl/GLBuffer.h
  17. 73 555
      src/modules/graphics/opengl/Graphics.cpp
  18. 39 310
      src/modules/graphics/opengl/Graphics.h
  19. 0 23
      src/modules/graphics/opengl/Image.cpp
  20. 0 8
      src/modules/graphics/opengl/Image.h
  21. 7 41
      src/modules/graphics/opengl/Mesh.cpp
  22. 5 21
      src/modules/graphics/opengl/Mesh.h
  23. 16 1
      src/modules/graphics/opengl/OpenGL.cpp
  24. 1 19
      src/modules/graphics/opengl/OpenGL.h
  25. 14 112
      src/modules/graphics/opengl/Shader.cpp
  26. 13 146
      src/modules/graphics/opengl/Shader.h
  27. 2 3
      src/modules/graphics/opengl/SpriteBatch.cpp
  28. 1 1
      src/modules/graphics/opengl/SpriteBatch.h
  29. 1 1
      src/modules/graphics/opengl/Text.cpp
  30. 3 3
      src/modules/graphics/opengl/Video.cpp
  31. 18 18
      src/modules/graphics/opengl/wrap_Graphics.cpp
  32. 2 2
      src/modules/graphics/opengl/wrap_Graphics.h
  33. 20 0
      src/modules/graphics/vertex.cpp
  34. 31 0
      src/modules/graphics/vertex.h
  35. 0 3
      src/modules/graphics/wrap_Canvas.cpp
  36. 2 8
      src/modules/graphics/wrap_Canvas.h
  37. 2 4
      src/modules/graphics/wrap_Shader.cpp
  38. 1 7
      src/modules/graphics/wrap_Shader.h

+ 8 - 4
CMakeLists.txt

@@ -465,6 +465,8 @@ source_group("modules\\font\\freetype" FILES ${LOVE_SRC_MODULE_FONT_FREETYPE})
 #
 
 set(LOVE_SRC_MODULE_GRAPHICS_ROOT
+	src/modules/graphics/Canvas.cpp
+	src/modules/graphics/Canvas.h
 	src/modules/graphics/Color.h
 	src/modules/graphics/Drawable.cpp
 	src/modules/graphics/Drawable.h
@@ -478,6 +480,8 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT
 	src/modules/graphics/Polyline.h
 	src/modules/graphics/Quad.cpp
 	src/modules/graphics/Quad.h
+	src/modules/graphics/Shader.cpp
+	src/modules/graphics/Shader.h
 	src/modules/graphics/StreamBuffer.cpp
 	src/modules/graphics/StreamBuffer.h
 	src/modules/graphics/Texture.cpp
@@ -486,10 +490,14 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT
 	src/modules/graphics/vertex.h
 	src/modules/graphics/Volatile.cpp
 	src/modules/graphics/Volatile.h
+	src/modules/graphics/wrap_Canvas.cpp
+	src/modules/graphics/wrap_Canvas.h
 	src/modules/graphics/wrap_Font.cpp
 	src/modules/graphics/wrap_Font.h
 	src/modules/graphics/wrap_Quad.cpp
 	src/modules/graphics/wrap_Quad.h
+	src/modules/graphics/wrap_Shader.cpp
+	src/modules/graphics/wrap_Shader.h
 	src/modules/graphics/wrap_Texture.cpp
 	src/modules/graphics/wrap_Texture.h
 )
@@ -519,8 +527,6 @@ set(LOVE_SRC_MODULE_GRAPHICS_OPENGL
 	src/modules/graphics/opengl/Text.h
 	src/modules/graphics/opengl/Video.cpp
 	src/modules/graphics/opengl/Video.h
-	src/modules/graphics/opengl/wrap_Canvas.cpp
-	src/modules/graphics/opengl/wrap_Canvas.h
 	src/modules/graphics/opengl/wrap_Graphics.cpp
 	src/modules/graphics/opengl/wrap_Graphics.h
 	src/modules/graphics/opengl/wrap_Image.cpp
@@ -529,8 +535,6 @@ set(LOVE_SRC_MODULE_GRAPHICS_OPENGL
 	src/modules/graphics/opengl/wrap_Mesh.h
 	src/modules/graphics/opengl/wrap_ParticleSystem.cpp
 	src/modules/graphics/opengl/wrap_ParticleSystem.h
-	src/modules/graphics/opengl/wrap_Shader.cpp
-	src/modules/graphics/opengl/wrap_Shader.h
 	src/modules/graphics/opengl/wrap_SpriteBatch.cpp
 	src/modules/graphics/opengl/wrap_SpriteBatch.h
 	src/modules/graphics/opengl/wrap_Text.cpp

+ 38 - 20
platform/xcode/liblove.xcodeproj/project.pbxproj

@@ -456,9 +456,6 @@
 		FA0B7D551A95902C000E1D17 /* GLBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BA41A95902C000E1D17 /* GLBuffer.cpp */; };
 		FA0B7D561A95902C000E1D17 /* GLBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BA41A95902C000E1D17 /* GLBuffer.cpp */; };
 		FA0B7D571A95902C000E1D17 /* GLBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BA51A95902C000E1D17 /* GLBuffer.h */; };
-		FA0B7D581A95902C000E1D17 /* wrap_Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BA61A95902C000E1D17 /* wrap_Canvas.cpp */; };
-		FA0B7D591A95902C000E1D17 /* wrap_Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BA61A95902C000E1D17 /* wrap_Canvas.cpp */; };
-		FA0B7D5A1A95902C000E1D17 /* wrap_Canvas.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BA71A95902C000E1D17 /* wrap_Canvas.h */; };
 		FA0B7D5E1A95902C000E1D17 /* wrap_Graphics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BAA1A95902C000E1D17 /* wrap_Graphics.cpp */; };
 		FA0B7D5F1A95902C000E1D17 /* wrap_Graphics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BAA1A95902C000E1D17 /* wrap_Graphics.cpp */; };
 		FA0B7D601A95902C000E1D17 /* wrap_Graphics.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BAB1A95902C000E1D17 /* wrap_Graphics.h */; };
@@ -471,9 +468,6 @@
 		FA0B7D671A95902C000E1D17 /* wrap_ParticleSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BB01A95902C000E1D17 /* wrap_ParticleSystem.cpp */; };
 		FA0B7D681A95902C000E1D17 /* wrap_ParticleSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BB01A95902C000E1D17 /* wrap_ParticleSystem.cpp */; };
 		FA0B7D691A95902C000E1D17 /* wrap_ParticleSystem.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BB11A95902C000E1D17 /* wrap_ParticleSystem.h */; };
-		FA0B7D6D1A95902C000E1D17 /* wrap_Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BB41A95902C000E1D17 /* wrap_Shader.cpp */; };
-		FA0B7D6E1A95902C000E1D17 /* wrap_Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BB41A95902C000E1D17 /* wrap_Shader.cpp */; };
-		FA0B7D6F1A95902C000E1D17 /* wrap_Shader.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BB51A95902C000E1D17 /* wrap_Shader.h */; };
 		FA0B7D701A95902C000E1D17 /* wrap_SpriteBatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BB61A95902C000E1D17 /* wrap_SpriteBatch.cpp */; };
 		FA0B7D711A95902C000E1D17 /* wrap_SpriteBatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7BB61A95902C000E1D17 /* wrap_SpriteBatch.cpp */; };
 		FA0B7D721A95902C000E1D17 /* wrap_SpriteBatch.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7BB71A95902C000E1D17 /* wrap_SpriteBatch.h */; };
@@ -851,6 +845,17 @@
 		FA1BA0A21E16D97500AA2803 /* wrap_Font.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0A01E16D97500AA2803 /* wrap_Font.cpp */; };
 		FA1BA0A31E16D97500AA2803 /* wrap_Font.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0A01E16D97500AA2803 /* wrap_Font.cpp */; };
 		FA1BA0A41E16D97500AA2803 /* wrap_Font.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1BA0A11E16D97500AA2803 /* wrap_Font.h */; };
+		FA1BA0A71E16F20600AA2803 /* Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0A51E16F20600AA2803 /* Canvas.cpp */; };
+		FA1BA0A81E16F20600AA2803 /* Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0A51E16F20600AA2803 /* Canvas.cpp */; };
+		FA1BA0A91E16F20600AA2803 /* Canvas.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1BA0A61E16F20600AA2803 /* Canvas.h */; };
+		FA1BA0AC1E16F9EE00AA2803 /* wrap_Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0AA1E16F9EE00AA2803 /* wrap_Canvas.cpp */; };
+		FA1BA0AD1E16F9EE00AA2803 /* wrap_Canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0AA1E16F9EE00AA2803 /* wrap_Canvas.cpp */; };
+		FA1BA0AE1E16F9EE00AA2803 /* wrap_Canvas.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1BA0AB1E16F9EE00AA2803 /* wrap_Canvas.h */; };
+		FA1BA0B11E16FD0800AA2803 /* Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0AF1E16FD0800AA2803 /* Shader.cpp */; };
+		FA1BA0B21E16FD0800AA2803 /* Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0AF1E16FD0800AA2803 /* Shader.cpp */; };
+		FA1BA0B31E16FD0800AA2803 /* Shader.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1BA0B01E16FD0800AA2803 /* Shader.h */; };
+		FA1BA0B71E17043400AA2803 /* wrap_Shader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1BA0B51E17043400AA2803 /* wrap_Shader.cpp */; };
+		FA1BA0B81E17043400AA2803 /* wrap_Shader.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1BA0B61E17043400AA2803 /* wrap_Shader.h */; };
 		FA1DC2631C5D9555008F99A0 /* HashFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1DC2611C5D9555008F99A0 /* HashFunction.cpp */; };
 		FA1DC2641C5D9555008F99A0 /* HashFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1DC2621C5D9555008F99A0 /* HashFunction.h */; };
 		FA1E887E1DF363CD00E808AA /* Filter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA1E887C1DF363CD00E808AA /* Filter.cpp */; };
@@ -1344,8 +1349,6 @@
 		FA0B7BA21A95902C000E1D17 /* Text.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Text.h; sourceTree = "<group>"; };
 		FA0B7BA41A95902C000E1D17 /* GLBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GLBuffer.cpp; sourceTree = "<group>"; };
 		FA0B7BA51A95902C000E1D17 /* GLBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLBuffer.h; sourceTree = "<group>"; };
-		FA0B7BA61A95902C000E1D17 /* wrap_Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Canvas.cpp; sourceTree = "<group>"; };
-		FA0B7BA71A95902C000E1D17 /* wrap_Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Canvas.h; sourceTree = "<group>"; };
 		FA0B7BAA1A95902C000E1D17 /* wrap_Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Graphics.cpp; sourceTree = "<group>"; };
 		FA0B7BAB1A95902C000E1D17 /* wrap_Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Graphics.h; sourceTree = "<group>"; };
 		FA0B7BAC1A95902C000E1D17 /* wrap_Image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Image.cpp; sourceTree = "<group>"; };
@@ -1354,8 +1357,6 @@
 		FA0B7BAF1A95902C000E1D17 /* wrap_Mesh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Mesh.h; sourceTree = "<group>"; };
 		FA0B7BB01A95902C000E1D17 /* wrap_ParticleSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_ParticleSystem.cpp; sourceTree = "<group>"; };
 		FA0B7BB11A95902C000E1D17 /* wrap_ParticleSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_ParticleSystem.h; sourceTree = "<group>"; };
-		FA0B7BB41A95902C000E1D17 /* wrap_Shader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Shader.cpp; sourceTree = "<group>"; };
-		FA0B7BB51A95902C000E1D17 /* wrap_Shader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Shader.h; sourceTree = "<group>"; };
 		FA0B7BB61A95902C000E1D17 /* wrap_SpriteBatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_SpriteBatch.cpp; sourceTree = "<group>"; };
 		FA0B7BB71A95902C000E1D17 /* wrap_SpriteBatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_SpriteBatch.h; sourceTree = "<group>"; };
 		FA0B7BB81A95902C000E1D17 /* wrap_Text.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Text.cpp; sourceTree = "<group>"; };
@@ -1613,6 +1614,14 @@
 		FA1BA09C1E16CFCE00AA2803 /* Font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Font.h; sourceTree = "<group>"; };
 		FA1BA0A01E16D97500AA2803 /* wrap_Font.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Font.cpp; sourceTree = "<group>"; };
 		FA1BA0A11E16D97500AA2803 /* wrap_Font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Font.h; sourceTree = "<group>"; };
+		FA1BA0A51E16F20600AA2803 /* Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Canvas.cpp; sourceTree = "<group>"; };
+		FA1BA0A61E16F20600AA2803 /* Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Canvas.h; sourceTree = "<group>"; };
+		FA1BA0AA1E16F9EE00AA2803 /* wrap_Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Canvas.cpp; sourceTree = "<group>"; };
+		FA1BA0AB1E16F9EE00AA2803 /* wrap_Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Canvas.h; sourceTree = "<group>"; };
+		FA1BA0AF1E16FD0800AA2803 /* Shader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Shader.cpp; sourceTree = "<group>"; };
+		FA1BA0B01E16FD0800AA2803 /* Shader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Shader.h; sourceTree = "<group>"; };
+		FA1BA0B51E17043400AA2803 /* wrap_Shader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Shader.cpp; sourceTree = "<group>"; };
+		FA1BA0B61E17043400AA2803 /* wrap_Shader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Shader.h; sourceTree = "<group>"; };
 		FA1DC2611C5D9555008F99A0 /* HashFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HashFunction.cpp; sourceTree = "<group>"; };
 		FA1DC2621C5D9555008F99A0 /* HashFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HashFunction.h; sourceTree = "<group>"; };
 		FA1E887C1DF363CD00E808AA /* Filter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Filter.cpp; sourceTree = "<group>"; };
@@ -2434,6 +2443,8 @@
 		FA0B7B871A95902C000E1D17 /* graphics */ = {
 			isa = PBXGroup;
 			children = (
+				FA1BA0A51E16F20600AA2803 /* Canvas.cpp */,
+				FA1BA0A61E16F20600AA2803 /* Canvas.h */,
 				FA0B7B881A95902C000E1D17 /* Color.h */,
 				FA9D8DDC1DEF842A002CD881 /* Drawable.cpp */,
 				FA0B7B891A95902C000E1D17 /* Drawable.h */,
@@ -2448,6 +2459,8 @@
 				FA0B7B9C1A95902C000E1D17 /* Polyline.h */,
 				FA0B7BBC1A95902C000E1D17 /* Quad.cpp */,
 				FA0B7BBD1A95902C000E1D17 /* Quad.h */,
+				FA1BA0AF1E16FD0800AA2803 /* Shader.cpp */,
+				FA1BA0B01E16FD0800AA2803 /* Shader.h */,
 				FA29C0041E12355B00268CD8 /* StreamBuffer.cpp */,
 				FA2AF6721DAD62710032B62C /* StreamBuffer.h */,
 				FA0B7BBE1A95902C000E1D17 /* Texture.cpp */,
@@ -2456,10 +2469,14 @@
 				FA2AF6711DAC76FF0032B62C /* vertex.h */,
 				FA0B7BC01A95902C000E1D17 /* Volatile.cpp */,
 				FA0B7BC11A95902C000E1D17 /* Volatile.h */,
+				FA1BA0AA1E16F9EE00AA2803 /* wrap_Canvas.cpp */,
+				FA1BA0AB1E16F9EE00AA2803 /* wrap_Canvas.h */,
 				FA1BA0A01E16D97500AA2803 /* wrap_Font.cpp */,
 				FA1BA0A11E16D97500AA2803 /* wrap_Font.h */,
 				FA620A2E1AA2F8DB005DB4C2 /* wrap_Quad.cpp */,
 				FA620A2F1AA2F8DB005DB4C2 /* wrap_Quad.h */,
+				FA1BA0B51E17043400AA2803 /* wrap_Shader.cpp */,
+				FA1BA0B61E17043400AA2803 /* wrap_Shader.h */,
 				FA620A301AA2F8DB005DB4C2 /* wrap_Texture.cpp */,
 				FA620A311AA2F8DB005DB4C2 /* wrap_Texture.h */,
 			);
@@ -2493,8 +2510,6 @@
 				FA0B7BA21A95902C000E1D17 /* Text.h */,
 				FA27B3C31B4985D8008A9DCE /* Video.cpp */,
 				FA27B3C41B4985D8008A9DCE /* Video.h */,
-				FA0B7BA61A95902C000E1D17 /* wrap_Canvas.cpp */,
-				FA0B7BA71A95902C000E1D17 /* wrap_Canvas.h */,
 				FA0B7BAA1A95902C000E1D17 /* wrap_Graphics.cpp */,
 				FA0B7BAB1A95902C000E1D17 /* wrap_Graphics.h */,
 				FA6AE6041B3335EC00583D5C /* wrap_Graphics.lua */,
@@ -2504,8 +2519,6 @@
 				FA0B7BAF1A95902C000E1D17 /* wrap_Mesh.h */,
 				FA0B7BB01A95902C000E1D17 /* wrap_ParticleSystem.cpp */,
 				FA0B7BB11A95902C000E1D17 /* wrap_ParticleSystem.h */,
-				FA0B7BB41A95902C000E1D17 /* wrap_Shader.cpp */,
-				FA0B7BB51A95902C000E1D17 /* wrap_Shader.h */,
 				FA0B7BB61A95902C000E1D17 /* wrap_SpriteBatch.cpp */,
 				FA0B7BB71A95902C000E1D17 /* wrap_SpriteBatch.h */,
 				FA0B7BB81A95902C000E1D17 /* wrap_Text.cpp */,
@@ -3134,6 +3147,7 @@
 				FA0B7D7E1A95902C000E1D17 /* Texture.h in Headers */,
 				FA0B7E561A95902C000E1D17 /* wrap_GearJoint.h in Headers */,
 				FA0B7E1D1A95902C000E1D17 /* MouseJoint.h in Headers */,
+				FA1BA0B81E17043400AA2803 /* wrap_Shader.h in Headers */,
 				FA1557C41CE90BD200AFF582 /* EXRHandler.h in Headers */,
 				FA0B7DC91A95902C000E1D17 /* Keyboard.h in Headers */,
 				FA0B7D4A1A95902C000E1D17 /* Polyline.h in Headers */,
@@ -3234,6 +3248,7 @@
 				FA0B7E441A95902C000E1D17 /* wrap_CircleShape.h in Headers */,
 				FA0B7EB41A95902C000E1D17 /* System.h in Headers */,
 				FA0B7CE11A95902C000E1D17 /* Source.h in Headers */,
+				FA1BA0AE1E16F9EE00AA2803 /* wrap_Canvas.h in Headers */,
 				FA0B7E621A95902C000E1D17 /* wrap_Physics.h in Headers */,
 				FA0B7DF01A95902C000E1D17 /* Mouse.h in Headers */,
 				217DFBDC1D9F6D490055D849 /* buffer.h in Headers */,
@@ -3270,6 +3285,7 @@
 				FAB17BE81ABFAA9000F9BA27 /* lz4.h in Headers */,
 				FA0B7E6B1A95902C000E1D17 /* wrap_PulleyJoint.h in Headers */,
 				FA0B7E051A95902C000E1D17 /* Contact.h in Headers */,
+				FA1BA0A91E16F20600AA2803 /* Canvas.h in Headers */,
 				FA0B7A691A958EA3000E1D17 /* b2Island.h in Headers */,
 				FA4F2BE41DE6650600CA37D7 /* Transform.h in Headers */,
 				FA0B7E0E1A95902C000E1D17 /* Fixture.h in Headers */,
@@ -3352,6 +3368,7 @@
 				FA0B7E651A95902C000E1D17 /* wrap_PolygonShape.h in Headers */,
 				FA0B7AC91A958EA3000E1D17 /* win32.h in Headers */,
 				FA0B7DFC1A95902C000E1D17 /* Body.h in Headers */,
+				FA1BA0B31E16FD0800AA2803 /* Shader.h in Headers */,
 				217DFC101D9F6D490055D849 /* url.lua.h in Headers */,
 				FA0B7A941A958EA3000E1D17 /* b2GearJoint.h in Headers */,
 				FA0B7DF31A95902C000E1D17 /* wrap_Cursor.h in Headers */,
@@ -3427,7 +3444,6 @@
 				FA0B7A9A1A958EA3000E1D17 /* b2MotorJoint.h in Headers */,
 				217DFC081D9F6D490055D849 /* udp.h in Headers */,
 				FA0B7DCF1A95902C000E1D17 /* wrap_Keyboard.h in Headers */,
-				FA0B7D6F1A95902C000E1D17 /* wrap_Shader.h in Headers */,
 				FA0B7EA21A95902C000E1D17 /* Sound.h in Headers */,
 				FA0B7B331A958EA3000E1D17 /* wuff_config.h in Headers */,
 				FA0B7CF31A95902C000E1D17 /* DroppedFile.h in Headers */,
@@ -3451,7 +3467,6 @@
 				FA0B79311A958E3B000E1D17 /* Module.h in Headers */,
 				217DFBF51D9F6D490055D849 /* mime.lua.h in Headers */,
 				FA9D8DD31DEB56C3002CD881 /* pixelformat.h in Headers */,
-				FA0B7D5A1A95902C000E1D17 /* wrap_Canvas.h in Headers */,
 				FA0B7E4A1A95902C000E1D17 /* wrap_DistanceJoint.h in Headers */,
 				FA0B7D2E1A95902C000E1D17 /* Color.h in Headers */,
 				FA0B7A6A1A958EA3000E1D17 /* b2TimeStep.h in Headers */,
@@ -3574,7 +3589,6 @@
 				FA0B7DA91A95902C000E1D17 /* PVRHandler.cpp in Sources */,
 				FA0B7EC61A95902C000E1D17 /* ThreadModule.cpp in Sources */,
 				FA0B7D2C1A95902C000E1D17 /* wrap_Rasterizer.cpp in Sources */,
-				FA0B7D591A95902C000E1D17 /* wrap_Canvas.cpp in Sources */,
 				FA9D8DD81DEF8411002CD881 /* Data.cpp in Sources */,
 				FA0B7E8F1A95902C000E1D17 /* GmeDecoder.cpp in Sources */,
 				FA0B7CD71A95902C000E1D17 /* Audio.cpp in Sources */,
@@ -3700,6 +3714,7 @@
 				FA2AF6751DAD64970032B62C /* vertex.cpp in Sources */,
 				FA0B7D801A95902C000E1D17 /* Volatile.cpp in Sources */,
 				FA0B792D1A958E3B000E1D17 /* Memoizer.cpp in Sources */,
+				FA1BA0B21E16FD0800AA2803 /* Shader.cpp in Sources */,
 				FA0B7EBC1A95902C000E1D17 /* LuaThread.cpp in Sources */,
 				FA0B7A871A958EA3000E1D17 /* b2PolygonAndCircleContact.cpp in Sources */,
 				FA0B7EF21A959D2C000E1D17 /* ios.mm in Sources */,
@@ -3786,7 +3801,6 @@
 				FA0B7DF81A95902C000E1D17 /* Body.cpp in Sources */,
 				FA4F2BB41DE1E4BD00CA37D7 /* RecordingDevice.cpp in Sources */,
 				FA0B7DF51A95902C000E1D17 /* wrap_Mouse.cpp in Sources */,
-				FA0B7D6E1A95902C000E1D17 /* wrap_Shader.cpp in Sources */,
 				FA0B7E861A95902C000E1D17 /* CoreAudioDecoder.cpp in Sources */,
 				FA0B7E761A95902C000E1D17 /* wrap_WeldJoint.cpp in Sources */,
 				FA0B7D561A95902C000E1D17 /* GLBuffer.cpp in Sources */,
@@ -3834,6 +3848,7 @@
 				FA0B7D4F1A95902C000E1D17 /* SpriteBatch.cpp in Sources */,
 				FAB2D5AB1AABDD8A008224A4 /* TrueTypeRasterizer.cpp in Sources */,
 				FA0B7A9F1A958EA3000E1D17 /* b2PrismaticJoint.cpp in Sources */,
+				FA1BA0AD1E16F9EE00AA2803 /* wrap_Canvas.cpp in Sources */,
 				FA0B79331A958E3B000E1D17 /* Object.cpp in Sources */,
 				FA0B7E5B1A95902C000E1D17 /* wrap_MotorJoint.cpp in Sources */,
 				FA0B79441A958E3B000E1D17 /* Variant.cpp in Sources */,
@@ -3852,6 +3867,7 @@
 				FA0B7E2E1A95902C000E1D17 /* RopeJoint.cpp in Sources */,
 				FA0B7CE01A95902C000E1D17 /* Source.cpp in Sources */,
 				FA0B7ECF1A95902C000E1D17 /* wrap_LuaThread.cpp in Sources */,
+				FA1BA0A81E16F20600AA2803 /* Canvas.cpp in Sources */,
 				FA0B7AA51A958EA3000E1D17 /* b2RevoluteJoint.cpp in Sources */,
 				FA0B7EA11A95902C000E1D17 /* Sound.cpp in Sources */,
 				FA0B7DE61A95902C000E1D17 /* Cursor.cpp in Sources */,
@@ -3894,7 +3910,6 @@
 				217DFC031D9F6D490055D849 /* timeout.c in Sources */,
 				FA9D8DD71DEF8411002CD881 /* Data.cpp in Sources */,
 				FA0B7D2B1A95902C000E1D17 /* wrap_Rasterizer.cpp in Sources */,
-				FA0B7D581A95902C000E1D17 /* wrap_Canvas.cpp in Sources */,
 				FA0B7E8E1A95902C000E1D17 /* GmeDecoder.cpp in Sources */,
 				FA0B7CD61A95902C000E1D17 /* Audio.cpp in Sources */,
 				FA0B7A9E1A958EA3000E1D17 /* b2PrismaticJoint.cpp in Sources */,
@@ -3999,6 +4014,7 @@
 				FA0B7E151A95902C000E1D17 /* Joint.cpp in Sources */,
 				FA0B7EE81A95902D000E1D17 /* wrap_Window.cpp in Sources */,
 				FA0B7E271A95902C000E1D17 /* PulleyJoint.cpp in Sources */,
+				FA1BA0B71E17043400AA2803 /* wrap_Shader.cpp in Sources */,
 				FA0B7B301A958EA3000E1D17 /* wuff.c in Sources */,
 				FA0B7E031A95902C000E1D17 /* Contact.cpp in Sources */,
 				FA0B7D821A95902C000E1D17 /* CompressedImageData.cpp in Sources */,
@@ -4017,6 +4033,7 @@
 				FA2AF6741DAD64970032B62C /* vertex.cpp in Sources */,
 				FA0B7D7F1A95902C000E1D17 /* Volatile.cpp in Sources */,
 				FA0B7A3B1A958EA3000E1D17 /* b2TimeOfImpact.cpp in Sources */,
+				FA1BA0B11E16FD0800AA2803 /* Shader.cpp in Sources */,
 				217DFBED1D9F6D490055D849 /* luasocket.c in Sources */,
 				217DFC011D9F6D490055D849 /* tcp.c in Sources */,
 				FA0B7EBB1A95902C000E1D17 /* LuaThread.cpp in Sources */,
@@ -4099,7 +4116,6 @@
 				FA0B7AAA1A958EA3000E1D17 /* b2WeldJoint.cpp in Sources */,
 				FA0B7DF71A95902C000E1D17 /* Body.cpp in Sources */,
 				FA0B7DF41A95902C000E1D17 /* wrap_Mouse.cpp in Sources */,
-				FA0B7D6D1A95902C000E1D17 /* wrap_Shader.cpp in Sources */,
 				FA0B7E851A95902C000E1D17 /* CoreAudioDecoder.cpp in Sources */,
 				FA0B7E751A95902C000E1D17 /* wrap_WeldJoint.cpp in Sources */,
 				FA0B7D551A95902C000E1D17 /* GLBuffer.cpp in Sources */,
@@ -4151,6 +4167,7 @@
 				FA0B7E5A1A95902C000E1D17 /* wrap_MotorJoint.cpp in Sources */,
 				FA0B7AA71A958EA3000E1D17 /* b2RopeJoint.cpp in Sources */,
 				FA0B7DD61A95902C000E1D17 /* MathModule.cpp in Sources */,
+				FA1BA0AC1E16F9EE00AA2803 /* wrap_Canvas.cpp in Sources */,
 				FA0B7D0F1A95902C000E1D17 /* BMFontRasterizer.cpp in Sources */,
 				FA0B7E9A1A95902C000E1D17 /* VorbisDecoder.cpp in Sources */,
 				FA0B7E4B1A95902C000E1D17 /* wrap_EdgeShape.cpp in Sources */,
@@ -4169,6 +4186,7 @@
 				FA0B7EA01A95902C000E1D17 /* Sound.cpp in Sources */,
 				FA0B7DE51A95902C000E1D17 /* Cursor.cpp in Sources */,
 				FA0B7EDB1A95902D000E1D17 /* Touch.cpp in Sources */,
+				FA1BA0A71E16F20600AA2803 /* Canvas.cpp in Sources */,
 				FA0B7CE81A95902C000E1D17 /* Event.cpp in Sources */,
 				FA0B7ACF1A958EA3000E1D17 /* peer.c in Sources */,
 				FA0B7ADE1A958EA3000E1D17 /* lodepng.cpp in Sources */,

+ 52 - 0
src/modules/graphics/Canvas.cpp

@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2006-2016 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 "Canvas.h"
+#include "Graphics.h"
+
+namespace love
+{
+namespace graphics
+{
+
+love::Type Canvas::type("Canvas", &Texture::type);
+int Canvas::canvasCount = 0;
+
+Canvas::Canvas()
+{
+	canvasCount++;
+}
+
+Canvas::~Canvas()
+{
+	canvasCount--;
+}
+
+void Canvas::drawv(love::graphics::Graphics *gfx, const love::Matrix4 &t, const Vertex *v)
+{
+	if (gfx->isCanvasActive(this))
+		throw love::Exception("Cannot render a Canvas to itself!");
+
+	Texture::drawv(gfx, t, v);
+}
+
+} // graphics
+} // love
+

+ 65 - 0
src/modules/graphics/Canvas.h

@@ -0,0 +1,65 @@
+/**
+* Copyright (c) 2006-2016 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.
+**/
+
+#pragma once
+
+#include "image/Image.h"
+#include "image/ImageData.h"
+#include "Texture.h"
+
+namespace love
+{
+namespace graphics
+{
+
+class Graphics;
+
+class Canvas : public Texture
+{
+public:
+
+	static love::Type type;
+
+	struct Settings
+	{
+		PixelFormat format = PIXELFORMAT_NORMAL;
+		float pixeldensity = 1.0f;
+		int msaa = 0;
+	};
+
+	Canvas();
+	virtual ~Canvas();
+
+	virtual love::image::ImageData *newImageData(love::image::Image *module, int x, int y, int w, int h) = 0;
+
+	virtual int getMSAA() const = 0;
+	virtual int getRequestedMSAA() const = 0;
+	virtual ptrdiff_t getMSAAHandle() const = 0;
+
+	static int canvasCount;
+
+private:
+
+	void drawv(Graphics *gfx, const Matrix4 &t, const Vertex *v) override;
+	
+}; // Canvas
+
+} // graphics
+} // love

+ 1 - 2
src/modules/graphics/Font.h

@@ -34,7 +34,6 @@
 
 #include "font/Rasterizer.h"
 #include "Texture.h"
-#include "Volatile.h"
 #include "vertex.h"
 
 namespace love
@@ -44,7 +43,7 @@ namespace graphics
 
 class Graphics;
 
-class Font : public Object, public Volatile
+class Font : public Object
 {
 public:
 

+ 498 - 2
src/modules/graphics/Graphics.cpp

@@ -22,6 +22,8 @@
 #include "Graphics.h"
 #include "math/MathModule.h"
 #include "Polyline.h"
+#include "font/Font.h"
+#include "window/Window.h"
 
 // C++
 #include <algorithm>
@@ -79,9 +81,20 @@ Colorf unGammaCorrectColor(const Colorf &c)
 
 love::Type Graphics::type("graphics", &Module::type);
 
+Shader::ShaderSource Graphics::defaultShaderCode[Graphics::RENDERER_MAX_ENUM][2];
+Shader::ShaderSource Graphics::defaultVideoShaderCode[Graphics::RENDERER_MAX_ENUM][2];
+
 Graphics::Graphics()
-	: streamBufferState()
+	: width(0)
+	, height(0)
+	, pixelWidth(0)
+	, pixelHeight(0)
+	, created(false)
+	, active(true)
+	, writingToStencil(false)
+	, streamBufferState()
 	, projectionMatrix()
+	, canvasSwitchCount(0)
 {
 	transformStack.reserve(16);
 	transformStack.push_back(Matrix4());
@@ -89,11 +102,426 @@ Graphics::Graphics()
 
 Graphics::~Graphics()
 {
+	states.clear();
+
+	defaultFont.set(nullptr);
+
+	if (Shader::defaultShader)
+	{
+		Shader::defaultShader->release();
+		Shader::defaultShader = nullptr;
+	}
+
+	if (Shader::defaultVideoShader)
+	{
+		Shader::defaultVideoShader->release();
+		Shader::defaultVideoShader = nullptr;
+	}
+
 	delete streamBufferState.vb[0];
 	delete streamBufferState.vb[1];
 	delete streamBufferState.indexBuffer;
 }
 
+Quad *Graphics::newQuad(Quad::Viewport v, double sw, double sh)
+{
+	return new Quad(v, sw, sh);
+}
+
+int Graphics::getWidth() const
+{
+	return width;
+}
+
+int Graphics::getHeight() const
+{
+	return height;
+}
+
+int Graphics::getPixelWidth() const
+{
+	return pixelWidth;
+}
+
+int Graphics::getPixelHeight() const
+{
+	return pixelHeight;
+}
+
+double Graphics::getCurrentPixelDensity() const
+{
+	if (states.back().canvases.size() > 0)
+	{
+		love::graphics::Canvas *c = states.back().canvases[0];
+		return (double) c->getPixelHeight() / (double) c->getHeight();
+	}
+
+	return getScreenPixelDensity();
+}
+
+double Graphics::getScreenPixelDensity() const
+{
+	return (double) getPixelHeight() / (double) getHeight();
+}
+
+bool Graphics::isCreated() const
+{
+	return created;
+}
+
+bool Graphics::isActive() const
+{
+	// The graphics module is only completely 'active' if there's a window, a
+	// context, and the active variable is set.
+	auto window = getInstance<love::window::Window>(M_WINDOW);
+	return active && isCreated() && window != nullptr && window->isOpen();
+}
+
+void Graphics::reset()
+{
+	DisplayState s;
+	stopDrawToStencilBuffer();
+	restoreState(s);
+	origin();
+}
+
+/**
+ * State functions.
+ **/
+
+void Graphics::restoreState(const DisplayState &s)
+{
+	setColor(s.color);
+	setBackgroundColor(s.backgroundColor);
+
+	setBlendMode(s.blendMode, s.blendAlphaMode);
+
+	setLineWidth(s.lineWidth);
+	setLineStyle(s.lineStyle);
+	setLineJoin(s.lineJoin);
+
+	setPointSize(s.pointSize);
+
+	if (s.scissor)
+		setScissor(s.scissorRect);
+	else
+		setScissor();
+
+	setStencilTest(s.stencilCompare, s.stencilTestValue);
+
+	setFont(s.font.get());
+	setShader(s.shader.get());
+	setCanvas(s.canvases);
+
+	setColorMask(s.colorMask);
+	setWireframe(s.wireframe);
+
+	setDefaultFilter(s.defaultFilter);
+	setDefaultMipmapFilter(s.defaultMipmapFilter, s.defaultMipmapSharpness);
+}
+
+void Graphics::restoreStateChecked(const DisplayState &s)
+{
+	const DisplayState &cur = states.back();
+
+	if (s.color != cur.color)
+		setColor(s.color);
+
+	setBackgroundColor(s.backgroundColor);
+
+	if (s.blendMode != cur.blendMode || s.blendAlphaMode != cur.blendAlphaMode)
+		setBlendMode(s.blendMode, s.blendAlphaMode);
+
+	// These are just simple assignments.
+	setLineWidth(s.lineWidth);
+	setLineStyle(s.lineStyle);
+	setLineJoin(s.lineJoin);
+
+	if (s.pointSize != cur.pointSize)
+		setPointSize(s.pointSize);
+
+	if (s.scissor != cur.scissor || (s.scissor && !(s.scissorRect == cur.scissorRect)))
+	{
+		if (s.scissor)
+			setScissor(s.scissorRect);
+		else
+			setScissor();
+	}
+
+	if (s.stencilCompare != cur.stencilCompare || s.stencilTestValue != cur.stencilTestValue)
+		setStencilTest(s.stencilCompare, s.stencilTestValue);
+
+	setFont(s.font.get());
+	setShader(s.shader.get());
+
+	bool canvaseschanged = s.canvases.size() != cur.canvases.size();
+	if (!canvaseschanged)
+	{
+		for (size_t i = 0; i < s.canvases.size() && i < cur.canvases.size(); i++)
+		{
+			if (s.canvases[i].get() != cur.canvases[i].get())
+			{
+				canvaseschanged = true;
+				break;
+			}
+		}
+	}
+
+	if (canvaseschanged)
+		setCanvas(s.canvases);
+
+	if (s.colorMask != cur.colorMask)
+		setColorMask(s.colorMask);
+
+	if (s.wireframe != cur.wireframe)
+		setWireframe(s.wireframe);
+
+	setDefaultFilter(s.defaultFilter);
+	setDefaultMipmapFilter(s.defaultMipmapFilter, s.defaultMipmapSharpness);
+}
+
+Colorf Graphics::getColor() const
+{
+	return states.back().color;
+}
+
+void Graphics::setBackgroundColor(Colorf c)
+{
+	states.back().backgroundColor = c;
+}
+
+Colorf Graphics::getBackgroundColor() const
+{
+	return states.back().backgroundColor;
+}
+
+void Graphics::checkSetDefaultFont()
+{
+	// We don't create or set the default Font if an existing font is in use.
+	if (states.back().font.get() != nullptr)
+		return;
+
+	// Create a new default font if we don't have one yet.
+	if (!defaultFont.get())
+	{
+		auto fontmodule = Module::getInstance<font::Font>(M_FONT);
+		if (!fontmodule)
+			throw love::Exception("Font module has not been loaded.");
+
+		auto hinting = font::TrueTypeRasterizer::HINTING_NORMAL;
+		StrongRef<font::Rasterizer> r(fontmodule->newTrueTypeRasterizer(12, hinting), Acquire::NORETAIN);
+
+		defaultFont.set(newFont(r.get()), Acquire::NORETAIN);
+	}
+
+	states.back().font.set(defaultFont.get());
+}
+
+void Graphics::setFont(love::graphics::Font *font)
+{
+	// We don't need to set a default font here if null is passed in, since we
+	// only care about the default font in getFont and print.
+	DisplayState &state = states.back();
+	state.font.set(font);
+}
+
+love::graphics::Font *Graphics::getFont()
+{
+	checkSetDefaultFont();
+	return states.back().font.get();
+}
+
+void Graphics::setShader(love::graphics::Shader *shader)
+{
+	if (shader == nullptr)
+		return setShader();
+
+	flushStreamDraws();
+
+	shader->attach();
+
+	states.back().shader.set(shader);
+}
+
+void Graphics::setShader()
+{
+	flushStreamDraws();
+
+	Shader::attachDefault();
+
+	states.back().shader.set(nullptr);
+}
+
+love::graphics::Shader *Graphics::getShader() const
+{
+	return states.back().shader.get();
+}
+
+void Graphics::setCanvas(Canvas *canvas)
+{
+	if (canvas == nullptr)
+		return setCanvas();
+
+	std::vector<Canvas *> canvases = {canvas};
+	setCanvas(canvases);
+}
+
+void Graphics::setCanvas(const std::vector<StrongRef<Canvas>> &canvases)
+{
+	std::vector<Canvas *> canvaslist;
+	canvaslist.reserve(canvases.size());
+
+	for (const StrongRef<Canvas> &c : canvases)
+		canvaslist.push_back(c.get());
+
+	return setCanvas(canvaslist);
+}
+
+std::vector<Canvas *> Graphics::getCanvas() const
+{
+	std::vector<Canvas *> canvases;
+	canvases.reserve(states.back().canvases.size());
+
+	for (const StrongRef<Canvas> &c : states.back().canvases)
+		canvases.push_back(c.get());
+
+	return canvases;
+}
+
+bool Graphics::isCanvasActive() const
+{
+	return !states.back().canvases.empty();
+}
+
+bool Graphics::isCanvasActive(love::graphics::Canvas *canvas) const
+{
+	for (const auto &c : states.back().canvases)
+	{
+		if (c.get() == canvas)
+			return true;
+	}
+
+	return false;
+}
+
+void Graphics::intersectScissor(const Rect &rect)
+{
+	Rect currect = states.back().scissorRect;
+
+	if (!states.back().scissor)
+	{
+		currect.x = 0;
+		currect.y = 0;
+		currect.w = std::numeric_limits<int>::max();
+		currect.h = std::numeric_limits<int>::max();
+	}
+
+	int x1 = std::max(currect.x, rect.x);
+	int y1 = std::max(currect.y, rect.y);
+
+	int x2 = std::min(currect.x + currect.w, rect.x + rect.w);
+	int y2 = std::min(currect.y + currect.h, rect.y + rect.h);
+
+	Rect newrect = {x1, y1, std::max(0, x2 - x1), std::max(0, y2 - y1)};
+	setScissor(newrect);
+}
+
+bool Graphics::getScissor(Rect &rect) const
+{
+	const DisplayState &state = states.back();
+	rect = state.scissorRect;
+	return state.scissor;
+}
+
+void Graphics::getStencilTest(CompareMode &compare, int &value)
+{
+	const DisplayState &state = states.back();
+	compare = state.stencilCompare;
+	value = state.stencilTestValue;
+}
+
+Graphics::ColorMask Graphics::getColorMask() const
+{
+	return states.back().colorMask;
+}
+
+Graphics::BlendMode Graphics::getBlendMode(BlendAlpha &alphamode) const
+{
+	alphamode = states.back().blendAlphaMode;
+	return states.back().blendMode;
+}
+
+void Graphics::setDefaultFilter(const Texture::Filter &f)
+{
+	Texture::defaultFilter = f;
+	states.back().defaultFilter = f;
+}
+
+const Texture::Filter &Graphics::getDefaultFilter() const
+{
+	return Texture::defaultFilter;
+}
+
+void Graphics::setDefaultMipmapFilter(Texture::FilterMode filter, float sharpness)
+{
+	Texture::defaultMipmapFilter = filter;
+	Texture::defaultMipmapSharpness = sharpness;
+
+	states.back().defaultMipmapFilter = filter;
+	states.back().defaultMipmapSharpness = sharpness;
+}
+
+void Graphics::getDefaultMipmapFilter(Texture::FilterMode *filter, float *sharpness) const
+{
+	*filter = Texture::defaultMipmapFilter;
+	*sharpness = Texture::defaultMipmapSharpness;
+}
+
+void Graphics::setLineWidth(float width)
+{
+	states.back().lineWidth = width;
+}
+
+void Graphics::setLineStyle(Graphics::LineStyle style)
+{
+	states.back().lineStyle = style;
+}
+
+void Graphics::setLineJoin(Graphics::LineJoin join)
+{
+	states.back().lineJoin = join;
+}
+
+float Graphics::getLineWidth() const
+{
+	return states.back().lineWidth;
+}
+
+Graphics::LineStyle Graphics::getLineStyle() const
+{
+	return states.back().lineStyle;
+}
+
+Graphics::LineJoin Graphics::getLineJoin() const
+{
+	return states.back().lineJoin;
+}
+
+float Graphics::getPointSize() const
+{
+	return states.back().pointSize;
+}
+
+bool Graphics::isWireframe() const
+{
+	return states.back().wireframe;
+}
+
+void Graphics::captureScreenshot(const ScreenshotInfo &info)
+{
+	pendingScreenshotCallbacks.push_back(info);
+}
+
 Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawRequest &req)
 {
 	using namespace vertex;
@@ -205,6 +633,30 @@ Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawRequest &
 	return d;
 }
 
+/**
+ * Drawing
+ **/
+
+void Graphics::print(const std::vector<Font::ColoredString> &str, const Matrix4 &m)
+{
+	checkSetDefaultFont();
+
+	DisplayState &state = states.back();
+
+	if (state.font.get() != nullptr)
+		state.font->print(this, str, m, state.color);
+}
+
+void Graphics::printf(const std::vector<Font::ColoredString> &str, float wrap, Font::AlignMode align, const Matrix4 &m)
+{
+	checkSetDefaultFont();
+
+	DisplayState &state = states.back();
+
+	if (state.font.get() != nullptr)
+		state.font->printf(this, str, wrap, align, m, state.color);
+}
+
 void Graphics::draw(Drawable *drawable, const Matrix4 &m)
 {
 	drawable->draw(this, m);
@@ -216,7 +668,7 @@ void Graphics::draw(Texture *texture, Quad *quad, const Matrix4 &m)
 }
 
 /**
- * Primitives
+ * Primitives (points, shapes, lines).
  **/
 
 void Graphics::points(const float *coords, const Colorf *colors, size_t numpoints)
@@ -524,6 +976,46 @@ void Graphics::polygon(DrawMode mode, const float *coords, size_t count)
 	}
 }
 
+void Graphics::push(StackType type)
+{
+	if (stackTypeStack.size() == MAX_USER_STACK_DEPTH)
+		throw Exception("Maximum stack depth reached (more pushes than pops?)");
+
+	pushTransform();
+
+	pixelScaleStack.push_back(pixelScaleStack.back());
+
+	if (type == STACK_ALL)
+		states.push_back(states.back());
+
+	stackTypeStack.push_back(type);
+}
+
+void Graphics::pop()
+{
+	if (stackTypeStack.size() < 1)
+		throw Exception("Minimum stack depth reached (more pops than pushes?)");
+
+	popTransform();
+	pixelScaleStack.pop_back();
+
+	if (stackTypeStack.back() == STACK_ALL)
+	{
+		DisplayState &newstate = states[states.size() - 2];
+
+		restoreStateChecked(newstate);
+
+		// The last two states in the stack should be equal now.
+		states.pop_back();
+	}
+	
+	stackTypeStack.pop_back();
+}
+
+/**
+ * Transform and stack functions.
+ **/
+
 const Matrix4 &Graphics::getTransform() const
 {
 	return transformStack.back();
@@ -612,6 +1104,10 @@ Vector Graphics::inverseTransformPoint(Vector point)
 	return p;
 }
 
+/**
+ * Constants.
+ **/
+
 bool Graphics::getConstant(const char *in, DrawMode &out)
 {
 	return drawModes.find(in, out);

+ 302 - 10
src/modules/graphics/Graphics.h

@@ -30,7 +30,12 @@
 #include "vertex.h"
 #include "Color.h"
 #include "Texture.h"
+#include "Canvas.h"
+#include "Font.h"
+#include "Shader.h"
+#include "Quad.h"
 #include "math/Transform.h"
+#include "font/Rasterizer.h"
 
 // C++
 #include <string>
@@ -38,6 +43,9 @@
 
 namespace love
 {
+
+class Reference;
+
 namespace graphics
 {
 
@@ -283,12 +291,43 @@ public:
 		Graphics *gfx;
 	};
 
+	typedef void (*ScreenshotCallback)(love::image::ImageData *i, Reference *ref, void *ud);
+
+	struct ScreenshotInfo
+	{
+		ScreenshotCallback callback;
+		Reference *ref;
+	};
+
 	Graphics();
 	virtual ~Graphics();
 
 	// Implements Module.
 	virtual ModuleType getModuleType() const { return M_GRAPHICS; }
 
+	Quad *newQuad(Quad::Viewport v, double sw, double sh);
+
+	virtual Font *newFont(love::font::Rasterizer *data, const Texture::Filter &filter = Texture::defaultFilter) = 0;
+
+	virtual Canvas *newCanvas(int width, int height, const Canvas::Settings &settings) = 0;
+
+	virtual Shader *newShader(const Shader::ShaderSource &source) = 0;
+
+	/**
+	 * Resets the current color, background color, line style, and so forth.
+	 **/
+	void reset();
+
+	virtual void clear(Colorf color) = 0;
+	virtual void clear(const std::vector<OptionalColorf> &colors) = 0;
+
+	virtual void discard(const std::vector<bool> &colorbuffers, bool depthstencil) = 0;
+
+	/**
+	 * Flips buffers. (Rendered geometry is presented on screen).
+	 **/
+	virtual void present(void *screenshotCallbackData) = 0;
+
 	/**
 	 * Sets the current graphics display viewport dimensions.
 	 **/
@@ -319,25 +358,190 @@ public:
 	 * Normally the module will always be active as long as a window exists, it
 	 * may be different on some platforms (especially mobile ones.)
 	 **/
-	virtual bool isActive() const = 0;
+	bool isActive() const;
 
-	virtual int getWidth() const = 0;
-	virtual int getHeight() const = 0;
+	/**
+	 * True if a graphics viewport is set.
+	 **/
+	bool isCreated() const;
 
-	virtual bool isCanvasActive() const = 0;
+	int getWidth() const;
+	int getHeight() const;
+	int getPixelWidth() const;
+	int getPixelHeight() const;
 
-	virtual void flushStreamDraws() = 0;
-	StreamVertexData requestStreamDraw(const StreamDrawRequest &request);
+	double getCurrentPixelDensity() const;
+	double getScreenPixelDensity() const;
+
+	/**
+	 * Sets the current constant color.
+	 **/
+	virtual void setColor(Colorf c) = 0;
+
+	/**
+	 * Gets current color.
+	 **/
+	Colorf getColor() const;
+
+	/**
+	 * Sets the background Color.
+	 **/
+	void setBackgroundColor(Colorf c);
+
+	/**
+	 * Gets the current background color.
+	 **/
+	Colorf getBackgroundColor() const;
+
+	void setFont(Font *font);
+	Font *getFont();
+
+	void setShader(Shader *shader);
+	void setShader();
+
+	Shader *getShader() const;
+
+	void setCanvas(Canvas *canvas);
+	virtual void setCanvas(const std::vector<Canvas *> &canvases) = 0;
+	void setCanvas(const std::vector<StrongRef<Canvas>> &canvases);
+	virtual void setCanvas() = 0;
+
+	std::vector<Canvas *> getCanvas() const;
+	bool isCanvasActive() const;
+	bool isCanvasActive(Canvas *canvas) const;
+
+	/**
+	 * Scissor defines a box such that everything outside that box is discarded
+	 * and not drawn. Scissoring is automatically enabled.
+	 * @param rect The rectangle defining the scissor area.
+	 **/
+	virtual void setScissor(const Rect &rect) = 0;
+	void intersectScissor(const Rect &rect);
+
+	/**
+	 * Clears any scissor that has been created.
+	 **/
+	virtual void setScissor() = 0;
+
+	/**
+	 * Gets the current scissor box.
+	 * @return Whether the scissor is enabled.
+	 */
+	bool getScissor(Rect &rect) const;
+
+	/**
+	 * Enables or disables drawing to the stencil buffer. When enabled, the
+	 * color buffer is disabled.
+	 **/
+	virtual void drawToStencilBuffer(StencilAction action, int value) = 0;
+	virtual void stopDrawToStencilBuffer() = 0;
+
+	/**
+	 * Sets whether stencil testing is enabled.
+	 **/
+	virtual void setStencilTest(CompareMode compare, int value) = 0;
+	virtual void setStencilTest() = 0;
+	void getStencilTest(CompareMode &compare, int &value);
+
+	/**
+	 * Clear the stencil buffer in the active Canvas(es.)
+	 **/
+	virtual void clearStencil() = 0;
+
+	/**
+	 * Sets the enabled color components when rendering.
+	 **/
+	virtual void setColorMask(ColorMask mask) = 0;
+
+	/**
+	 * Gets the current color mask.
+	 **/
+	ColorMask getColorMask() const;
+
+	/**
+	 * Sets the current blend mode.
+	 **/
+	virtual void setBlendMode(BlendMode mode, BlendAlpha alphamode) = 0;
+
+	/**
+	 * Gets the current blend mode.
+	 **/
+	BlendMode getBlendMode(BlendAlpha &alphamode) const;
+
+	/**
+	 * Sets the default filter for images, canvases, and fonts.
+	 **/
+	void setDefaultFilter(const Texture::Filter &f);
+
+	/**
+	 * Gets the default filter for images, canvases, and fonts.
+	 **/
+	const Texture::Filter &getDefaultFilter() const;
+
+	/**
+	 * Default Image mipmap filter mode and sharpness values.
+	 **/
+	void setDefaultMipmapFilter(Texture::FilterMode filter, float sharpness);
+	void getDefaultMipmapFilter(Texture::FilterMode *filter, float *sharpness) const;
+
+	/**
+	 * Sets the line width.
+	 * @param width The new width of the line.
+	 **/
+	void setLineWidth(float width);
+	float getLineWidth() const;
 
-	virtual Colorf getColor() const = 0;
+	/**
+	 * Sets the line style.
+	 * @param style LINE_ROUGH or LINE_SMOOTH.
+	 **/
+	void setLineStyle(LineStyle style);
+	LineStyle getLineStyle() const;
 
-	virtual float getLineWidth() const = 0;
-	virtual LineStyle getLineStyle() const = 0;
-	virtual LineJoin getLineJoin() const = 0;
+	/**
+	 * Sets the line join mode.
+	 **/
+	void setLineJoin(LineJoin style);
+	LineJoin getLineJoin() const;
+
+	/**
+	 * Sets the size of points.
+	 **/
+	virtual void setPointSize(float size) = 0;
+
+	/**
+	 * Gets the point size.
+	 **/
+	float getPointSize() const;
+
+	/**
+	 * Sets whether graphics will be drawn as wireframe lines instead of filled
+	 * triangles (has no effect for drawn points.)
+	 * This should only be used as a debugging tool. The wireframe lines do not
+	 * behave the same as regular love.graphics lines.
+	 **/
+	virtual void setWireframe(bool enable) = 0;
+
+	/**
+	 * Gets whether wireframe drawing mode is enabled.
+	 **/
+	bool isWireframe() const;
+
+	void captureScreenshot(const ScreenshotInfo &info);
 
 	void draw(Drawable *drawable, const Matrix4 &m);
 	void draw(Texture *texture, Quad *quad, const Matrix4 &m);
 
+	/**
+	 * Draws text at the specified coordinates
+	 **/
+	void print(const std::vector<Font::ColoredString> &str, const Matrix4 &m);
+
+	/**
+	 * Draws formatted text on screen at the specified coordinates.
+	 **/
+	void printf(const std::vector<Font::ColoredString> &str, float wrap, Font::AlignMode align, const Matrix4 &m);
+
 	/**
 	 * Draws a point at (x,y).
 	 * @param x Point along x-axis.
@@ -420,11 +624,31 @@ public:
 	 **/
 	void polygon(DrawMode mode, const float *coords, size_t count);
 
+	/**
+	 * Gets whether a graphics feature is supported on this system.
+	 **/
+	virtual bool isSupported(Feature feature) const = 0;
+
 	/**
 	 * Gets the system-dependent numeric limit for the specified parameter.
 	 **/
 	virtual double getSystemLimit(SystemLimit limittype) const = 0;
 
+	/**
+	 * Returns system-dependent renderer information.
+	 * Returned strings can vary greatly between systems! Do not rely on it for
+	 * anything!
+	 **/
+	virtual RendererInfo getRendererInfo() const = 0;
+
+	/**
+	 * Returns performance-related statistics.
+	 **/
+	virtual Stats getStats() const = 0;
+
+	void push(StackType type = STACK_TRANSFORM);
+	void pop();
+
 	const Matrix4 &getTransform() const;
 	const Matrix4 &getProjection() const;
 
@@ -440,6 +664,9 @@ public:
 	Vector transformPoint(Vector point);
 	Vector inverseTransformPoint(Vector point);
 
+	virtual void flushStreamDraws() = 0;
+	StreamVertexData requestStreamDraw(const StreamDrawRequest &request);
+
 	template <typename T>
 	T *getScratchBuffer(size_t count)
 	{
@@ -484,8 +711,48 @@ public:
 	static bool getConstant(const char *in, StackType &out);
 	static bool getConstant(StackType in, const char *&out);
 
+	// Default shader code (a shader is always required internally.)
+	static Shader::ShaderSource defaultShaderCode[RENDERER_MAX_ENUM][2];
+	static Shader::ShaderSource defaultVideoShaderCode[RENDERER_MAX_ENUM][2];
+
 protected:
 
+	struct DisplayState
+	{
+		Colorf color = Colorf(1.0, 1.0, 1.0, 1.0);
+		Colorf gammaCorrectedColor = Colorf(1.0f, 1.0f, 1.0f, 1.0f);
+		Colorf backgroundColor = Colorf(0.0, 0.0, 0.0, 1.0);
+
+		BlendMode blendMode = BLEND_ALPHA;
+		BlendAlpha blendAlphaMode = BLENDALPHA_MULTIPLY;
+
+		float lineWidth = 1.0f;
+		LineStyle lineStyle = LINE_SMOOTH;
+		LineJoin lineJoin = LINE_JOIN_MITER;
+
+		float pointSize = 1.0f;
+
+		bool scissor = false;
+		Rect scissorRect = Rect();
+
+		CompareMode stencilCompare = COMPARE_ALWAYS;
+		int stencilTestValue = 0;
+
+		StrongRef<Font> font;
+		StrongRef<Shader> shader;
+
+		std::vector<StrongRef<Canvas>> canvases;
+
+		ColorMask colorMask = ColorMask(true, true, true, true);
+
+		bool wireframe = false;
+
+		Texture::Filter defaultFilter = Texture::Filter();
+
+		Texture::FilterMode defaultMipmapFilter = Texture::FILTER_NEAREST;
+		float defaultMipmapSharpness = 0.0f;
+	};
+
 	struct StreamBufferState
 	{
 		StreamBuffer *vb[2];
@@ -498,10 +765,27 @@ protected:
 		int indexCount;
 	};
 
+	void restoreState(const DisplayState &s);
+	void restoreStateChecked(const DisplayState &s);
+
 	void pushTransform();
 	void pushIdentityTransform();
 	void popTransform();
 
+	int width;
+	int height;
+	int pixelWidth;
+	int pixelHeight;
+
+	bool created;
+	bool active;
+
+	bool writingToStencil;
+
+	StrongRef<love::graphics::Font> defaultFont;
+
+	std::vector<ScreenshotInfo> pendingScreenshotCallbacks;
+
 	StreamBufferState streamBufferState;
 
 	std::vector<Matrix4> transformStack;
@@ -509,8 +793,16 @@ protected:
 
 	std::vector<double> pixelScaleStack;
 
+	std::vector<DisplayState> states;
+	std::vector<StackType> stackTypeStack;
+
+	int canvasSwitchCount;
+
+	static const size_t MAX_USER_STACK_DEPTH = 64;
+
 private:
 
+	void checkSetDefaultFont();
 	int calculateEllipsePoints(float rx, float ry) const;
 
 	std::vector<uint8> scratchBuffer;

+ 145 - 0
src/modules/graphics/Shader.cpp

@@ -0,0 +1,145 @@
+/**
+ * Copyright (c) 2006-2016 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 "Shader.h"
+
+namespace love
+{
+namespace graphics
+{
+
+love::Type Shader::type("Shader", &Object::type);
+Shader *Shader::current = nullptr;
+Shader *Shader::defaultShader = nullptr;
+Shader *Shader::defaultVideoShader = nullptr;
+
+Shader::~Shader()
+{
+	if (defaultShader == this)
+		defaultShader = nullptr;
+
+	if (defaultVideoShader == this)
+		defaultVideoShader = nullptr;
+
+	if (current == this)
+		attachDefault();
+}
+
+void Shader::attachDefault()
+{
+	if (defaultShader)
+	{
+		if (current != defaultShader)
+			defaultShader->attach();
+
+		return;
+	}
+
+	current = nullptr;
+}
+
+bool Shader::getConstant(const char *in, ShaderStage &out)
+{
+	return stageNames.find(in, out);
+}
+
+bool Shader::getConstant(ShaderStage in, const char *&out)
+{
+	return stageNames.find(in, out);
+}
+
+bool Shader::getConstant(const char *in, UniformType &out)
+{
+	return uniformTypes.find(in, out);
+}
+
+bool Shader::getConstant(UniformType in, const char *&out)
+{
+	return uniformTypes.find(in, out);
+}
+
+bool Shader::getConstant(const char *in, VertexAttribID &out)
+{
+	return attribNames.find(in, out);
+}
+
+bool Shader::getConstant(VertexAttribID in, const char *&out)
+{
+	return attribNames.find(in, out);
+}
+
+bool Shader::getConstant(const char *in, BuiltinUniform &out)
+{
+	return builtinNames.find(in, out);
+}
+
+bool Shader::getConstant(BuiltinUniform in, const char *&out)
+{
+	return builtinNames.find(in, out);
+}
+
+StringMap<Shader::ShaderStage, Shader::STAGE_MAX_ENUM>::Entry Shader::stageNameEntries[] =
+{
+	{"vertex", Shader::STAGE_VERTEX},
+	{"pixel", Shader::STAGE_PIXEL},
+};
+
+StringMap<Shader::ShaderStage, Shader::STAGE_MAX_ENUM> Shader::stageNames(Shader::stageNameEntries, sizeof(Shader::stageNameEntries));
+
+StringMap<Shader::UniformType, Shader::UNIFORM_MAX_ENUM>::Entry Shader::uniformTypeEntries[] =
+{
+	{"float", Shader::UNIFORM_FLOAT},
+	{"matrix", Shader::UNIFORM_MATRIX},
+	{"int", Shader::UNIFORM_INT},
+	{"bool", Shader::UNIFORM_BOOL},
+	{"image", Shader::UNIFORM_SAMPLER},
+	{"unknown", Shader::UNIFORM_UNKNOWN},
+};
+
+StringMap<Shader::UniformType, Shader::UNIFORM_MAX_ENUM> Shader::uniformTypes(Shader::uniformTypeEntries, sizeof(Shader::uniformTypeEntries));
+
+StringMap<VertexAttribID, ATTRIB_MAX_ENUM>::Entry Shader::attribNameEntries[] =
+{
+	{"VertexPosition", ATTRIB_POS},
+	{"VertexTexCoord", ATTRIB_TEXCOORD},
+	{"VertexColor", ATTRIB_COLOR},
+	{"ConstantColor", ATTRIB_CONSTANTCOLOR},
+};
+
+StringMap<VertexAttribID, ATTRIB_MAX_ENUM> Shader::attribNames(Shader::attribNameEntries, sizeof(Shader::attribNameEntries));
+
+StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM>::Entry Shader::builtinNameEntries[] =
+{
+	{"TransformMatrix", Shader::BUILTIN_TRANSFORM_MATRIX},
+	{"ProjectionMatrix", Shader::BUILTIN_PROJECTION_MATRIX},
+	{"TransformProjectionMatrix", Shader::BUILTIN_TRANSFORM_PROJECTION_MATRIX},
+	{"NormalMatrix", Shader::BUILTIN_NORMAL_MATRIX},
+	{"love_PointSize", Shader::BUILTIN_POINT_SIZE},
+	{"love_ScreenSize", Shader::BUILTIN_SCREEN_SIZE},
+	{"love_VideoYChannel", Shader::BUILTIN_VIDEO_Y_CHANNEL},
+	{"love_VideoCbChannel", Shader::BUILTIN_VIDEO_CB_CHANNEL},
+	{"love_VideoCrChannel", Shader::BUILTIN_VIDEO_CR_CHANNEL},
+};
+
+StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM> Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries));
+
+} // graphics
+} // love

+ 184 - 0
src/modules/graphics/Shader.h

@@ -0,0 +1,184 @@
+/**
+ * Copyright (c) 2006-2016 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.
+ **/
+
+#pragma once
+
+// LOVE
+#include "common/Object.h"
+#include "common/StringMap.h"
+#include "Texture.h"
+
+// STL
+#include <string>
+#include <map>
+#include <vector>
+
+namespace love
+{
+namespace graphics
+{
+
+// A GLSL shader
+class Shader : public Object
+{
+public:
+
+	static love::Type type;
+
+	enum ShaderStage
+	{
+		STAGE_VERTEX,
+		STAGE_PIXEL,
+		STAGE_MAX_ENUM
+	};
+
+	// Built-in uniform variables.
+	enum BuiltinUniform
+	{
+		BUILTIN_TRANSFORM_MATRIX = 0,
+		BUILTIN_PROJECTION_MATRIX,
+		BUILTIN_TRANSFORM_PROJECTION_MATRIX,
+		BUILTIN_NORMAL_MATRIX,
+		BUILTIN_POINT_SIZE,
+		BUILTIN_SCREEN_SIZE,
+		BUILTIN_VIDEO_Y_CHANNEL,
+		BUILTIN_VIDEO_CB_CHANNEL,
+		BUILTIN_VIDEO_CR_CHANNEL,
+		BUILTIN_MAX_ENUM
+	};
+
+	// Types of potential uniform variables used in love's shaders.
+	enum UniformType
+	{
+		UNIFORM_FLOAT,
+		UNIFORM_MATRIX,
+		UNIFORM_INT,
+		UNIFORM_BOOL,
+		UNIFORM_SAMPLER,
+		UNIFORM_UNKNOWN,
+		UNIFORM_MAX_ENUM
+	};
+
+	struct ShaderSource
+	{
+		std::string vertex;
+		std::string pixel;
+	};
+
+	struct MatrixSize
+	{
+		short columns;
+		short rows;
+	};
+
+	struct UniformInfo
+	{
+		int location;
+		int count;
+
+		union
+		{
+			int components;
+			MatrixSize matrix;
+		};
+
+		UniformType baseType;
+		std::string name;
+
+		union
+		{
+			void *data;
+			float *floats;
+			int *ints;
+		};
+
+		Texture **textures;
+	};
+
+	// Pointer to currently active Shader.
+	static Shader *current;
+
+	// Pointer to the default Shader.
+	static Shader *defaultShader;
+	static Shader *defaultVideoShader;
+
+	virtual ~Shader();
+
+	/**
+	 * Binds this Shader's program to be used when rendering.
+	 *
+	 * @param temporary True if we just want to send values to the shader with
+	 * no intention of rendering.
+	 **/
+	virtual void attach(bool temporary = false) = 0;
+
+	/**
+	 * Attach the default shader.
+	 **/
+	static void attachDefault();
+
+	/**
+	 * Returns any warnings this Shader may have generated.
+	 **/
+	virtual std::string getWarnings() const = 0;
+
+	virtual const UniformInfo *getUniformInfo(const std::string &name) const = 0;
+	virtual void updateUniform(const UniformInfo *info, int count, bool internalUpdate = false) = 0;
+
+	virtual void sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalUpdate = false) = 0;
+
+	/**
+	 * Gets whether a uniform with the specified name exists and is actively
+	 * used in the shader.
+	 **/
+	virtual bool hasUniform(const std::string &name) const = 0;
+
+	static bool getConstant(const char *in, ShaderStage &out);
+	static bool getConstant(ShaderStage in, const char *&out);
+
+	static bool getConstant(const char *in, UniformType &out);
+	static bool getConstant(UniformType in, const char *&out);
+
+	static bool getConstant(const char *in, VertexAttribID &out);
+	static bool getConstant(VertexAttribID in, const char *&out);
+
+	static bool getConstant(const char *in, BuiltinUniform &out);
+	static bool getConstant(BuiltinUniform in, const char *&out);
+
+private:
+
+	static StringMap<ShaderStage, STAGE_MAX_ENUM>::Entry stageNameEntries[];
+	static StringMap<ShaderStage, STAGE_MAX_ENUM> stageNames;
+	
+	static StringMap<UniformType, UNIFORM_MAX_ENUM>::Entry uniformTypeEntries[];
+	static StringMap<UniformType, UNIFORM_MAX_ENUM> uniformTypes;
+	
+	// Names for the generic vertex attributes used by love.
+	static StringMap<VertexAttribID, ATTRIB_MAX_ENUM>::Entry attribNameEntries[];
+	static StringMap<VertexAttribID, ATTRIB_MAX_ENUM> attribNames;
+	
+	// Names for the built-in uniform variables.
+	static StringMap<BuiltinUniform, BUILTIN_MAX_ENUM>::Entry builtinNameEntries[];
+	static StringMap<BuiltinUniform, BUILTIN_MAX_ENUM> builtinNames;
+
+}; // Shader
+
+} // graphics
+} // love

+ 4 - 11
src/modules/graphics/Texture.cpp

@@ -27,7 +27,10 @@ namespace graphics
 {
 
 love::Type Texture::type("Texture", &Drawable::type);
+
 Texture::Filter Texture::defaultFilter;
+Texture::FilterMode Texture::defaultMipmapFilter = Texture::FILTER_LINEAR;
+float Texture::defaultMipmapSharpness = 0.0f;
 
 Texture::Texture()
 	: format(PIXELFORMAT_UNKNOWN)
@@ -35,7 +38,7 @@ Texture::Texture()
 	, height(0)
 	, pixelWidth(0)
 	, pixelHeight(0)
-	, filter(getDefaultFilter())
+	, filter(defaultFilter)
 	, wrap()
 	, vertices()
 {
@@ -122,16 +125,6 @@ const Vertex *Texture::getVertices() const
 	return vertices;
 }
 
-void Texture::setDefaultFilter(const Filter &f)
-{
-	defaultFilter = f;
-}
-
-const Texture::Filter &Texture::getDefaultFilter()
-{
-	return defaultFilter;
-}
-
 bool Texture::validateFilter(const Filter &f, bool mipmapsAllowed)
 {
 	if (!mipmapsAllowed && f.mipmap != FILTER_NONE)

+ 4 - 7
src/modules/graphics/Texture.h

@@ -81,6 +81,10 @@ public:
 	Texture();
 	virtual ~Texture();
 
+	static Filter defaultFilter;
+	static FilterMode defaultMipmapFilter;
+	static float defaultMipmapSharpness;
+
 	// Drawable.
 	void draw(Graphics *gfx, const Matrix4 &m) override;
 
@@ -109,10 +113,6 @@ public:
 
 	virtual ptrdiff_t getHandle() const = 0;
 
-	// The default filter.
-	static void setDefaultFilter(const Filter &f);
-	static const Filter &getDefaultFilter();
-
 	static bool validateFilter(const Filter &f, bool mipmapsAllowed);
 
 	static bool getConstant(const char *in, FilterMode &out);
@@ -140,9 +140,6 @@ protected:
 
 private:
 
-	// The default texture filter.
-	static Filter defaultFilter;
-
 	static StringMap<FilterMode, FILTER_MAX_ENUM>::Entry filterModeEntries[];
 	static StringMap<FilterMode, FILTER_MAX_ENUM> filterModes;
 

+ 3 - 27
src/modules/graphics/opengl/Canvas.cpp

@@ -19,8 +19,7 @@
  **/
 
 #include "Canvas.h"
-#include "Image.h"
-#include "Graphics.h"
+#include "graphics/Graphics.h"
 
 #include <algorithm> // For min/max
 
@@ -97,9 +96,6 @@ static bool createMSAABuffer(int width, int height, int &samples, PixelFormat pi
 	return status == GL_FRAMEBUFFER_COMPLETE && samples > 1;
 }
 
-love::Type Canvas::type("Canvas", &Texture::type);
-int Canvas::canvasCount = 0;
-
 Canvas::Canvas(int width, int height, const Settings &settings)
 	: settings(settings)
 	, fbo(0)
@@ -140,13 +136,10 @@ Canvas::Canvas(int width, int height, const Settings &settings)
 	this->format = getSizedFormat(settings.format);
 
 	loadVolatile();
-
-	++canvasCount;
 }
 
 Canvas::~Canvas()
 {
-	--canvasCount;
 	unloadVolatile();
 }
 
@@ -247,16 +240,6 @@ void Canvas::unloadVolatile()
 	texture_memory = 0;
 }
 
-void Canvas::drawv(love::graphics::Graphics *gfx, const Matrix4 &localTransform, const Vertex *v)
-{
-	Graphics *glgfx = (Graphics *) gfx;
-
-	if (glgfx != nullptr && glgfx->isCanvasActive(this))
-		throw love::Exception("Cannot render a Canvas to itself!");
-
-	Texture::drawv(gfx, localTransform, v);
-}
-
 void Canvas::setFilter(const Texture::Filter &f)
 {
 	if (!validateFilter(f, false))
@@ -307,15 +290,8 @@ love::image::ImageData *Canvas::newImageData(love::image::Image *module, int x,
 		throw love::Exception("Invalid rectangle dimensions.");
 
 	Graphics *gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
-
-	if (gfx != nullptr)
-	{
-		for (const auto &c : gfx->getCanvas())
-		{
-			if (c == this)
-				throw love::Exception("Canvas:newImageData cannot be called while that Canvas is currently active.");
-		}
-	}
+	if (gfx != nullptr && gfx->isCanvasActive(this))
+		throw love::Exception("Canvas:newImageData cannot be called while that Canvas is currently active.");
 
 	PixelFormat dataformat;
 	switch (getPixelFormat())

+ 12 - 28
src/modules/graphics/opengl/Canvas.h

@@ -23,12 +23,8 @@
 
 #include "common/config.h"
 #include "graphics/Color.h"
-#include "image/Image.h"
-#include "image/ImageData.h"
-#include "common/Matrix.h"
-#include "common/StringMap.h"
 #include "common/int.h"
-#include "graphics/Texture.h"
+#include "graphics/Canvas.h"
 #include "graphics/Volatile.h"
 #include "OpenGL.h"
 
@@ -39,19 +35,10 @@ namespace graphics
 namespace opengl
 {
 
-class Canvas : public Texture, public Volatile
+class Canvas final : public love::graphics::Canvas, public Volatile
 {
 public:
 
-	static love::Type type;
-
-    struct Settings
-    {
-        PixelFormat format = PIXELFORMAT_NORMAL;
-        float pixeldensity = 1.0f;
-        int msaa = 0;
-    };
-
 	Canvas(int width, int height, const Settings &settings);
 	virtual ~Canvas();
 
@@ -64,28 +51,29 @@ public:
 	bool setWrap(const Texture::Wrap &w) override;
 	ptrdiff_t getHandle() const override;
 
-	love::image::ImageData *newImageData(love::image::Image *module, int x, int y, int w, int h);
-
-	inline GLenum getStatus() const
-	{
-		return status;
-	}
+	love::image::ImageData *newImageData(love::image::Image *module, int x, int y, int w, int h) override;
 
-	inline int getMSAA() const
+	int getMSAA() const override
 	{
 		return actual_samples;
 	}
 
-	inline int getRequestedMSAA() const
+	int getRequestedMSAA() const override
 	{
 		return settings.msaa;
 	}
 
-	inline ptrdiff_t getMSAAHandle() const
+	ptrdiff_t getMSAAHandle() const override
 	{
 		return msaa_buffer;
 	}
 
+
+	inline GLenum getStatus() const
+	{
+		return status;
+	}
+
 	inline GLuint getFBO() const
 	{
 		return fbo;
@@ -96,12 +84,8 @@ public:
 	static bool isMultiFormatMultiCanvasSupported();
 	static bool isFormatSupported(PixelFormat format);
 
-	static int canvasCount;
-
 private:
 
-	void drawv(Graphics *gfx, const Matrix4 &t, const Vertex *v) override;
-
     Settings settings;
 
 	GLuint fbo;

+ 2 - 1
src/modules/graphics/opengl/Font.h

@@ -22,6 +22,7 @@
 
 // LOVE
 #include "graphics/Font.h"
+#include "graphics/Volatile.h"
 #include "OpenGL.h"
 
 namespace love
@@ -31,7 +32,7 @@ namespace graphics
 namespace opengl
 {
 
-class Font : public love::graphics::Font
+class Font final : public love::graphics::Font, public Volatile
 {
 public:
 

+ 8 - 6
src/modules/graphics/opengl/GLBuffer.cpp

@@ -35,7 +35,7 @@ namespace graphics
 namespace opengl
 {
 
-GLBuffer::GLBuffer(size_t size, const void *data, BufferType type, GLenum usage, uint32 mapflags)
+GLBuffer::GLBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags)
 	: is_mapped(false)
 	, size(size)
 	, type(type)
@@ -100,11 +100,13 @@ void GLBuffer::unmapStatic(size_t offset, size_t size)
 
 void GLBuffer::unmapStream()
 {
+	GLenum glusage = OpenGL::getGLBufferUsage(getUsage());
+
 	// "orphan" current buffer to avoid implicit synchronisation on the GPU:
 	// http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-AsynchronousBufferTransfers.pdf
 	gl.bindBuffer(type, vbo);
-	glBufferData(target, (GLsizeiptr) getSize(), nullptr,    getUsage());
-	glBufferData(target, (GLsizeiptr) getSize(), memory_map, getUsage());
+	glBufferData(target, (GLsizeiptr) getSize(), nullptr,    glusage);
+	glBufferData(target, (GLsizeiptr) getSize(), memory_map, glusage);
 }
 
 void GLBuffer::unmap()
@@ -125,7 +127,7 @@ void GLBuffer::unmap()
 
 	if (modified_size > 0)
 	{
-		switch (getUsage())
+		switch (OpenGL::getGLBufferUsage(getUsage()))
 		{
 		case GL_STATIC_DRAW:
 			unmapStatic(modified_offset, modified_size);
@@ -213,7 +215,7 @@ bool GLBuffer::load(bool restore)
 	const GLvoid *src = restore ? memory_map : nullptr;
 
 	// Note that if 'src' is '0', no data will be copied.
-	glBufferData(target, (GLsizeiptr) getSize(), src, getUsage());
+	glBufferData(target, (GLsizeiptr) getSize(), src, OpenGL::getGLBufferUsage(getUsage()));
 
 	return (glGetError() == GL_NO_ERROR);
 }
@@ -260,7 +262,7 @@ QuadIndices::QuadIndices(size_t size)
 		// QuadIndices will propagate the exception and keep the old GLBuffer.
 		try
 		{
-			newbuffer = new GLBuffer(buffersize, nullptr, BUFFER_INDEX, GL_STATIC_DRAW);
+			newbuffer = new GLBuffer(buffersize, nullptr, BUFFER_INDEX, vertex::USAGE_STATIC);
 			newindices = new char[buffersize];
 		}
 		catch (std::bad_alloc &)

+ 5 - 6
src/modules/graphics/opengl/GLBuffer.h

@@ -25,6 +25,7 @@
 // LOVE
 #include "common/config.h"
 #include "graphics/Volatile.h"
+#include "graphics/vertex.h"
 
 // OpenGL
 #include "OpenGL.h"
@@ -57,9 +58,9 @@ public:
 	 *
 	 * @param size The size of the GLBuffer in bytes.
 	 * @param type The type of the buffer object.
-	 * @param usage Usage hint, e.g. GL_DYNAMIC_DRAW.
+	 * @param usage Usage hint.
 	 */
-	GLBuffer(size_t size, const void *data, BufferType type, GLenum usage, uint32 mapflags = 0);
+	GLBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags = 0);
 
 	/**
 	 * Destructor.
@@ -86,10 +87,8 @@ public:
 
 	/**
 	 * Get the usage hint for this GLBuffer.
-	 *
-	 * @return The usage hint, e.g. GL_DYNAMIC_DRAW.
 	 */
-	GLenum getUsage() const
+	vertex::Usage getUsage() const
 	{
 		return usage;
 	}
@@ -214,7 +213,7 @@ private:
 	GLenum target;
 
 	// Usage hint. GL_[DYNAMIC, STATIC, STREAM]_DRAW.
-	GLenum usage;
+	vertex::Usage usage;
 
 	// The VBO identifier. Assigned by OpenGL.
 	GLuint vbo;

+ 73 - 555
src/modules/graphics/opengl/Graphics.cpp

@@ -55,14 +55,6 @@ namespace opengl
 
 Graphics::Graphics()
 	: quadIndices(nullptr)
-	, width(0)
-	, height(0)
-	, pixelWidth(0)
-	, pixelHeight(0)
-	, created(false)
-	, active(true)
-	, writingToStencil(false)
-	, canvasSwitchCount(0)
 {
 	gl = OpenGL();
 
@@ -88,21 +80,6 @@ Graphics::Graphics()
 
 Graphics::~Graphics()
 {
-	// We do this manually so the graphics objects are released before the window.
-	states.clear();
-	defaultFont.set(nullptr);
-
-	if (Shader::defaultShader)
-	{
-		Shader::defaultShader->release();
-		Shader::defaultShader = nullptr;
-	}
-	if (Shader::defaultVideoShader)
-	{
-		Shader::defaultVideoShader->release();
-		Shader::defaultVideoShader = nullptr;
-	}
-
 	if (quadIndices)
 		delete quadIndices;
 }
@@ -112,133 +89,93 @@ const char *Graphics::getName() const
 	return "love.graphics.opengl";
 }
 
-void Graphics::restoreState(const DisplayState &s)
+Image *Graphics::newImage(const std::vector<love::image::ImageData *> &data, const Image::Settings &settings)
 {
-	setColor(s.color);
-	setBackgroundColor(s.backgroundColor);
-
-	setBlendMode(s.blendMode, s.blendAlphaMode);
-
-	setLineWidth(s.lineWidth);
-	setLineStyle(s.lineStyle);
-	setLineJoin(s.lineJoin);
-
-	setPointSize(s.pointSize);
-
-	if (s.scissor)
-		setScissor(s.scissorRect);
-	else
-		setScissor();
-
-	setStencilTest(s.stencilCompare, s.stencilTestValue);
-
-	setFont(s.font.get());
-	setShader(s.shader.get());
-	setCanvas(s.canvases);
-
-	setColorMask(s.colorMask);
-	setWireframe(s.wireframe);
-
-	setDefaultFilter(s.defaultFilter);
-	setDefaultMipmapFilter(s.defaultMipmapFilter, s.defaultMipmapSharpness);
+	return new Image(data, settings);
 }
 
-void Graphics::restoreStateChecked(const DisplayState &s)
+Image *Graphics::newImage(const std::vector<love::image::CompressedImageData *> &cdata, const Image::Settings &settings)
 {
-	const DisplayState &cur = states.back();
-
-	if (s.color != cur.color)
-		setColor(s.color);
-
-	setBackgroundColor(s.backgroundColor);
-
-	if (s.blendMode != cur.blendMode || s.blendAlphaMode != cur.blendAlphaMode)
-		setBlendMode(s.blendMode, s.blendAlphaMode);
-
-	// These are just simple assignments.
-	setLineWidth(s.lineWidth);
-	setLineStyle(s.lineStyle);
-	setLineJoin(s.lineJoin);
+	return new Image(cdata, settings);
+}
 
-	if (s.pointSize != cur.pointSize)
-		setPointSize(s.pointSize);
+graphics::Font *Graphics::newFont(love::font::Rasterizer *r, const Texture::Filter &filter)
+{
+	return new Font(r, filter);
+}
 
-	if (s.scissor != cur.scissor || (s.scissor && !(s.scissorRect == cur.scissorRect)))
-	{
-		if (s.scissor)
-			setScissor(s.scissorRect);
-		else
-			setScissor();
-	}
+SpriteBatch *Graphics::newSpriteBatch(Texture *texture, int size, vertex::Usage usage)
+{
+	return new SpriteBatch(texture, size, usage);
+}
 
-	if (s.stencilCompare != cur.stencilCompare || s.stencilTestValue != cur.stencilTestValue)
-		setStencilTest(s.stencilCompare, s.stencilTestValue);
+ParticleSystem *Graphics::newParticleSystem(Texture *texture, int size)
+{
+	return new ParticleSystem(texture, size);
+}
 
-	setFont(s.font.get());
-	setShader(s.shader.get());
+love::graphics::Canvas *Graphics::newCanvas(int width, int height, const Canvas::Settings &settings)
+{
+	if (!Canvas::isSupported())
+		throw love::Exception("Canvases are not supported by your OpenGL drivers!");
 
-	bool canvaseschanged = s.canvases.size() != cur.canvases.size();
-	if (!canvaseschanged)
+	if (!Canvas::isFormatSupported(settings.format))
 	{
-		for (size_t i = 0; i < s.canvases.size() && i < cur.canvases.size(); i++)
-		{
-			if (s.canvases[i].get() != cur.canvases[i].get())
-			{
-				canvaseschanged = true;
-				break;
-			}
-		}
+		const char *fstr = "rgba8";
+		love::getConstant(Canvas::getSizedFormat(settings.format), fstr);
+		throw love::Exception("The %s canvas format is not supported by your OpenGL drivers.", fstr);
 	}
 
-	if (canvaseschanged)
-		setCanvas(s.canvases);
+	if (width > gl.getMaxTextureSize())
+		throw Exception("Cannot create canvas: width of %d pixels is too large for this system.", width);
+	else if (height > gl.getMaxTextureSize())
+		throw Exception("Cannot create canvas: height of %d pixels is too large for this system.", height);
 
-	if (s.colorMask != cur.colorMask)
-		setColorMask(s.colorMask);
+	Canvas *canvas = new Canvas(width, height, settings);
+	GLenum err = canvas->getStatus();
 
-	if (s.wireframe != cur.wireframe)
-		setWireframe(s.wireframe);
+	// everything ok, return canvas (early out)
+	if (err == GL_FRAMEBUFFER_COMPLETE)
+		return canvas;
 
-	setDefaultFilter(s.defaultFilter);
-	setDefaultMipmapFilter(s.defaultMipmapFilter, s.defaultMipmapSharpness);
+	canvas->release();
+	throw love::Exception("Cannot create Canvas: %s", OpenGL::framebufferStatusString(err));
+	return nullptr; // never reached
 }
 
-void Graphics::checkSetDefaultFont()
+love::graphics::Shader *Graphics::newShader(const Shader::ShaderSource &source)
 {
-	// We don't create or set the default Font if an existing font is in use.
-	if (states.back().font.get() != nullptr)
-		return;
-
-	// Create a new default font if we don't have one yet.
-	if (!defaultFont.get())
-	{
-		auto fontmodule = Module::getInstance<font::Font>(M_FONT);
-		if (!fontmodule)
-			throw love::Exception("Font module has not been loaded.");
+	return new Shader(source);
+}
 
-		auto hinting = font::TrueTypeRasterizer::HINTING_NORMAL;
-		StrongRef<font::Rasterizer> r(fontmodule->newTrueTypeRasterizer(12, hinting), Acquire::NORETAIN);
+Mesh *Graphics::newMesh(const std::vector<Vertex> &vertices, Mesh::DrawMode drawmode, vertex::Usage usage)
+{
+	return new Mesh(vertices, drawmode, usage);
+}
 
-		defaultFont.set(newFont(r.get()), Acquire::NORETAIN);
-	}
+Mesh *Graphics::newMesh(int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage)
+{
+	return new Mesh(vertexcount, drawmode, usage);
+}
 
-	states.back().font.set(defaultFont.get());
+Mesh *Graphics::newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage)
+{
+	return new Mesh(vertexformat, vertexcount, drawmode, usage);
 }
 
-double Graphics::getCurrentPixelDensity() const
+Mesh *Graphics::newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, const void *data, size_t datasize, Mesh::DrawMode drawmode, vertex::Usage usage)
 {
-	if (states.back().canvases.size() > 0)
-	{
-		Canvas *c = states.back().canvases[0];
-		return (double) c->getPixelHeight() / (double) c->getHeight();
-	}
+	return new Mesh(vertexformat, data, datasize, drawmode, usage);
+}
 
-	return getScreenPixelDensity();
+Text *Graphics::newText(graphics::Font *font, const std::vector<Font::ColoredString> &text)
+{
+	return new Text(font, text);
 }
 
-double Graphics::getScreenPixelDensity() const
+Video *Graphics::newVideo(love::video::VideoStream *stream, float pixeldensity)
 {
-	return (double) getPixelHeight() / (double) getHeight();
+	return new Video(stream, pixeldensity);
 }
 
 void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight)
@@ -352,14 +289,14 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight)
 	if (!Shader::defaultShader)
 	{
 		Renderer renderer = GLAD_ES_VERSION_2_0 ? RENDERER_OPENGLES : RENDERER_OPENGL;
-		Shader::defaultShader = newShader(Shader::defaultCode[renderer][gammacorrect]);
+		Shader::defaultShader = newShader(defaultShaderCode[renderer][gammacorrect]);
 	}
 
 	// and a default video shader.
 	if (!Shader::defaultVideoShader)
 	{
 		Renderer renderer = GLAD_ES_VERSION_2_0 ? RENDERER_OPENGLES : RENDERER_OPENGL;
-		Shader::defaultVideoShader = newShader(Shader::defaultVideoCode[renderer][gammacorrect]);
+		Shader::defaultVideoShader = newShader(defaultVideoShaderCode[renderer][gammacorrect]);
 	}
 
 	// A shader should always be active, but the default shader shouldn't be
@@ -407,14 +344,6 @@ void Graphics::setActive(bool enable)
 	active = enable;
 }
 
-bool Graphics::isActive() const
-{
-	// The graphics module is only completely 'active' if there's a window, a
-	// context, and the active variable is set.
-	auto window = getInstance<love::window::Window>(M_WINDOW);
-	return active && isCreated() && window != nullptr && window->isOpen();
-}
-
 void Graphics::flushStreamDraws()
 {
 	using namespace vertex;
@@ -584,24 +513,7 @@ void Graphics::setDebug(bool enable)
 	::printf("OpenGL debug output enabled (LOVE_GRAPHICS_DEBUG=1)\n");
 }
 
-void Graphics::reset()
-{
-	DisplayState s;
-	stopDrawToStencilBuffer();
-	restoreState(s);
-	origin();
-}
-
-void Graphics::setCanvas(Canvas *canvas)
-{
-	if (canvas == nullptr)
-		return setCanvas();
-
-	std::vector<Canvas *> canvases = {canvas};
-	setCanvas(canvases);
-}
-
-void Graphics::setCanvas(const std::vector<Canvas *> &canvases)
+void Graphics::setCanvas(const std::vector<love::graphics::Canvas *> &canvases)
 {
 	DisplayState &state = states.back();
 	int ncanvases = (int) canvases.size();
@@ -629,7 +541,7 @@ void Graphics::setCanvas(const std::vector<Canvas *> &canvases)
 	if (ncanvases > gl.getMaxRenderTargets())
 		throw love::Exception("This system can't simultaneously render to %d canvases.", ncanvases);
 
-	Canvas *firstcanvas = canvases[0];
+	love::graphics::Canvas *firstcanvas = canvases[0];
 
 	bool multiformatsupported = Canvas::isMultiFormatMultiCanvasSupported();
 	PixelFormat firstformat = firstcanvas->getPixelFormat();
@@ -640,7 +552,7 @@ void Graphics::setCanvas(const std::vector<Canvas *> &canvases)
 
 	for (int i = 1; i < ncanvases; i++)
 	{
-		Canvas *c = canvases[i];
+		love::graphics::Canvas *c = canvases[i];
 
 		if (c->getPixelWidth() != pixelwidth || c->getPixelHeight() != pixelheight)
 			throw love::Exception("All canvases in must have the same pixel dimensions.");
@@ -681,10 +593,10 @@ void Graphics::setCanvas(const std::vector<Canvas *> &canvases)
 			gl.setFramebufferSRGB(false);
 	}
 
-	std::vector<StrongRef<Canvas>> canvasrefs;
+	std::vector<StrongRef<love::graphics::Canvas>> canvasrefs;
 	canvasrefs.reserve(canvases.size());
 
-	for (Canvas *c : canvases)
+	for (love::graphics::Canvas *c : canvases)
 		canvasrefs.push_back(c);
 
 	std::swap(state.canvases, canvasrefs);
@@ -692,17 +604,6 @@ void Graphics::setCanvas(const std::vector<Canvas *> &canvases)
 	canvasSwitchCount++;
 }
 
-void Graphics::setCanvas(const std::vector<StrongRef<Canvas>> &canvases)
-{
-	std::vector<Canvas *> canvaslist;
-	canvaslist.reserve(canvases.size());
-
-	for (const StrongRef<Canvas> &c : canvases)
-		canvaslist.push_back(c.get());
-
-	return setCanvas(canvaslist);
-}
-
 void Graphics::setCanvas()
 {
 	DisplayState &state = states.back();
@@ -740,17 +641,6 @@ void Graphics::setCanvas()
 	canvasSwitchCount++;
 }
 
-std::vector<Canvas *> Graphics::getCanvas() const
-{
-	std::vector<Canvas *> canvases;
-	canvases.reserve(states.back().canvases.size());
-
-	for (const StrongRef<Canvas> &c : states.back().canvases)
-		canvases.push_back(c.get());
-
-	return canvases;
-}
-
 void Graphics::endPass()
 {
 	flushStreamDraws();
@@ -768,9 +658,11 @@ void Graphics::endPass()
 
 		for (int i = 0; i < (int) canvases.size(); i++)
 		{
+			Canvas *c = (Canvas *) canvases[i].get();
+
 			glReadBuffer(GL_COLOR_ATTACHMENT0 + i);
 
-			gl.bindFramebuffer(OpenGL::FRAMEBUFFER_DRAW, canvases[i]->getFBO());
+			gl.bindFramebuffer(OpenGL::FRAMEBUFFER_DRAW, c->getFBO());
 
 			if (GLAD_APPLE_framebuffer_multisample)
 				glResolveMultisampleFramebufferAPPLE();
@@ -793,7 +685,7 @@ void Graphics::clear(Colorf c)
 		// This seems to be enough to fix the bug for me. Other methods I've
 		// tried (e.g. dummy draws) don't work in all cases.
 		gl.useProgram(0);
-		gl.useProgram(Shader::current->getProgram());
+		gl.useProgram(((Shader *)Shader::current)->getProgram());
 	}
 }
 
@@ -859,24 +751,8 @@ void Graphics::clear(const std::vector<OptionalColorf> &colors)
 		// This seems to be enough to fix the bug for me. Other methods I've
 		// tried (e.g. dummy draws) don't work in all cases.
 		gl.useProgram(0);
-		gl.useProgram(Shader::current->getProgram());
-	}
-}
-
-bool Graphics::isCanvasActive() const
-{
-	return !states.back().canvases.empty();
-}
-
-bool Graphics::isCanvasActive(Canvas *canvas) const
-{
-	for (const auto &c : states.back().canvases)
-	{
-		if (c.get() == canvas)
-			return true;
+		gl.useProgram(((Shader *)Shader::current)->getProgram());
 	}
-
-	return false;
 }
 
 void Graphics::discard(const std::vector<bool> &colorbuffers, bool depthstencil)
@@ -935,11 +811,11 @@ void Graphics::discard(OpenGL::FramebufferTarget target, const std::vector<bool>
 		glDiscardFramebufferEXT(gltarget, (GLint) attachments.size(), &attachments[0]);
 }
 
-void Graphics::bindCachedFBO(const std::vector<Canvas *> &canvases)
+void Graphics::bindCachedFBO(const std::vector<love::graphics::Canvas *> &canvases)
 {
 	int ncanvases = (int) canvases.size();
 
-	uint32 hash = XXH32(&canvases[0], sizeof(Canvas *) * ncanvases, 0);
+	uint32 hash = XXH32(&canvases[0], sizeof(love::graphics::Canvas *) * ncanvases, 0);
 
 	GLuint fbo = framebufferObjects[hash];
 
@@ -1075,11 +951,6 @@ GLuint Graphics::attachCachedStencilBuffer(int w, int h, int samples)
 	return rb.renderbuffer;
 }
 
-void Graphics::captureScreenshot(const ScreenshotInfo &info)
-{
-	pendingScreenshotCallbacks.push_back(info);
-}
-
 void Graphics::present(void *screenshotCallbackData)
 {
 	if (!isActive())
@@ -1200,31 +1071,6 @@ void Graphics::present(void *screenshotCallbackData)
 	canvasSwitchCount = 0;
 }
 
-int Graphics::getWidth() const
-{
-	return width;
-}
-
-int Graphics::getHeight() const
-{
-	return height;
-}
-
-int Graphics::getPixelWidth() const
-{
-	return pixelWidth;
-}
-
-int Graphics::getPixelHeight() const
-{
-	return pixelHeight;
-}
-
-bool Graphics::isCreated() const
-{
-	return created;
-}
-
 void Graphics::setScissor(const Rect &rect)
 {
 	flushStreamDraws();
@@ -1248,28 +1094,6 @@ void Graphics::setScissor(const Rect &rect)
 	state.scissorRect = rect;
 }
 
-void Graphics::intersectScissor(const Rect &rect)
-{
-	Rect currect = states.back().scissorRect;
-
-	if (!states.back().scissor)
-	{
-		currect.x = 0;
-		currect.y = 0;
-		currect.w = std::numeric_limits<int>::max();
-		currect.h = std::numeric_limits<int>::max();
-	}
-
-	int x1 = std::max(currect.x, rect.x);
-	int y1 = std::max(currect.y, rect.y);
-
-	int x2 = std::min(currect.x + currect.w, rect.x + rect.w);
-	int y2 = std::min(currect.y + currect.h, rect.y + rect.h);
-
-	Rect newrect = {x1, y1, std::max(0, x2 - x1), std::max(0, y2 - y1)};
-	setScissor(newrect);
-}
-
 void Graphics::setScissor()
 {
 	flushStreamDraws();
@@ -1277,13 +1101,6 @@ void Graphics::setScissor()
 	glDisable(GL_SCISSOR_TEST);
 }
 
-bool Graphics::getScissor(Rect &rect) const
-{
-	const DisplayState &state = states.back();
-	rect = state.scissorRect;
-	return state.scissor;
-}
-
 void Graphics::drawToStencilBuffer(StencilAction action, int value)
 {
 	writingToStencil = true;
@@ -1405,117 +1222,11 @@ void Graphics::setStencilTest()
 	setStencilTest(COMPARE_ALWAYS, 0);
 }
 
-void Graphics::getStencilTest(CompareMode &compare, int &value)
-{
-	const DisplayState &state = states.back();
-	compare = state.stencilCompare;
-	value = state.stencilTestValue;
-}
-
 void Graphics::clearStencil()
 {
 	glClear(GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 }
 
-Image *Graphics::newImage(const std::vector<love::image::ImageData *> &data, const Image::Settings &settings)
-{
-	return new Image(data, settings);
-}
-
-Image *Graphics::newImage(const std::vector<love::image::CompressedImageData *> &cdata, const Image::Settings &settings)
-{
-	return new Image(cdata, settings);
-}
-
-Quad *Graphics::newQuad(Quad::Viewport v, double sw, double sh)
-{
-	return new Quad(v, sw, sh);
-}
-
-graphics::Font *Graphics::newFont(love::font::Rasterizer *r, const Texture::Filter &filter)
-{
-	return new Font(r, filter);
-}
-
-SpriteBatch *Graphics::newSpriteBatch(Texture *texture, int size, Mesh::Usage usage)
-{
-	return new SpriteBatch(texture, size, usage);
-}
-
-ParticleSystem *Graphics::newParticleSystem(Texture *texture, int size)
-{
-	return new ParticleSystem(texture, size);
-}
-
-Canvas *Graphics::newCanvas(int width, int height, const Canvas::Settings &settings)
-{
-	if (!Canvas::isSupported())
-		throw love::Exception("Canvases are not supported by your OpenGL drivers!");
-
-	if (!Canvas::isFormatSupported(settings.format))
-	{
-		const char *fstr = "rgba8";
-		love::getConstant(Canvas::getSizedFormat(settings.format), fstr);
-		throw love::Exception("The %s canvas format is not supported by your OpenGL drivers.", fstr);
-	}
-
-	if (width > gl.getMaxTextureSize())
-		throw Exception("Cannot create canvas: width of %d pixels is too large for this system.", width);
-	else if (height > gl.getMaxTextureSize())
-		throw Exception("Cannot create canvas: height of %d pixels is too large for this system.", height);
-
-	Canvas *canvas = new Canvas(width, height, settings);
-	GLenum err = canvas->getStatus();
-
-	// everything ok, return canvas (early out)
-	if (err == GL_FRAMEBUFFER_COMPLETE)
-		return canvas;
-
-	canvas->release();
-	throw love::Exception("Cannot create Canvas: %s", OpenGL::framebufferStatusString(err));
-	return nullptr; // never reached
-}
-
-Shader *Graphics::newShader(const Shader::ShaderSource &source)
-{
-	return new Shader(source);
-}
-
-Mesh *Graphics::newMesh(const std::vector<Vertex> &vertices, Mesh::DrawMode drawmode, Mesh::Usage usage)
-{
-	return new Mesh(vertices, drawmode, usage);
-}
-
-Mesh *Graphics::newMesh(int vertexcount, Mesh::DrawMode drawmode, Mesh::Usage usage)
-{
-	return new Mesh(vertexcount, drawmode, usage);
-}
-
-Mesh *Graphics::newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, int vertexcount, Mesh::DrawMode drawmode, Mesh::Usage usage)
-{
-	return new Mesh(vertexformat, vertexcount, drawmode, usage);
-}
-
-Mesh *Graphics::newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, const void *data, size_t datasize, Mesh::DrawMode drawmode, Mesh::Usage usage)
-{
-	return new Mesh(vertexformat, data, datasize, drawmode, usage);
-}
-
-Text *Graphics::newText(graphics::Font *font, const std::vector<Font::ColoredString> &text)
-{
-	return new Text(font, text);
-}
-
-Video *Graphics::newVideo(love::video::VideoStream *stream, float pixeldensity)
-{
-	return new Video(stream, pixeldensity);
-}
-
-bool Graphics::isGammaCorrect() const
-{
-	return love::graphics::isGammaCorrect();
-}
-
 void Graphics::setColor(Colorf c)
 {
 	c.r = std::min(std::max(c.r, 0.0f), 1.0f);
@@ -1531,66 +1242,6 @@ void Graphics::setColor(Colorf c)
 	states.back().gammaCorrectedColor = nc;
 }
 
-Colorf Graphics::getColor() const
-{
-	return states.back().color;
-}
-
-void Graphics::setBackgroundColor(Colorf c)
-{
-	states.back().backgroundColor = c;
-}
-
-Colorf Graphics::getBackgroundColor() const
-{
-	return states.back().backgroundColor;
-}
-
-void Graphics::setFont(love::graphics::Font *font)
-{
-	// We don't need to set a default font here if null is passed in, since we
-	// only care about the default font in getFont and print.
-	DisplayState &state = states.back();
-	state.font.set(font);
-}
-
-love::graphics::Font *Graphics::getFont()
-{
-	checkSetDefaultFont();
-	return states.back().font.get();
-}
-
-void Graphics::setShader(Shader *shader)
-{
-	if (shader == nullptr)
-		return setShader();
-
-	flushStreamDraws();
-
-	DisplayState &state = states.back();
-
-	shader->attach();
-
-	state.shader.set(shader);
-}
-
-void Graphics::setShader()
-{
-	flushStreamDraws();
-
-	DisplayState &state = states.back();
-
-	// This will activate the default shader.
-	Shader::detach();
-
-	state.shader.set(nullptr);
-}
-
-Shader *Graphics::getShader() const
-{
-	return states.back().shader.get();
-}
-
 void Graphics::setColorMask(ColorMask mask)
 {
 	flushStreamDraws();
@@ -1599,11 +1250,6 @@ void Graphics::setColorMask(ColorMask mask)
 	states.back().colorMask = mask;
 }
 
-Graphics::ColorMask Graphics::getColorMask() const
-{
-	return states.back().colorMask;
-}
-
 void Graphics::setBlendMode(BlendMode mode, BlendAlpha alphamode)
 {
 	flushStreamDraws();
@@ -1682,68 +1328,6 @@ void Graphics::setBlendMode(BlendMode mode, BlendAlpha alphamode)
 	states.back().blendAlphaMode = alphamode;
 }
 
-Graphics::BlendMode Graphics::getBlendMode(BlendAlpha &alphamode) const
-{
-	alphamode = states.back().blendAlphaMode;
-	return states.back().blendMode;
-}
-
-void Graphics::setDefaultFilter(const Texture::Filter &f)
-{
-	Texture::setDefaultFilter(f);
-	states.back().defaultFilter = f;
-}
-
-const Texture::Filter &Graphics::getDefaultFilter() const
-{
-	return Texture::getDefaultFilter();
-}
-
-void Graphics::setDefaultMipmapFilter(Texture::FilterMode filter, float sharpness)
-{
-	Image::setDefaultMipmapFilter(filter);
-	Image::setDefaultMipmapSharpness(sharpness);
-
-	states.back().defaultMipmapFilter = filter;
-	states.back().defaultMipmapSharpness = sharpness;
-}
-
-void Graphics::getDefaultMipmapFilter(Texture::FilterMode *filter, float *sharpness) const
-{
-	*filter = Image::getDefaultMipmapFilter();
-	*sharpness = Image::getDefaultMipmapSharpness();
-}
-
-void Graphics::setLineWidth(float width)
-{
-	states.back().lineWidth = width;
-}
-
-void Graphics::setLineStyle(Graphics::LineStyle style)
-{
-	states.back().lineStyle = style;
-}
-
-void Graphics::setLineJoin(Graphics::LineJoin join)
-{
-	states.back().lineJoin = join;
-}
-
-float Graphics::getLineWidth() const
-{
-	return states.back().lineWidth;
-}
-
-Graphics::LineStyle Graphics::getLineStyle() const
-{
-	return states.back().lineStyle;
-}
-
-Graphics::LineJoin Graphics::getLineJoin() const
-{
-	return states.back().lineJoin;
-}
-
 void Graphics::setPointSize(float size)
 {
 	if (streamBufferState.primitiveMode == vertex::PrimitiveMode::POINTS)
@@ -1753,11 +1337,6 @@ void Graphics::setPointSize(float size)
 	states.back().pointSize = size;
 }
 
-float Graphics::getPointSize() const
-{
-	return states.back().pointSize;
-}
-
 void Graphics::setWireframe(bool enable)
 {
 	// Not supported in OpenGL ES.
@@ -1770,31 +1349,6 @@ void Graphics::setWireframe(bool enable)
 	states.back().wireframe = enable;
 }
 
-bool Graphics::isWireframe() const
-{
-	return states.back().wireframe;
-}
-
-void Graphics::print(const std::vector<Font::ColoredString> &str, const Matrix4 &m)
-{
-	checkSetDefaultFont();
-
-	DisplayState &state = states.back();
-
-	if (state.font.get() != nullptr)
-		state.font->print(this, str, m, state.color);
-}
-
-void Graphics::printf(const std::vector<Font::ColoredString> &str, float wrap, Font::AlignMode align, const Matrix4 &m)
-{
-	checkSetDefaultFont();
-
-	DisplayState &state = states.back();
-
-	if (state.font.get() != nullptr)
-		state.font->printf(this, str, wrap, align, m, state.color);
-}
-
 Graphics::RendererInfo Graphics::getRendererInfo() const
 {
 	RendererInfo info;
@@ -1883,42 +1437,6 @@ bool Graphics::isSupported(Feature feature) const
 	}
 }
 
-void Graphics::push(StackType type)
-{
-	if (stackTypes.size() == MAX_USER_STACK_DEPTH)
-		throw Exception("Maximum stack depth reached (more pushes than pops?)");
-
-	pushTransform();
-
-	pixelScaleStack.push_back(pixelScaleStack.back());
-
-	if (type == STACK_ALL)
-		states.push_back(states.back());
-
-	stackTypes.push_back(type);
-}
-
-void Graphics::pop()
-{
-	if (stackTypes.size() < 1)
-		throw Exception("Minimum stack depth reached (more pops than pushes?)");
-
-	popTransform();
-	pixelScaleStack.pop_back();
-
-	if (stackTypes.back() == STACK_ALL)
-	{
-		DisplayState &newstate = states[states.size() - 2];
-
-		restoreStateChecked(newstate);
-
-		// The last two states in the stack should be equal now.
-		states.pop_back();
-	}
-
-	stackTypes.pop_back();
-}
-
 } // opengl
 } // graphics
 } // love

+ 39 - 310
src/modules/graphics/opengl/Graphics.h

@@ -38,10 +38,7 @@
 
 #include "video/VideoStream.h"
 
-#include "graphics/Font.h"
 #include "Image.h"
-#include "graphics/Quad.h"
-#include "graphics/Texture.h"
 #include "SpriteBatch.h"
 #include "ParticleSystem.h"
 #include "Canvas.h"
@@ -53,8 +50,6 @@
 namespace love
 {
 
-class Reference;
-
 namespace graphics
 {
 namespace opengl
@@ -64,320 +59,80 @@ class Graphics final : public love::graphics::Graphics
 {
 public:
 
-	typedef void (*ScreenshotCallback)(love::image::ImageData *i, Reference *ref, void *ud);
-
-	struct ScreenshotInfo
-	{
-		ScreenshotCallback callback;
-		Reference *ref;
-	};
-
 	Graphics();
 	virtual ~Graphics();
 
 	// Implements Module.
 	const char *getName() const override;
 
-	void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override;
-	bool setMode(int width, int height, int pixelwidth, int pixelheight) override;
-	void unSetMode() override;
-
-	void setActive(bool active) override;
-	bool isActive() const override;
-
-	void flushStreamDraws() override;
-
-	/**
-	 * Resets the current color, background color,
-	 * line style, and so forth. (This will be called
-	 * when the game reloads.
-	 **/
-	void reset();
-
-	void clear(Colorf color);
-	void clear(const std::vector<OptionalColorf> &colors);
-
-	void discard(const std::vector<bool> &colorbuffers, bool depthstencil);
-
-	bool isCanvasActive() const override;
-	bool isCanvasActive(Canvas *canvas) const;
-
-	/**
-	 * Flips buffers. (Rendered geometry is presented on screen).
-	 **/
-	void present(void *screenshotCallbackData);
-
-	int getWidth() const override;
-	int getHeight() const override;
-	int getPixelWidth() const;
-	int getPixelHeight() const;
-
-	double getCurrentPixelDensity() const;
-	double getScreenPixelDensity() const;
-
-	/**
-	 * True if a graphics viewport is set.
-	 **/
-	bool isCreated() const;
-
-	void setCanvas(Canvas *canvas);
-	void setCanvas(const std::vector<Canvas *> &canvases);
-	void setCanvas(const std::vector<StrongRef<Canvas>> &canvases);
-	void setCanvas();
-
-	std::vector<Canvas *> getCanvas() const;
-
-	/**
-	 * Scissor defines a box such that everything outside that box is discarded and not drawn.
-	 * Scissoring is automatically enabled.
-	 * @param rect The rectangle defining the scissor area.
-	 **/
-	void setScissor(const Rect &rect);
-	void intersectScissor(const Rect &rect);
-
-	/**
-	 * Clears any scissor that has been created.
-	 **/
-	void setScissor();
-
-	/**
-	 * Gets the current scissor box.
-	 * @return Whether the scissor is enabled.
-	 */
-	bool getScissor(Rect &rect) const;
-
-	/**
-	 * Enables or disables drawing to the stencil buffer. When enabled, the
-	 * color buffer is disabled.
-	 **/
-	void drawToStencilBuffer(StencilAction action, int value);
-	void stopDrawToStencilBuffer();
-
-	/**
-	 * Sets whether stencil testing is enabled.
-	 **/
-	void setStencilTest(CompareMode compare, int value);
-	void setStencilTest();
-	void getStencilTest(CompareMode &compare, int &value);
-
-	/**
-	 * Clear the stencil buffer in the active Canvas(es.)
-	 **/
-	void clearStencil();
-
-	/**
-	 * Creates an Image object with padding and/or optimization.
-	 **/
 	Image *newImage(const std::vector<love::image::ImageData *> &data, const Image::Settings &settings);
 	Image *newImage(const std::vector<love::image::CompressedImageData *> &cdata, const Image::Settings &settings);
 
-	Quad *newQuad(Quad::Viewport v, double sw, double sh);
-
-	/**
-	 * Creates a Font object.
-	 **/
-	graphics::Font *newFont(love::font::Rasterizer *data, const Texture::Filter &filter = Texture::getDefaultFilter());
+	love::graphics::Font *newFont(love::font::Rasterizer *data, const Texture::Filter &filter = Texture::defaultFilter) override;
 
-	SpriteBatch *newSpriteBatch(Texture *texture, int size, Mesh::Usage usage);
+	SpriteBatch *newSpriteBatch(Texture *texture, int size, vertex::Usage usage);
 
 	ParticleSystem *newParticleSystem(Texture *texture, int size);
 
-	Canvas *newCanvas(int width, int height, const Canvas::Settings &settings);
+	love::graphics::Canvas *newCanvas(int width, int height, const Canvas::Settings &settings) override;
 
-	Shader *newShader(const Shader::ShaderSource &source);
+	love::graphics::Shader *newShader(const Shader::ShaderSource &source) override;
 
-	Mesh *newMesh(const std::vector<Vertex> &vertices, Mesh::DrawMode drawmode, Mesh::Usage usage);
-	Mesh *newMesh(int vertexcount, Mesh::DrawMode drawmode, Mesh::Usage usage);
+	Mesh *newMesh(const std::vector<Vertex> &vertices, Mesh::DrawMode drawmode, vertex::Usage usage);
+	Mesh *newMesh(int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage);
 
-	Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, int vertexcount, Mesh::DrawMode drawmode, Mesh::Usage usage);
-	Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, const void *data, size_t datasize, Mesh::DrawMode drawmode, Mesh::Usage usage);
+	Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage);
+	Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, const void *data, size_t datasize, Mesh::DrawMode drawmode, vertex::Usage usage);
 
-	Text *newText(graphics::Font *font, const std::vector<Font::ColoredString> &text = {});
+	Text *newText(love::graphics::Font *font, const std::vector<Font::ColoredString> &text = {});
 
 	Video *newVideo(love::video::VideoStream *stream, float pixeldensity);
 
-	bool isGammaCorrect() const;
-
-	/**
-	 * Sets the current constant color.
-	 **/
-	void setColor(Colorf c);
-
-	/**
-	 * Gets current color.
-	 **/
-	Colorf getColor() const override;
-
-	/**
-	 * Sets the background Color.
-	 **/
-	void setBackgroundColor(Colorf c);
-
-	/**
-	 * Gets the current background color.
-	 **/
-	Colorf getBackgroundColor() const;
-
-	void setFont(love::graphics::Font *font);
-	love::graphics::Font *getFont();
-
-	void setShader(Shader *shader);
-	void setShader();
-
-	Shader *getShader() const;
-
-	/**
-	 * Sets the enabled color components when rendering.
-	 **/
-	void setColorMask(ColorMask mask);
-
-	/**
-	 * Gets the current color mask.
-	 **/
-	ColorMask getColorMask() const;
-
-	/**
-	 * Sets the current blend mode.
-	 **/
-	void setBlendMode(BlendMode mode, BlendAlpha alphamode);
-
-	/**
-	 * Gets the current blend mode.
-	 **/
-	BlendMode getBlendMode(BlendAlpha &alphamode) const;
-
-	/**
-	 * Sets the default filter for images, canvases, and fonts.
-	 **/
-	void setDefaultFilter(const Texture::Filter &f);
-
-	/**
-	 * Gets the default filter for images, canvases, and fonts.
-	 **/
-	const Texture::Filter &getDefaultFilter() const;
-
-	/**
-	 * Default Image mipmap filter mode and sharpness values.
-	 **/
-	void setDefaultMipmapFilter(Texture::FilterMode filter, float sharpness);
-	void getDefaultMipmapFilter(Texture::FilterMode *filter, float *sharpness) const;
-
-	/**
-	 * Sets the line width.
-	 * @param width The new width of the line.
-	 **/
-	void setLineWidth(float width);
-
-	/**
-	 * Sets the line style.
-	 * @param style LINE_ROUGH or LINE_SMOOTH.
-	 **/
-	void setLineStyle(LineStyle style);
-
-	/**
-	 * Sets the line join mode.
-	 **/
-	void setLineJoin(LineJoin style);
-
-	float getLineWidth() const override;
-	LineStyle getLineStyle() const override;
-	LineJoin getLineJoin() const override;
-
-	/**
-	 * Sets the size of points.
-	 **/
-	void setPointSize(float size);
-
-	/**
-	 * Gets the point size.
-	 **/
-	float getPointSize() const;
-
-	/**
-	 * Sets whether graphics will be drawn as wireframe lines instead of filled
-	 * triangles (has no effect for drawn points.)
-	 * This should only be used as a debugging tool. The wireframe lines do not
-	 * behave the same as regular love.graphics lines.
-	 **/
-	void setWireframe(bool enable);
-
-	/**
-	 * Gets whether wireframe drawing mode is enabled.
-	 **/
-	bool isWireframe() const;
-
-	/**
-	 * Draws text at the specified coordinates
-	 **/
-	void print(const std::vector<Font::ColoredString> &str, const Matrix4 &m);
-
-	/**
-	 * Draws formatted text on screen at the specified coordinates.
-	 **/
-	void printf(const std::vector<Font::ColoredString> &str, float wrap, Font::AlignMode align, const Matrix4 &m);
-
-	void captureScreenshot(const ScreenshotInfo &info);
-
-	/**
-	 * Returns system-dependent renderer information.
-	 * Returned strings can vary greatly between systems! Do not rely on it for
-	 * anything!
-	 **/
-	RendererInfo getRendererInfo() const;
-
-	/**
-	 * Returns performance-related statistics.
-	 **/
-	Stats getStats() const;
+	void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override;
+	bool setMode(int width, int height, int pixelwidth, int pixelheight) override;
+	void unSetMode() override;
 
-	double getSystemLimit(SystemLimit limittype) const override;
+	void setActive(bool active) override;
 
-	/**
-	 * Gets whether a graphics feature is supported on this system.
-	 **/
-	bool isSupported(Feature feature) const;
+	void flushStreamDraws() override;
 
-	void push(StackType type = STACK_TRANSFORM);
-	void pop();
+	void clear(Colorf color) override;
+	void clear(const std::vector<OptionalColorf> &colors) override;
 
-private:
+	void discard(const std::vector<bool> &colorbuffers, bool depthstencil) override;
 
-	struct DisplayState
-	{
-		Colorf color = Colorf(1.0, 1.0, 1.0, 1.0);
-		Colorf gammaCorrectedColor = Colorf(1.0f, 1.0f, 1.0f, 1.0f);
-		Colorf backgroundColor = Colorf(0.0, 0.0, 0.0, 1.0);
+	void present(void *screenshotCallbackData) override;
 
-		BlendMode blendMode = BLEND_ALPHA;
-		BlendAlpha blendAlphaMode = BLENDALPHA_MULTIPLY;
+	void setColor(Colorf c) override;
 
-		float lineWidth = 1.0f;
-		LineStyle lineStyle = LINE_SMOOTH;
-		LineJoin lineJoin = LINE_JOIN_MITER;
+	void setCanvas(const std::vector<love::graphics::Canvas *> &canvases) override;
+	void setCanvas() override;
 
-		float pointSize = 1.0f;
+	void setScissor(const Rect &rect) override;
+	void setScissor() override;
 
-		bool scissor = false;
-		Rect scissorRect = Rect();
+	void drawToStencilBuffer(StencilAction action, int value) override;
+	void stopDrawToStencilBuffer() override;
 
-		// Stencil.
-		CompareMode stencilCompare = COMPARE_ALWAYS;
-		int stencilTestValue = 0;
+	void setStencilTest(CompareMode compare, int value) override;
+	void setStencilTest() override;
 
-		StrongRef<love::graphics::Font> font;
-		StrongRef<Shader> shader;
+	void clearStencil() override;
 
-		std::vector<StrongRef<Canvas>> canvases;
+	void setColorMask(ColorMask mask) override;
 
-		ColorMask colorMask = ColorMask(true, true, true, true);
+	void setBlendMode(BlendMode mode, BlendAlpha alphamode) override;
 
-		bool wireframe = false;
+	void setPointSize(float size) override;
 
-		Texture::Filter defaultFilter = Texture::Filter();
+	void setWireframe(bool enable) override;
 
-		Texture::FilterMode defaultMipmapFilter = Texture::FILTER_NEAREST;
-		float defaultMipmapSharpness = 0.0f;
-	};
+	bool isSupported(Feature feature) const override;
+	double getSystemLimit(SystemLimit limittype) const override;
+	RendererInfo getRendererInfo() const override;
+	Stats getStats() const override;
+
+private:
 
 	struct CachedRenderbuffer
 	{
@@ -388,44 +143,18 @@ private:
 		GLuint renderbuffer;
 	};
 
-	void restoreState(const DisplayState &s);
-	void restoreStateChecked(const DisplayState &s);
-
 	void endPass();
-	void bindCachedFBO(const std::vector<Canvas *> &canvases);
+	void bindCachedFBO(const std::vector<love::graphics::Canvas *> &canvases);
 	void discard(OpenGL::FramebufferTarget target, const std::vector<bool> &colorbuffers, bool depthstencil);
 	GLuint attachCachedStencilBuffer(int w, int h, int samples);
 
 	void setDebug(bool enable);
 
-	void checkSetDefaultFont();
-
-	StrongRef<love::graphics::Font> defaultFont;
-
-	std::vector<ScreenshotInfo> pendingScreenshotCallbacks;
-
 	std::unordered_map<uint32, GLuint> framebufferObjects;
 	std::vector<CachedRenderbuffer> stencilBuffers;
 
 	QuadIndices *quadIndices;
 
-	int width;
-	int height;
-	int pixelWidth;
-	int pixelHeight;
-
-	bool created;
-	bool active;
-
-	bool writingToStencil;
-
-	std::vector<DisplayState> states;
-	std::vector<StackType> stackTypes; // Keeps track of the pushed stack types.
-
-	int canvasSwitchCount;
-
-	static const size_t MAX_USER_STACK_DEPTH = 64;
-
 }; // Graphics
 
 } // opengl

+ 0 - 23
src/modules/graphics/opengl/Image.cpp

@@ -49,9 +49,6 @@ int Image::imageCount = 0;
 
 float Image::maxMipmapSharpness = 0.0f;
 
-Texture::FilterMode Image::defaultMipmapFilter = Texture::FILTER_LINEAR;
-float Image::defaultMipmapSharpness = 0.0f;
-
 static int getMipmapCount(int basewidth, int baseheight)
 {
 	return (int) log2(std::max(basewidth, baseheight)) + 1;
@@ -553,26 +550,6 @@ const Image::Settings &Image::getFlags() const
 	return settings;
 }
 
-void Image::setDefaultMipmapSharpness(float sharpness)
-{
-	defaultMipmapSharpness = sharpness;
-}
-
-float Image::getDefaultMipmapSharpness()
-{
-	return defaultMipmapSharpness;
-}
-
-void Image::setDefaultMipmapFilter(Texture::FilterMode f)
-{
-	defaultMipmapFilter = f;
-}
-
-Texture::FilterMode Image::getDefaultMipmapFilter()
-{
-	return defaultMipmapFilter;
-}
-
 bool Image::isCompressed() const
 {
 	return compressed;

+ 0 - 8
src/modules/graphics/opengl/Image.h

@@ -116,11 +116,6 @@ public:
 
 	const Settings &getFlags() const;
 
-	static void setDefaultMipmapSharpness(float sharpness);
-	static float getDefaultMipmapSharpness();
-	static void setDefaultMipmapFilter(FilterMode f);
-	static FilterMode getDefaultMipmapFilter();
-
 	static bool isFormatSupported(PixelFormat pixelformat);
 	static bool hasSRGBSupport();
 
@@ -169,9 +164,6 @@ private:
 
 	static float maxMipmapSharpness;
 
-	static FilterMode defaultMipmapFilter;
-	static float defaultMipmapSharpness;
-
 	static StringMap<SettingType, SETTING_MAX_ENUM>::Entry settingTypeEntries[];
 	static StringMap<SettingType, SETTING_MAX_ENUM> settingTypes;
 

+ 7 - 41
src/modules/graphics/opengl/Mesh.cpp

@@ -61,7 +61,7 @@ static std::vector<Mesh::AttribFormat> getDefaultVertexFormat()
 
 love::Type Mesh::type("Mesh", &Drawable::type);
 
-Mesh::Mesh(const std::vector<AttribFormat> &vertexformat, const void *data, size_t datasize, DrawMode drawmode, Usage usage)
+Mesh::Mesh(const std::vector<AttribFormat> &vertexformat, const void *data, size_t datasize, DrawMode drawmode, vertex::Usage usage)
 	: vertexFormat(vertexformat)
 	, vbo(nullptr)
 	, vertexCount(0)
@@ -83,12 +83,12 @@ Mesh::Mesh(const std::vector<AttribFormat> &vertexformat, const void *data, size
 	if (vertexCount == 0)
 		throw love::Exception("Data size is too small for specified vertex attribute formats.");
 
-	vbo = new GLBuffer(datasize, data, BUFFER_VERTEX, getGLBufferUsage(usage), GLBuffer::MAP_EXPLICIT_RANGE_MODIFY);
+	vbo = new GLBuffer(datasize, data, BUFFER_VERTEX, usage, GLBuffer::MAP_EXPLICIT_RANGE_MODIFY);
 
 	vertexScratchBuffer = new char[vertexStride];
 }
 
-Mesh::Mesh(const std::vector<AttribFormat> &vertexformat, int vertexcount, DrawMode drawmode, Usage usage)
+Mesh::Mesh(const std::vector<AttribFormat> &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage)
 	: vertexFormat(vertexformat)
 	, vbo(nullptr)
 	, vertexCount((size_t) vertexcount)
@@ -109,7 +109,7 @@ Mesh::Mesh(const std::vector<AttribFormat> &vertexformat, int vertexcount, DrawM
 
 	size_t buffersize = vertexCount * vertexStride;
 
-	vbo = new GLBuffer(buffersize, nullptr, BUFFER_VERTEX, getGLBufferUsage(usage), GLBuffer::MAP_EXPLICIT_RANGE_MODIFY);
+	vbo = new GLBuffer(buffersize, nullptr, BUFFER_VERTEX, usage, GLBuffer::MAP_EXPLICIT_RANGE_MODIFY);
 
 	// Initialize the buffer's contents to 0.
 	memset(vbo->map(), 0, buffersize);
@@ -119,12 +119,12 @@ Mesh::Mesh(const std::vector<AttribFormat> &vertexformat, int vertexcount, DrawM
 	vertexScratchBuffer = new char[vertexStride];
 }
 
-Mesh::Mesh(const std::vector<Vertex> &vertices, DrawMode drawmode, Usage usage)
+Mesh::Mesh(const std::vector<Vertex> &vertices, DrawMode drawmode, vertex::Usage usage)
 	: Mesh(getDefaultVertexFormat(), &vertices[0], vertices.size() * sizeof(Vertex), drawmode, usage)
 {
 }
 
-Mesh::Mesh(int vertexcount, DrawMode drawmode, Usage usage)
+Mesh::Mesh(int vertexcount, DrawMode drawmode, vertex::Usage usage)
 	: Mesh(getDefaultVertexFormat(), vertexcount, drawmode, usage)
 {
 }
@@ -554,7 +554,7 @@ int Mesh::bindAttributeToShaderInput(int attributeindex, const std::string &inpu
 	if (Shader::getConstant(inputname.c_str(), builtinattrib))
 		attriblocation = (GLint) builtinattrib;
 	else if (Shader::current)
-		attriblocation = Shader::current->getAttribLocation(inputname);
+		attriblocation = ((Shader *) Shader::current)->getAttribLocation(inputname);
 
 	// The active shader might not use this vertex attribute name.
 	if (attriblocation < 0)
@@ -713,31 +713,6 @@ size_t Mesh::getGLDataTypeSize(GLenum datatype)
 	}
 }
 
-GLenum Mesh::getGLBufferUsage(Usage usage)
-{
-	switch (usage)
-	{
-	case USAGE_STREAM:
-		return GL_STREAM_DRAW;
-	case USAGE_DYNAMIC:
-		return GL_DYNAMIC_DRAW;
-	case USAGE_STATIC:
-		return GL_STATIC_DRAW;
-	default:
-		return 0;
-	}
-}
-
-bool Mesh::getConstant(const char *in, Usage &out)
-{
-	return usages.find(in, out);
-}
-
-bool Mesh::getConstant(Usage in, const char *&out)
-{
-	return usages.find(in, out);
-}
-
 bool Mesh::getConstant(const char *in, Mesh::DrawMode &out)
 {
 	return drawModes.find(in, out);
@@ -758,15 +733,6 @@ bool Mesh::getConstant(DataType in, const char *&out)
 	return dataTypes.find(in, out);
 }
 
-StringMap<Mesh::Usage, Mesh::USAGE_MAX_ENUM>::Entry Mesh::usageEntries[] =
-{
-	{"stream", USAGE_STREAM},
-	{"dynamic", USAGE_DYNAMIC},
-	{"static", USAGE_STATIC},
-};
-
-StringMap<Mesh::Usage, Mesh::USAGE_MAX_ENUM> Mesh::usages(Mesh::usageEntries, sizeof(Mesh::usageEntries));
-
 StringMap<Mesh::DrawMode, Mesh::DRAWMODE_MAX_ENUM>::Entry Mesh::drawModeEntries[] =
 {
 	{"fan", DRAWMODE_FAN},

+ 5 - 21
src/modules/graphics/opengl/Mesh.h

@@ -28,6 +28,7 @@
 #include "common/StringMap.h"
 #include "graphics/Drawable.h"
 #include "graphics/Texture.h"
+#include "graphics/vertex.h"
 #include "GLBuffer.h"
 
 // C++
@@ -52,15 +53,6 @@ public:
 
 	static love::Type type;
 
-	// The expected usage pattern of the Mesh's vertex data.
-	enum Usage
-	{
-		USAGE_STREAM,
-		USAGE_DYNAMIC,
-		USAGE_STATIC,
-		USAGE_MAX_ENUM
-	};
-
 	// How the Mesh's vertices are used when drawing.
 	// http://escience.anu.edu.au/lecture/cg/surfaceModeling/image/surfaceModeling015.png
 	enum DrawMode
@@ -87,11 +79,11 @@ public:
 		int components; // max 4
 	};
 
-	Mesh(const std::vector<AttribFormat> &vertexformat, const void *data, size_t datasize, DrawMode drawmode, Usage usage);
-	Mesh(const std::vector<AttribFormat> &vertexformat, int vertexcount, DrawMode drawmode, Usage usage);
+	Mesh(const std::vector<AttribFormat> &vertexformat, const void *data, size_t datasize, DrawMode drawmode, vertex::Usage usage);
+	Mesh(const std::vector<AttribFormat> &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage);
 
-	Mesh(const std::vector<Vertex> &vertices, DrawMode drawmode, Usage usage);
-	Mesh(int vertexcount, DrawMode drawmode, Usage usage);
+	Mesh(const std::vector<Vertex> &vertices, DrawMode drawmode, vertex::Usage usage);
+	Mesh(int vertexcount, DrawMode drawmode, vertex::Usage usage);
 
 	virtual ~Mesh();
 
@@ -202,11 +194,6 @@ public:
 	// Implements Drawable.
 	void draw(Graphics *gfx, const Matrix4 &m) override;
 
-	static GLenum getGLBufferUsage(Usage usage);
-
-	static bool getConstant(const char *in, Usage &out);
-	static bool getConstant(Usage in, const char *&out);
-
 	static bool getConstant(const char *in, DrawMode &out);
 	static bool getConstant(DrawMode in, const char *&out);
 
@@ -260,9 +247,6 @@ private:
 
 	StrongRef<Texture> texture;
 
-	static StringMap<Usage, USAGE_MAX_ENUM>::Entry usageEntries[];
-	static StringMap<Usage, USAGE_MAX_ENUM> usages;
-
 	static StringMap<DrawMode, DRAWMODE_MAX_ENUM>::Entry drawModeEntries[];
 	static StringMap<DrawMode, DRAWMODE_MAX_ENUM> drawModes;
 

+ 16 - 1
src/modules/graphics/opengl/OpenGL.cpp

@@ -336,7 +336,7 @@ void OpenGL::prepareDraw()
 
 	// Make sure the active shader's love-provided uniforms are up to date.
 	if (Shader::current != nullptr)
-		Shader::current->checkSetBuiltinUniforms();
+		((Shader *)Shader::current)->checkSetBuiltinUniforms();
 }
 
 GLenum OpenGL::getGLBufferType(BufferType type)
@@ -352,6 +352,21 @@ GLenum OpenGL::getGLBufferType(BufferType type)
 	}
 }
 
+GLenum OpenGL::getGLBufferUsage(vertex::Usage usage)
+{
+	switch (usage)
+	{
+	case vertex::USAGE_STREAM:
+		return GL_STREAM_DRAW;
+	case vertex::USAGE_DYNAMIC:
+		return GL_DYNAMIC_DRAW;
+	case vertex::USAGE_STATIC:
+		return GL_STATIC_DRAW;
+	default:
+		return 0;
+	}
+}
+
 void OpenGL::bindBuffer(BufferType type, GLuint buffer)
 {
 	if (state.boundBuffers[type] != buffer)

+ 1 - 19
src/modules/graphics/opengl/OpenGL.h

@@ -52,25 +52,6 @@ namespace opengl
 // no clashes with other GL libraries when linking, etc.
 using namespace glad;
 
-// Vertex attribute indices used in shaders by LOVE. The values map to OpenGL
-// generic vertex attribute indices.
-enum VertexAttribID
-{
-	ATTRIB_POS = 0,
-	ATTRIB_TEXCOORD,
-	ATTRIB_COLOR,
-	ATTRIB_CONSTANTCOLOR,
-	ATTRIB_MAX_ENUM
-};
-
-enum VertexAttribFlags
-{
-	ATTRIBFLAG_POS = 1 << ATTRIB_POS,
-	ATTRIBFLAG_TEXCOORD = 1 << ATTRIB_TEXCOORD,
-	ATTRIBFLAG_COLOR = 1 << ATTRIB_COLOR,
-	ATTRIBFLAG_CONSTANTCOLOR = 1 << ATTRIB_CONSTANTCOLOR
-};
-
 /**
  * Thin layer between OpenGL and the rest of the program.
  * Internally shadows some OpenGL context state for improved efficiency and
@@ -377,6 +358,7 @@ public:
 	Vendor getVendor() const;
 
 	static GLenum getGLBufferType(BufferType type);
+	static GLenum getGLBufferUsage(vertex::Usage usage);
 	static GLint getGLWrapMode(Texture::WrapMode wmode);
 
 	static TextureFormat convertPixelFormat(PixelFormat pixelformat, bool renderbuffer, bool &isSRGB);

+ 14 - 112
src/modules/graphics/opengl/Shader.cpp

@@ -42,7 +42,7 @@ namespace
 	// reattaches the originally active program when destroyed
 	struct TemporaryAttacher
 	{
-		TemporaryAttacher(Shader *shader, bool attachNow)
+		TemporaryAttacher(graphics::Shader *shader, bool attachNow)
 		: curShader(shader)
 		, prevShader(Shader::current)
 		{
@@ -55,7 +55,7 @@ namespace
 			if (prevShader != nullptr)
 				prevShader->attach();
 			else
-				curShader->detach();
+				Shader::attachDefault();
 		}
 
 		void attach()
@@ -63,20 +63,11 @@ namespace
 			curShader->attach(true);
 		}
 
-		Shader *curShader;
-		Shader *prevShader;
+		graphics::Shader *curShader;
+		graphics::Shader *prevShader;
 	};
 } // anonymous namespace
 
-
-love::Type Shader::type("Shader", &Object::type);
-Shader *Shader::current = nullptr;
-Shader *Shader::defaultShader = nullptr;
-Shader *Shader::defaultVideoShader = nullptr;
-
-Shader::ShaderSource Shader::defaultCode[Graphics::RENDERER_MAX_ENUM][2];
-Shader::ShaderSource Shader::defaultVideoCode[Graphics::RENDERER_MAX_ENUM][2];
-
 Shader::Shader(const ShaderSource &source)
 	: shaderSource(source)
 	, program(0)
@@ -96,9 +87,6 @@ Shader::Shader(const ShaderSource &source)
 
 Shader::~Shader()
 {
-	if (current == this)
-		detach();
-
 	unloadVolatile();
 
 	for (const auto &p : uniforms)
@@ -125,7 +113,7 @@ GLuint Shader::compileCode(ShaderStage stage, const std::string &code)
 	GLenum glstage;
 	const char *typestr;
 
-	if (!stageNames.find(stage, typestr))
+	if (!getConstant(stage, typestr))
 		typestr = "";
 
 	switch (stage)
@@ -232,7 +220,7 @@ void Shader::mapActiveUniforms()
 
 		// If this is a built-in (LOVE-created) uniform, store the location.
 		BuiltinUniform builtin;
-		if (builtinNames.find(u.name.c_str(), builtin))
+		if (getConstant(u.name.c_str(), builtin))
 			builtinUniforms[int(builtin)] = u.location;
 
 		if (u.location == -1)
@@ -397,9 +385,9 @@ bool Shader::loadVolatile()
 	std::vector<GLuint> shaderids;
 
 	bool gammacorrect = graphics::isGammaCorrect();
-	const ShaderSource *defaults = &defaultCode[Graphics::RENDERER_OPENGL][gammacorrect ? 1 : 0];
+	const ShaderSource *defaults = &Graphics::defaultShaderCode[Graphics::RENDERER_OPENGL][gammacorrect ? 1 : 0];
 	if (GLAD_ES_VERSION_2_0)
-		defaults = &defaultCode[Graphics::RENDERER_OPENGLES][gammacorrect ? 1 : 0];
+		defaults = &Graphics::defaultShaderCode[Graphics::RENDERER_OPENGLES][gammacorrect ? 1 : 0];
 
 	// The shader program must have both vertex and pixel shader stages.
 	const std::string &vertexcode = shaderSource.vertex.empty() ? defaults->vertex : shaderSource.vertex;
@@ -433,7 +421,7 @@ bool Shader::loadVolatile()
 	for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
 	{
 		const char *name = nullptr;
-		if (attribNames.find((VertexAttribID) i, name))
+		if (getConstant((VertexAttribID) i, name))
 			glBindAttribLocation(program, i, (const GLchar *) name);
 	}
 
@@ -460,7 +448,7 @@ bool Shader::loadVolatile()
 	for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
 	{
 		const char *name = nullptr;
-		if (attribNames.find(VertexAttribID(i), name))
+		if (getConstant(VertexAttribID(i), name))
 			builtinAttributes[i] = glGetAttribLocation(program, name);
 		else
 			builtinAttributes[i] = -1;
@@ -529,7 +517,7 @@ std::string Shader::getWarnings() const
 	// Get the individual shader stage warnings
 	for (const auto &warning : shaderWarnings)
 	{
-		if (stageNames.find(warning.first, stagestr))
+		if (getConstant(warning.first, stagestr))
 			warnings += std::string(stagestr) + std::string(" shader:\n") + warning.second;
 	}
 
@@ -565,22 +553,6 @@ void Shader::attach(bool temporary)
 	}
 }
 
-void Shader::detach()
-{
-	if (defaultShader)
-	{
-		if (current != defaultShader)
-			defaultShader->attach();
-
-		return;
-	}
-
-	if (current != nullptr)
-		gl.useProgram(0);
-
-	current = nullptr;
-}
-
 const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const
 {
 	const auto it = uniforms.find(name);
@@ -777,11 +749,6 @@ GLint Shader::getAttribLocation(const std::string &name)
 	return location;
 }
 
-bool Shader::hasVertexAttrib(VertexAttribID attrib) const
-{
-	return builtinAttributes[int(attrib)] != -1;
-}
-
 void Shader::setVideoTextures(GLuint ytexture, GLuint cbtexture, GLuint crtexture)
 {
 	// Set up the texture units that will be used by the shader to sample from
@@ -797,9 +764,9 @@ void Shader::setVideoTextures(GLuint ytexture, GLuint cbtexture, GLuint crtextur
 		};
 
 		const char *names[3] = {nullptr, nullptr, nullptr};
-		builtinNames.find(BUILTIN_VIDEO_Y_CHANNEL,  names[0]);
-		builtinNames.find(BUILTIN_VIDEO_CB_CHANNEL, names[1]);
-		builtinNames.find(BUILTIN_VIDEO_CR_CHANNEL, names[2]);
+		getConstant(BUILTIN_VIDEO_Y_CHANNEL,  names[0]);
+		getConstant(BUILTIN_VIDEO_CB_CHANNEL, names[1]);
+		getConstant(BUILTIN_VIDEO_CR_CHANNEL, names[2]);
 
 		for (int i = 0; i < 3; i++)
 		{
@@ -1093,71 +1060,6 @@ Shader::UniformType Shader::getUniformBaseType(GLenum type) const
 	}
 }
 
-bool Shader::getConstant(const char *in, UniformType &out)
-{
-	return uniformTypes.find(in, out);
-}
-
-bool Shader::getConstant(UniformType in, const char *&out)
-{
-	return uniformTypes.find(in, out);
-}
-
-bool Shader::getConstant(const char *in, VertexAttribID &out)
-{
-	return attribNames.find(in, out);
-}
-
-bool Shader::getConstant(VertexAttribID in, const char *&out)
-{
-	return attribNames.find(in, out);
-}
-
-StringMap<Shader::ShaderStage, Shader::STAGE_MAX_ENUM>::Entry Shader::stageNameEntries[] =
-{
-	{"vertex", Shader::STAGE_VERTEX},
-	{"pixel", Shader::STAGE_PIXEL},
-};
-
-StringMap<Shader::ShaderStage, Shader::STAGE_MAX_ENUM> Shader::stageNames(Shader::stageNameEntries, sizeof(Shader::stageNameEntries));
-
-StringMap<Shader::UniformType, Shader::UNIFORM_MAX_ENUM>::Entry Shader::uniformTypeEntries[] =
-{
-	{"float", Shader::UNIFORM_FLOAT},
-	{"matrix", Shader::UNIFORM_MATRIX},
-	{"int", Shader::UNIFORM_INT},
-	{"bool", Shader::UNIFORM_BOOL},
-	{"image", Shader::UNIFORM_SAMPLER},
-	{"unknown", Shader::UNIFORM_UNKNOWN},
-};
-
-StringMap<Shader::UniformType, Shader::UNIFORM_MAX_ENUM> Shader::uniformTypes(Shader::uniformTypeEntries, sizeof(Shader::uniformTypeEntries));
-
-StringMap<VertexAttribID, ATTRIB_MAX_ENUM>::Entry Shader::attribNameEntries[] =
-{
-	{"VertexPosition", ATTRIB_POS},
-	{"VertexTexCoord", ATTRIB_TEXCOORD},
-	{"VertexColor", ATTRIB_COLOR},
-	{"ConstantColor", ATTRIB_CONSTANTCOLOR},
-};
-
-StringMap<VertexAttribID, ATTRIB_MAX_ENUM> Shader::attribNames(Shader::attribNameEntries, sizeof(Shader::attribNameEntries));
-
-StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM>::Entry Shader::builtinNameEntries[] =
-{
-	{"TransformMatrix", Shader::BUILTIN_TRANSFORM_MATRIX},
-	{"ProjectionMatrix", Shader::BUILTIN_PROJECTION_MATRIX},
-	{"TransformProjectionMatrix", Shader::BUILTIN_TRANSFORM_PROJECTION_MATRIX},
-	{"NormalMatrix", Shader::BUILTIN_NORMAL_MATRIX},
-	{"love_PointSize", Shader::BUILTIN_POINT_SIZE},
-	{"love_ScreenSize", Shader::BUILTIN_SCREEN_SIZE},
-	{"love_VideoYChannel", Shader::BUILTIN_VIDEO_Y_CHANNEL},
-	{"love_VideoCbChannel", Shader::BUILTIN_VIDEO_CB_CHANNEL},
-	{"love_VideoCrChannel", Shader::BUILTIN_VIDEO_CR_CHANNEL},
-};
-
-StringMap<Shader::BuiltinUniform, Shader::BUILTIN_MAX_ENUM> Shader::builtinNames(Shader::builtinNameEntries, sizeof(Shader::builtinNameEntries));
-
 } // opengl
 } // graphics
 } // love

+ 13 - 146
src/modules/graphics/opengl/Shader.h

@@ -18,14 +18,11 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
-#ifndef LOVE_GRAPHICS_SHADER_H
-#define LOVE_GRAPHICS_SHADER_H
+#pragma once
 
 // LOVE
-#include "common/Object.h"
-#include "common/StringMap.h"
+#include "graphics/Shader.h"
 #include "graphics/Graphics.h"
-#include "graphics/Texture.h"
 #include "graphics/Volatile.h"
 #include "OpenGL.h"
 
@@ -42,93 +39,10 @@ namespace opengl
 {
 
 // A GLSL shader
-class Shader : public Object, public Volatile
+class Shader final : public love::graphics::Shader, public Volatile
 {
 public:
 
-	static love::Type type;
-
-	enum ShaderStage
-	{
-		STAGE_VERTEX,
-		STAGE_PIXEL,
-		STAGE_MAX_ENUM
-	};
-
-	// Built-in uniform variables.
-	enum BuiltinUniform
-	{
-		BUILTIN_TRANSFORM_MATRIX = 0,
-		BUILTIN_PROJECTION_MATRIX,
-		BUILTIN_TRANSFORM_PROJECTION_MATRIX,
-		BUILTIN_NORMAL_MATRIX,
-		BUILTIN_POINT_SIZE,
-		BUILTIN_SCREEN_SIZE,
-		BUILTIN_VIDEO_Y_CHANNEL,
-		BUILTIN_VIDEO_CB_CHANNEL,
-		BUILTIN_VIDEO_CR_CHANNEL,
-		BUILTIN_MAX_ENUM
-	};
-
-	// Types of potential uniform variables used in love's shaders.
-	enum UniformType
-	{
-		UNIFORM_FLOAT,
-		UNIFORM_MATRIX,
-		UNIFORM_INT,
-		UNIFORM_BOOL,
-		UNIFORM_SAMPLER,
-		UNIFORM_UNKNOWN,
-		UNIFORM_MAX_ENUM
-	};
-
-	struct ShaderSource
-	{
-		std::string vertex;
-		std::string pixel;
-	};
-
-	struct MatrixSize
-	{
-		short columns;
-		short rows;
-	};
-
-	struct UniformInfo
-	{
-		int location;
-		int count;
-
-		union
-		{
-			int components;
-			MatrixSize matrix;
-		};
-
-		UniformType baseType;
-		std::string name;
-
-		union
-		{
-			void *data;
-			float *floats;
-			int *ints;
-		};
-
-		Texture **textures;
-	};
-
-	// Pointer to currently active Shader.
-	static Shader *current;
-
-	// Pointer to the default Shader.
-	static Shader *defaultShader;
-	static Shader *defaultVideoShader;
-
-	// Default shader code (a shader is always required internally.)
-	static ShaderSource defaultCode[Graphics::RENDERER_MAX_ENUM][2];
-	static ShaderSource defaultVideoCode[Graphics::RENDERER_MAX_ENUM][2];
-
 	/**
 	 * Creates a new Shader using a list of source codes.
 	 * Source must contain either vertex or pixel shader code, or both.
@@ -138,45 +52,19 @@ public:
 	virtual ~Shader();
 
 	// Implements Volatile
-	virtual bool loadVolatile();
-	virtual void unloadVolatile();
+	bool loadVolatile() override;
+	void unloadVolatile() override;
 
-	/**
-	 * Binds this Shader's program to be used when rendering.
-	 *
-	 * @param temporary True if we just want to send values to the shader with no intention of rendering.
-	 **/
-	void attach(bool temporary = false);
-
-	/**
-	 * Detach the currently bound Shader.
-	 * Causes the GPU rendering pipeline to use fixed functionality in place of shader programs.
-	 **/
-	static void detach();
-
-	/**
-	 * Returns any warnings this Shader may have generated.
-	 **/
-	std::string getWarnings() const;
-
-	const UniformInfo *getUniformInfo(const std::string &name) const;
-	void updateUniform(const UniformInfo *info, int count, bool internalUpdate = false);
-
-	void sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalUpdate = false);
-
-	/**
-	 * Gets whether a uniform with the specified name exists and is actively
-	 * used in the shader.
-	 **/
-	bool hasUniform(const std::string &name) const;
+	// Implements Shader.
+	void attach(bool temporary = false) override;
+	std::string getWarnings() const override;
+	const UniformInfo *getUniformInfo(const std::string &name) const override;
+	void updateUniform(const UniformInfo *info, int count, bool internalUpdate = false) override;
+	void sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalUpdate = false) override;
+	bool hasUniform(const std::string &name) const override;
 
 	GLint getAttribLocation(const std::string &name);
 
-	/**
-	 * Internal use only.
-	 **/
-	bool hasVertexAttrib(VertexAttribID attrib) const;
-
 	void setVideoTextures(GLuint ytexture, GLuint cbtexture, GLuint crtexture);
 	void checkSetScreenParams();
 	void checkSetPointSize(float size);
@@ -190,12 +78,6 @@ public:
 	static std::string getGLSLVersion();
 	static bool isSupported();
 
-	static bool getConstant(const char *in, UniformType &out);
-	static bool getConstant(UniformType in, const char *&out);
-
-	static bool getConstant(const char *in, VertexAttribID &out);
-	static bool getConstant(VertexAttribID in, const char *&out);
-
 private:
 
 	struct TextureUnit
@@ -255,23 +137,8 @@ private:
 
 	GLuint videoTextureUnits[3];
 
-	static StringMap<ShaderStage, STAGE_MAX_ENUM>::Entry stageNameEntries[];
-	static StringMap<ShaderStage, STAGE_MAX_ENUM> stageNames;
-
-	static StringMap<UniformType, UNIFORM_MAX_ENUM>::Entry uniformTypeEntries[];
-	static StringMap<UniformType, UNIFORM_MAX_ENUM> uniformTypes;
-
-	// Names for the generic vertex attributes used by love.
-	static StringMap<VertexAttribID, ATTRIB_MAX_ENUM>::Entry attribNameEntries[];
-	static StringMap<VertexAttribID, ATTRIB_MAX_ENUM> attribNames;
-
-	// Names for the built-in uniform variables.
-	static StringMap<BuiltinUniform, BUILTIN_MAX_ENUM>::Entry builtinNameEntries[];
-	static StringMap<BuiltinUniform, BUILTIN_MAX_ENUM> builtinNames;
-};
+}; // Shader
 
 } // opengl
 } // graphics
 } // love
-
-#endif // LOVE_GRAPHICS_SHADER_H

+ 2 - 3
src/modules/graphics/opengl/SpriteBatch.cpp

@@ -44,7 +44,7 @@ namespace opengl
 
 love::Type SpriteBatch::type("SpriteBatch", &Drawable::type);
 
-SpriteBatch::SpriteBatch(Texture *texture, int size, Mesh::Usage usage)
+SpriteBatch::SpriteBatch(Texture *texture, int size, vertex::Usage usage)
 	: texture(texture)
 	, size(size)
 	, next(0)
@@ -57,10 +57,9 @@ SpriteBatch::SpriteBatch(Texture *texture, int size, Mesh::Usage usage)
 	if (size <= 0)
 		throw love::Exception("Invalid SpriteBatch size.");
 
-	GLenum gl_usage = Mesh::getGLBufferUsage(usage);
 	size_t vertex_size = sizeof(Vertex) * 4 * size;
 
-	array_buf = new GLBuffer(vertex_size, nullptr, BUFFER_VERTEX, gl_usage, GLBuffer::MAP_EXPLICIT_RANGE_MODIFY);
+	array_buf = new GLBuffer(vertex_size, nullptr, BUFFER_VERTEX, usage, GLBuffer::MAP_EXPLICIT_RANGE_MODIFY);
 }
 
 SpriteBatch::~SpriteBatch()

+ 1 - 1
src/modules/graphics/opengl/SpriteBatch.h

@@ -54,7 +54,7 @@ public:
 
 	static love::Type type;
 
-	SpriteBatch(Texture *texture, int size, Mesh::Usage usage);
+	SpriteBatch(Texture *texture, int size, vertex::Usage usage);
 	virtual ~SpriteBatch();
 
 	int add(const Matrix4 &m, int index = -1);

+ 1 - 1
src/modules/graphics/opengl/Text.cpp

@@ -62,7 +62,7 @@ void Text::uploadVertices(const std::vector<Font::GlyphVertex> &vertices, size_t
 		if (vbo != nullptr)
 			newsize = std::max(size_t(vbo->getSize() * 1.5), newsize);
 
-		GLBuffer *new_vbo = new GLBuffer(newsize, nullptr, BUFFER_VERTEX, GL_DYNAMIC_DRAW);
+		GLBuffer *new_vbo = new GLBuffer(newsize, nullptr, BUFFER_VERTEX, vertex::USAGE_DYNAMIC);
 
 		if (vbo != nullptr)
 		{

+ 3 - 3
src/modules/graphics/opengl/Video.cpp

@@ -37,7 +37,7 @@ Video::Video(love::video::VideoStream *stream, float pixeldensity)
 	: stream(stream)
 	, width(stream->getWidth() / pixeldensity)
 	, height(stream->getHeight() / pixeldensity)
-	, filter(Texture::getDefaultFilter())
+	, filter(Texture::defaultFilter)
 {
 	filter.mipmap = Texture::FILTER_NONE;
 
@@ -124,13 +124,13 @@ void Video::draw(Graphics *gfx, const Matrix4 &m)
 
 	gfx->flushStreamDraws();
 
-	Shader *shader = Shader::current;
+	Shader *shader = (Shader *) Shader::current;
 	bool defaultShader = (shader == Shader::defaultShader);
 	if (defaultShader)
 	{
 		// If we're still using the default shader, substitute the video version
 		Shader::defaultVideoShader->attach();
-		shader = Shader::defaultVideoShader;
+		shader = (Shader *) Shader::defaultVideoShader;
 	}
 
 	shader->setVideoTextures(textures[0], textures[1], textures[2]);

+ 18 - 18
src/modules/graphics/opengl/wrap_Graphics.cpp

@@ -153,7 +153,7 @@ int w_isActive(lua_State *L)
 
 int w_isGammaCorrect(lua_State *L)
 {
-	luax_pushboolean(L, instance()->isGammaCorrect());
+	luax_pushboolean(L, graphics::isGammaCorrect());
 	return 1;
 }
 
@@ -214,7 +214,7 @@ int w_setCanvas(lua_State *L)
 	}
 
 	bool is_table = lua_istable(L, 1);
-	std::vector<Canvas *> canvases;
+	std::vector<love::graphics::Canvas *> canvases;
 
 	if (is_table)
 	{
@@ -243,10 +243,10 @@ int w_setCanvas(lua_State *L)
 
 int w_getCanvas(lua_State *L)
 {
-	const std::vector<Canvas *> canvases = instance()->getCanvas();
+	const std::vector<love::graphics::Canvas *> canvases = instance()->getCanvas();
 	int n = 0;
 
-	for (Canvas *c : canvases)
+	for (love::graphics::Canvas *c : canvases)
 	{
 		luax_pushtype(L, c);
 		n++;
@@ -644,12 +644,12 @@ int w_newSpriteBatch(lua_State *L)
 
 	Texture *texture = luax_checktexture(L, 1);
 	int size = (int) luaL_optnumber(L, 2, 1000);
-	Mesh::Usage usage = Mesh::USAGE_DYNAMIC;
+	vertex::Usage usage = vertex::USAGE_DYNAMIC;
 	if (lua_gettop(L) > 2)
 	{
 		const char *usagestr = luaL_checkstring(L, 3);
-		if (!Mesh::getConstant(usagestr, usage))
-			return luaL_error(L, "Invalid SpriteBatch usage hint: %s", usagestr);
+		if (!vertex::getConstant(usagestr, usage))
+			return luaL_error(L, "Invalid usage hint: %s", usagestr);
 	}
 
 	SpriteBatch *t = nullptr;
@@ -709,7 +709,7 @@ int w_newCanvas(lua_State *L)
 		settings.msaa = luax_intflag(L, 3, "msaa", settings.msaa);
 	}
 
-	Canvas *canvas = nullptr;
+	love::graphics::Canvas *canvas = nullptr;
 	luax_catchexcept(L, [&](){ canvas = instance()->newCanvas(width, height, settings); });
 
 	if (canvas == nullptr)
@@ -807,7 +807,7 @@ int w_newShader(lua_State *L)
 	bool should_error = false;
 	try
 	{
-		Shader *shader = instance()->newShader(source);
+		love::graphics::Shader *shader = instance()->newShader(source);
 		luax_pushtype(L, shader);
 		shader->release();
 	}
@@ -827,12 +827,12 @@ int w_newShader(lua_State *L)
 	return 1;
 }
 
-static Mesh::Usage luax_optmeshusage(lua_State *L, int idx, Mesh::Usage def)
+static vertex::Usage luax_optmeshusage(lua_State *L, int idx, vertex::Usage def)
 {
 	const char *usagestr = lua_isnoneornil(L, idx) ? nullptr : luaL_checkstring(L, idx);
 
-	if (usagestr && !Mesh::getConstant(usagestr, def))
-		luaL_error(L, "Invalid mesh usage hint: %s", usagestr);
+	if (usagestr && !vertex::getConstant(usagestr, def))
+		luaL_error(L, "Invalid usage hint: %s", usagestr);
 
 	return def;
 }
@@ -852,7 +852,7 @@ static Mesh *newStandardMesh(lua_State *L)
 	Mesh *t = nullptr;
 
 	Mesh::DrawMode drawmode = luax_optmeshdrawmode(L, 2, Mesh::DRAWMODE_FAN);
-	Mesh::Usage usage = luax_optmeshusage(L, 3, Mesh::USAGE_DYNAMIC);
+	vertex::Usage usage = luax_optmeshusage(L, 3, vertex::USAGE_DYNAMIC);
 
 	// First argument is a table of standard vertices, or the number of
 	// standard vertices.
@@ -912,7 +912,7 @@ static Mesh *newCustomMesh(lua_State *L)
 	std::vector<Mesh::AttribFormat> vertexformat;
 
 	Mesh::DrawMode drawmode = luax_optmeshdrawmode(L, 3, Mesh::DRAWMODE_FAN);
-	Mesh::Usage usage = luax_optmeshusage(L, 4, Mesh::USAGE_DYNAMIC);
+	vertex::Usage usage = luax_optmeshusage(L, 4, vertex::USAGE_DYNAMIC);
 
 	lua_rawgeti(L, 1, 1);
 	if (!lua_istable(L, -1))
@@ -1410,14 +1410,14 @@ int w_setShader(lua_State *L)
 		return 0;
 	}
 
-	Shader *shader = luax_checkshader(L, 1);
+	love::graphics::Shader *shader = luax_checkshader(L, 1);
 	instance()->setShader(shader);
 	return 0;
 }
 
 int w_getShader(lua_State *L)
 {
-	Shader *shader = instance()->getShader();
+	love::graphics::Shader *shader = instance()->getShader();
 	if (shader)
 		luax_pushtype(L, shader);
 	else
@@ -1453,8 +1453,8 @@ int w_setDefaultShaderCode(lua_State *L)
 
 			lua_pop(L, 4);
 
-			Shader::defaultCode[renderer][i] = code;
-			Shader::defaultVideoCode[renderer][i] = videocode;
+			Graphics::defaultShaderCode[renderer][i] = code;
+			Graphics::defaultVideoShaderCode[renderer][i] = videocode;
 		}
 	}
 

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

@@ -28,8 +28,8 @@
 #include "graphics/wrap_Quad.h"
 #include "wrap_SpriteBatch.h"
 #include "wrap_ParticleSystem.h"
-#include "wrap_Canvas.h"
-#include "wrap_Shader.h"
+#include "graphics/wrap_Canvas.h"
+#include "graphics/wrap_Shader.h"
 #include "wrap_Mesh.h"
 #include "wrap_Text.h"
 #include "wrap_Video.h"

+ 20 - 0
src/modules/graphics/vertex.cpp

@@ -19,6 +19,7 @@
  **/
 
 #include "vertex.h"
+#include "common/StringMap.h"
 
 namespace love
 {
@@ -129,6 +130,25 @@ void fillIndices(TriangleIndexMode mode, uint32 vertexStart, uint32 vertexCount,
 	fillIndicesT(mode, vertexStart, vertexCount, indices);
 }
 
+static StringMap<Usage, USAGE_MAX_ENUM>::Entry usageEntries[] =
+{
+	{ "stream",  USAGE_STREAM  },
+	{ "dynamic", USAGE_DYNAMIC },
+	{ "static",  USAGE_STATIC  },
+};
+
+static StringMap<Usage, USAGE_MAX_ENUM> usages(usageEntries, sizeof(usageEntries));
+
+bool getConstant(const char *in, Usage &out)
+{
+	return usages.find(in, out);
+}
+
+bool getConstant(Usage in, const char *&out)
+{
+	return usages.find(in, out);
+}
+
 } // vertex
 } // graphics
 } // love

+ 31 - 0
src/modules/graphics/vertex.h

@@ -32,6 +32,25 @@ namespace love
 namespace graphics
 {
 
+// Vertex attribute indices used in shaders by LOVE. The values map to OpenGL
+// generic vertex attribute indices.
+enum VertexAttribID
+{
+	ATTRIB_POS = 0,
+	ATTRIB_TEXCOORD,
+	ATTRIB_COLOR,
+	ATTRIB_CONSTANTCOLOR,
+	ATTRIB_MAX_ENUM
+};
+
+enum VertexAttribFlags
+{
+	ATTRIBFLAG_POS = 1 << ATTRIB_POS,
+	ATTRIBFLAG_TEXCOORD = 1 << ATTRIB_TEXCOORD,
+	ATTRIBFLAG_COLOR = 1 << ATTRIB_COLOR,
+	ATTRIBFLAG_CONSTANTCOLOR = 1 << ATTRIB_CONSTANTCOLOR
+};
+
 enum BufferType
 {
 	BUFFER_VERTEX = 0,
@@ -42,6 +61,15 @@ enum BufferType
 namespace vertex
 {
 
+// The expected usage pattern of vertex data.
+enum Usage
+{
+	USAGE_STREAM,
+	USAGE_DYNAMIC,
+	USAGE_STATIC,
+	USAGE_MAX_ENUM
+};
+
 enum class PrimitiveMode
 {
 	TRIANGLES,
@@ -93,6 +121,9 @@ int getIndexCount(TriangleIndexMode mode, int vertexCount);
 void fillIndices(TriangleIndexMode mode, uint16 vertexStart, uint16 vertexCount, uint16 *indices);
 void fillIndices(TriangleIndexMode mode, uint32 vertexStart, uint32 vertexCount, uint32 *indices);
 
+bool getConstant(const char *in, Usage &out);
+bool getConstant(Usage in, const char *&out);
+
 } // vertex
 
 typedef vertex::XYf_STf_RGBAub Vertex;

+ 0 - 3
src/modules/graphics/opengl/wrap_Canvas.cpp → src/modules/graphics/wrap_Canvas.cpp

@@ -25,8 +25,6 @@ namespace love
 {
 namespace graphics
 {
-namespace opengl
-{
 
 Canvas *luax_checkcanvas(lua_State *L, int idx)
 {
@@ -115,6 +113,5 @@ extern "C" int luaopen_canvas(lua_State *L)
 	return luax_register_type(L, &Canvas::type, w_Texture_functions, w_Canvas_functions, nullptr);
 }
 
-} // opengl
 } // graphics
 } // love

+ 2 - 8
src/modules/graphics/opengl/wrap_Canvas.h → src/modules/graphics/wrap_Canvas.h

@@ -18,27 +18,21 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
-#ifndef LOVE_GRAPHICS_OPENGL_WRAP_CANVAS_H
-#define LOVE_GRAPHICS_OPENGL_WRAP_CANVAS_H
+#pragma once
 
 // LOVE
 #include "common/runtime.h"
 #include "Canvas.h"
-#include "graphics/wrap_Texture.h"
+#include "wrap_Texture.h"
 
 namespace love
 {
 namespace graphics
 {
-namespace opengl
-{
 
 //see Canvas.h
 Canvas *luax_checkcanvas(lua_State *L, int idx);
 extern "C" int luaopen_canvas(lua_State *L);
 
-} // opengl
 } // graphics
 } // love
-
-#endif // LOVE_GRAPHICS_OPENGL_WRAP_CANVAS_H

+ 2 - 4
src/modules/graphics/opengl/wrap_Shader.cpp → src/modules/graphics/wrap_Shader.cpp

@@ -19,9 +19,10 @@
  **/
 
 #include "wrap_Shader.h"
-#include "graphics/wrap_Texture.h"
+#include "wrap_Texture.h"
 #include "math/MathModule.h"
 #include "math/Transform.h"
+#include "Graphics.h"
 
 #include <string>
 #include <algorithm>
@@ -31,8 +32,6 @@ namespace love
 {
 namespace graphics
 {
-namespace opengl
-{
 
 Shader *luax_checkshader(lua_State *L, int idx)
 {
@@ -331,7 +330,6 @@ extern "C" int luaopen_shader(lua_State *L)
 	return luax_register_type(L, &Shader::type, w_Shader_functions, nullptr);
 }
 
-} // opengl
 } // graphics
 } // love
 

+ 1 - 7
src/modules/graphics/opengl/wrap_Shader.h → src/modules/graphics/wrap_Shader.h

@@ -18,8 +18,7 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
-#ifndef LOVE_GRAPHICS_OPENGL_WRAP_PROGRAM_H
-#define LOVE_GRAPHICS_OPENGL_WRAP_PROGRAM_H
+#pragma once
 
 #include "common/runtime.h"
 #include "common/config.h"
@@ -29,14 +28,9 @@ namespace love
 {
 namespace graphics
 {
-namespace opengl
-{
 
 Shader *luax_checkshader(lua_State *L, int idx);
 extern "C" int luaopen_shader(lua_State *L);
 
-} // opengl
 } // graphics
 } // love
-
-#endif